33 |
33 |
34 /* Calculate the MD5 Sum for a GRF */ |
34 /* Calculate the MD5 Sum for a GRF */ |
35 static bool CalcGRFMD5Sum(GRFConfig *config) |
35 static bool CalcGRFMD5Sum(GRFConfig *config) |
36 { |
36 { |
37 FILE *f; |
37 FILE *f; |
38 char filename[MAX_PATH]; |
|
39 md5_state_t md5state; |
38 md5_state_t md5state; |
40 md5_byte_t buffer[1024]; |
39 md5_byte_t buffer[1024]; |
41 size_t len; |
40 size_t len; |
42 |
41 |
43 /* open the file */ |
42 /* open the file */ |
44 snprintf(filename, lengthof(filename), "%s%s", _paths.data_dir, config->filename); |
43 f = fopen(config->full_path, "rb"); |
45 f = fopen(filename, "rb"); |
|
46 if (f == NULL) return false; |
44 if (f == NULL) return false; |
47 |
45 |
48 /* calculate md5sum */ |
46 /* calculate md5sum */ |
49 md5_init(&md5state); |
47 md5_init(&md5state); |
50 while ((len = fread(buffer, 1, sizeof(buffer), f)) != 0) { |
48 while ((len = fread(buffer, 1, sizeof(buffer), f)) != 0) { |
59 |
57 |
60 |
58 |
61 /* Find the GRFID and calculate the md5sum */ |
59 /* Find the GRFID and calculate the md5sum */ |
62 bool FillGRFDetails(GRFConfig *config, bool is_static) |
60 bool FillGRFDetails(GRFConfig *config, bool is_static) |
63 { |
61 { |
64 if (!FioCheckFileExists(config->filename)) { |
62 if (!FileExists(config->full_path)) { |
65 config->status = GCS_NOT_FOUND; |
63 config->status = GCS_NOT_FOUND; |
66 return false; |
64 return false; |
|
65 } |
|
66 |
|
67 if (config->filename == NULL) { |
|
68 config->filename = strdup(strrchr(config->full_path, PATHSEPCHAR) + 1); |
67 } |
69 } |
68 |
70 |
69 /* Find and load the Action 8 information */ |
71 /* Find and load the Action 8 information */ |
70 /* 62 is the last file slot before sample.cat. |
72 /* 62 is the last file slot before sample.cat. |
71 * Should perhaps be some "don't care" value */ |
73 * Should perhaps be some "don't care" value */ |
89 void ClearGRFConfig(GRFConfig **config) |
91 void ClearGRFConfig(GRFConfig **config) |
90 { |
92 { |
91 /* GCF_COPY as in NOT strdupped/alloced the filename, name and info */ |
93 /* GCF_COPY as in NOT strdupped/alloced the filename, name and info */ |
92 if (!HASBIT((*config)->flags, GCF_COPY)) { |
94 if (!HASBIT((*config)->flags, GCF_COPY)) { |
93 free((*config)->filename); |
95 free((*config)->filename); |
|
96 free((*config)->full_path); |
94 free((*config)->name); |
97 free((*config)->name); |
95 free((*config)->info); |
98 free((*config)->info); |
96 free((*config)->error); |
99 free((*config)->error); |
97 } |
100 } |
98 free(*config); |
101 free(*config); |
121 /* Clear destination as it will be overwritten */ |
124 /* Clear destination as it will be overwritten */ |
122 ClearGRFConfigList(dst); |
125 ClearGRFConfigList(dst); |
123 for (; src != NULL; src = src->next) { |
126 for (; src != NULL; src = src->next) { |
124 GRFConfig *c = CallocT<GRFConfig>(1); |
127 GRFConfig *c = CallocT<GRFConfig>(1); |
125 *c = *src; |
128 *c = *src; |
126 if (src->filename != NULL) c->filename = strdup(src->filename); |
129 if (src->filename != NULL) c->filename = strdup(src->filename); |
127 if (src->name != NULL) c->name = strdup(src->name); |
130 if (src->full_path != NULL) c->full_path = strdup(src->full_path); |
128 if (src->info != NULL) c->info = strdup(src->info); |
131 if (src->name != NULL) c->name = strdup(src->name); |
129 if (src->error != NULL) { |
132 if (src->info != NULL) c->info = strdup(src->info); |
|
133 if (src->error != NULL) { |
130 c->error = CallocT<GRFError>(1); |
134 c->error = CallocT<GRFError>(1); |
131 memcpy(c->error, src->error, sizeof(GRFError)); |
135 memcpy(c->error, src->error, sizeof(GRFError)); |
132 } |
136 } |
133 |
137 |
134 *dst = c; |
138 *dst = c; |
253 * in any case and set the name and info when it is not set already. |
257 * in any case and set the name and info when it is not set already. |
254 * When the GCF_COPY flag is set, it is certain that the filename is |
258 * When the GCF_COPY flag is set, it is certain that the filename is |
255 * already a local one, so there is no need to replace it. */ |
259 * already a local one, so there is no need to replace it. */ |
256 if (!HASBIT(c->flags, GCF_COPY)) { |
260 if (!HASBIT(c->flags, GCF_COPY)) { |
257 free(c->filename); |
261 free(c->filename); |
|
262 free(c->full_path); |
258 c->filename = strdup(f->filename); |
263 c->filename = strdup(f->filename); |
|
264 c->full_path = strdup(f->full_path); |
259 memcpy(c->md5sum, f->md5sum, sizeof(c->md5sum)); |
265 memcpy(c->md5sum, f->md5sum, sizeof(c->md5sum)); |
260 if (c->name == NULL && f->name != NULL) c->name = strdup(f->name); |
266 if (c->name == NULL && f->name != NULL) c->name = strdup(f->name); |
261 if (c->info == NULL && f->info != NULL) c->info = strdup(f->info); |
267 if (c->info == NULL && f->info != NULL) c->info = strdup(f->info); |
262 c->error = NULL; |
268 c->error = NULL; |
263 } |
269 } |
276 uint num = 0; |
282 uint num = 0; |
277 struct stat sb; |
283 struct stat sb; |
278 struct dirent *dirent; |
284 struct dirent *dirent; |
279 DIR *dir; |
285 DIR *dir; |
280 |
286 |
281 if ((dir = ttd_opendir(path)) == NULL) return 0; |
287 if (path == NULL || (dir = ttd_opendir(path)) == NULL) return 0; |
282 |
288 |
283 while ((dirent = readdir(dir)) != NULL) { |
289 while ((dirent = readdir(dir)) != NULL) { |
284 const char *d_name = FS2OTTD(dirent->d_name); |
290 const char *d_name = FS2OTTD(dirent->d_name); |
285 char filename[MAX_PATH]; |
291 char filename[MAX_PATH]; |
286 |
292 |
287 if (!FiosIsValidFile(path, dirent, &sb)) continue; |
293 if (!FiosIsValidFile(path, dirent, &sb)) continue; |
288 |
294 |
289 snprintf(filename, lengthof(filename), "%s" PATHSEP "%s", path, d_name); |
295 snprintf(filename, lengthof(filename), "%s%s", path, d_name); |
290 |
296 |
291 if (sb.st_mode & S_IFDIR) { |
297 if (sb.st_mode & S_IFDIR) { |
292 /* Directory */ |
298 /* Directory */ |
293 if (strcmp(d_name, ".") == 0 || strcmp(d_name, "..") == 0) continue; |
299 if (strcmp(d_name, ".") == 0 || strcmp(d_name, "..") == 0) continue; |
|
300 AppendPathSeparator(filename, lengthof(filename)); |
294 num += ScanPath(filename); |
301 num += ScanPath(filename); |
295 } else if (sb.st_mode & S_IFREG) { |
302 } else if (sb.st_mode & S_IFREG) { |
296 /* File */ |
303 /* File */ |
297 char *ext = strrchr(filename, '.'); |
304 char *ext = strrchr(filename, '.'); |
298 char *file = filename + strlen(_paths.data_dir) + 1; // Crop base path |
|
299 |
305 |
300 /* If no extension or extension isn't .grf, skip the file */ |
306 /* If no extension or extension isn't .grf, skip the file */ |
301 if (ext == NULL) continue; |
307 if (ext == NULL) continue; |
302 if (strcasecmp(ext, ".grf") != 0) continue; |
308 if (strcasecmp(ext, ".grf") != 0) continue; |
303 |
309 |
304 GRFConfig *c = CallocT<GRFConfig>(1); |
310 GRFConfig *c = CallocT<GRFConfig>(1); |
305 c->filename = strdup(file); |
311 c->full_path = strdup(filename); |
306 |
312 |
|
313 bool added = true; |
307 if (FillGRFDetails(c, false)) { |
314 if (FillGRFDetails(c, false)) { |
308 if (_all_grfs == NULL) { |
315 if (_all_grfs == NULL) { |
309 _all_grfs = c; |
316 _all_grfs = c; |
310 } else { |
317 } else { |
311 /* Insert file into list at a position determined by its |
318 /* Insert file into list at a position determined by its |
312 * name, so the list is sorted as we go along */ |
319 * name, so the list is sorted as we go along */ |
313 GRFConfig **pd, *d; |
320 GRFConfig **pd, *d; |
314 for (pd = &_all_grfs; (d = *pd) != NULL; pd = &d->next) { |
321 for (pd = &_all_grfs; (d = *pd) != NULL; pd = &d->next) { |
|
322 if (c->grfid == d->grfid && memcmp(c->md5sum, d->md5sum, sizeof(c->md5sum)) == 0) added = false; |
315 if (strcasecmp(c->name, d->name) <= 0) break; |
323 if (strcasecmp(c->name, d->name) <= 0) break; |
316 } |
324 } |
317 c->next = d; |
325 if (added) { |
318 *pd = c; |
326 c->next = d; |
|
327 *pd = c; |
|
328 } |
319 } |
329 } |
320 |
|
321 num++; |
|
322 } else { |
330 } else { |
|
331 added = false; |
|
332 } |
|
333 |
|
334 if (!added) { |
323 /* File couldn't be opened, or is either not a NewGRF or is a |
335 /* File couldn't be opened, or is either not a NewGRF or is a |
324 * 'system' NewGRF, so forget about it. */ |
336 * 'system' NewGRF or it's already known, so forget about it. */ |
325 free(c->filename); |
337 free(c->filename); |
|
338 free(c->full_path); |
326 free(c->name); |
339 free(c->name); |
327 free(c->info); |
340 free(c->info); |
328 free(c); |
341 free(c); |
|
342 } else { |
|
343 num++; |
329 } |
344 } |
330 } |
345 } |
331 } |
346 } |
332 |
347 |
333 closedir(dir); |
348 closedir(dir); |
342 uint num; |
357 uint num; |
343 |
358 |
344 ClearGRFConfigList(&_all_grfs); |
359 ClearGRFConfigList(&_all_grfs); |
345 |
360 |
346 DEBUG(grf, 1, "Scanning for NewGRFs"); |
361 DEBUG(grf, 1, "Scanning for NewGRFs"); |
347 num = ScanPath(_paths.data_dir); |
362 num = ScanPath(_paths.data_dir); |
|
363 num += ScanPath(_paths.second_data_dir); |
348 DEBUG(grf, 1, "Scan complete, found %d files", num); |
364 DEBUG(grf, 1, "Scan complete, found %d files", num); |
349 } |
365 } |
350 |
366 |
351 |
367 |
352 /* Find a NewGRF in the scanned list, if md5sum is NULL, we don't care about it*/ |
368 /* Find a NewGRF in the scanned list, if md5sum is NULL, we don't care about it*/ |