0
|
1 /*
|
|
2 * dmlib
|
|
3 * -- Resource management
|
|
4 * Programmed and designed by Matti 'ccr' Hamalainen
|
|
5 * (C) Copyright 2003-2012 Tecnic Software productions (TNSP)
|
|
6 */
|
|
7 #include "dmres.h"
|
|
8 #include <time.h>
|
|
9
|
|
10 #if !defined(DMRES_PACKFS) && !defined(DMRES_STDIO)
|
|
11 #error At least one of DMRES_PACKFS, DMRES_STDIO must be defined.
|
|
12 #endif
|
|
13
|
|
14 #define DMRES_LOCK(x) dmMutexLock(dfResourcesMutex)
|
|
15 #define DMRES_UNLOCK(x) dmMutexUnlock(dfResourcesMutex)
|
|
16
|
|
17
|
|
18 /* Global variables
|
|
19 */
|
|
20 static BOOL dfResInitialized = FALSE;
|
|
21 static int dfResFlags = 0;
|
|
22 static char * dfResPath = NULL;
|
|
23 DMResource * dfResources = NULL;
|
|
24 DMMutex * dfResourcesMutex = NULL;
|
|
25
|
|
26
|
|
27 #ifdef DMRES_PACKFS
|
|
28 static DMPackFile *dfResPackFile = NULL;
|
|
29 static char * dfResPackFilename = NULL;
|
|
30 #endif
|
|
31
|
|
32
|
|
33 DMResource *dmres_new(const char *filename, int flags, size_t size)
|
|
34 {
|
|
35 DMResource *res = dmMalloc0(sizeof(DMResource));
|
|
36 if (res == NULL)
|
|
37 return NULL;
|
|
38
|
|
39 res->filename = dm_strdup(filename);
|
|
40 res->flags = flags;
|
|
41 res->dataSize = size;
|
|
42
|
|
43 return res;
|
|
44 }
|
|
45
|
|
46
|
|
47 void dmres_free(DMResource *res)
|
|
48 {
|
|
49 if (res != NULL)
|
|
50 {
|
|
51 dmFree(res->filename);
|
|
52 dmFree(res->data);
|
|
53 dmFree(res);
|
|
54 }
|
|
55 }
|
|
56
|
|
57
|
|
58 void dmres_insert(DMResource * node)
|
|
59 {
|
|
60 if (dfResources != NULL)
|
|
61 {
|
|
62 node->prev = dfResources->prev;
|
|
63 dfResources->prev->next = node;
|
|
64 dfResources->prev = node;
|
|
65 }
|
|
66 else
|
|
67 {
|
|
68 dfResources = node->prev = node;
|
|
69 }
|
|
70
|
|
71 node->next = NULL;
|
|
72 }
|
|
73
|
|
74
|
|
75 void dmres_delete(DMResource * node)
|
|
76 {
|
|
77 if (node->prev)
|
|
78 node->prev->next = node->next;
|
|
79
|
|
80 if (node->next)
|
|
81 node->next->prev = node->prev;
|
|
82 else
|
|
83 dfResources->prev = node->prev;
|
|
84
|
|
85 node->prev = node->next = NULL;
|
|
86 }
|
|
87
|
|
88
|
|
89 DMResource * dmres_find(const char *filename)
|
|
90 {
|
|
91 DMResource *node, *found = NULL;
|
|
92
|
|
93 DMRES_LOCK();
|
|
94
|
|
95 for (node = dfResources; node != NULL; node = node->next)
|
|
96 {
|
|
97 if (strcmp(node->filename, filename) == 0)
|
|
98 {
|
|
99 found = node;
|
|
100 break;
|
|
101 }
|
|
102 }
|
|
103
|
|
104 DMRES_UNLOCK();
|
|
105
|
|
106 return found;
|
|
107 }
|
|
108
|
|
109
|
|
110 #ifdef DMRES_STDIO
|
|
111 /* Basic stdio file routines
|
|
112 */
|
|
113 static int dm_stdio_fopen(DMResource *handle)
|
|
114 {
|
|
115 char *rfilename = dm_strdup_printf("%s%s", DMRES_DATA_PATH, handle->filename);
|
|
116 if (rfilename == NULL)
|
|
117 return DMERR_MALLOC;
|
|
118
|
|
119 handle->fh = fopen(rfilename, "rb");
|
|
120 dmFree(rfilename);
|
|
121
|
|
122 handle->error = dmGetErrno();
|
|
123 return (handle->fh != NULL) ? DMERR_OK : DMERR_FOPEN;
|
|
124 }
|
|
125
|
|
126
|
|
127 static void dm_stdio_fclose(DMResource * f)
|
|
128 {
|
|
129 if (f->fh != NULL)
|
|
130 {
|
|
131 fclose(f->fh);
|
|
132 f->fh = NULL;
|
|
133 }
|
|
134 }
|
|
135
|
|
136
|
|
137 static int dm_stdio_ferror(DMResource * f)
|
|
138 {
|
|
139 return f->error;
|
|
140 }
|
|
141
|
|
142
|
|
143 static int dm_stdio_fseek(DMResource *f, const off_t pos, const int whence)
|
|
144 {
|
|
145 int ret = fseek(f->fh, pos, whence);
|
|
146 f->error = dmGetErrno();
|
|
147 return ret;
|
|
148 }
|
|
149
|
|
150
|
|
151 static off_t dm_stdio_fsize(DMResource *f)
|
|
152 {
|
|
153 off_t savePos, fileSize;
|
|
154
|
|
155 // Check if the size is cached
|
|
156 if (f->dataSize != 0)
|
|
157 return f->dataSize;
|
|
158
|
|
159 // Get file size
|
|
160 savePos = ftell(f->fh);
|
|
161 if (fseek(f->fh, 0L, SEEK_END) != 0)
|
|
162 {
|
|
163 f->error = dmGetErrno();
|
|
164 return -1;
|
|
165 }
|
|
166
|
|
167 fileSize = ftell(f->fh);
|
|
168 if (fseek(f->fh, savePos, SEEK_SET) != 0)
|
|
169 {
|
|
170 f->error = dmGetErrno();
|
|
171 return -1;
|
|
172 }
|
|
173
|
|
174 f->dataSize = fileSize;
|
|
175 return fileSize;
|
|
176 }
|
|
177
|
|
178
|
|
179 static off_t dm_stdio_ftell(DMResource * f)
|
|
180 {
|
|
181 return ftell(f->fh);
|
|
182 }
|
|
183
|
|
184
|
|
185 static BOOL dm_stdio_feof(DMResource * f)
|
|
186 {
|
|
187 return feof(f->fh);
|
|
188 }
|
|
189
|
|
190
|
|
191 static int dm_stdio_fgetc(DMResource * f)
|
|
192 {
|
|
193 int ret = fgetc(f->fh);
|
|
194 f->error = dmGetErrno();
|
|
195 return ret;
|
|
196 }
|
|
197
|
|
198
|
|
199 static size_t dm_stdio_fread(void *ptr, size_t size, size_t nmemb, DMResource * f)
|
|
200 {
|
|
201 size_t ret = fread(ptr, size, nmemb, f->fh);
|
|
202 f->error = dmGetErrno();
|
|
203 return ret;
|
|
204 }
|
|
205
|
|
206
|
|
207 static int dm_stdio_preload(DMResource *handle)
|
|
208 {
|
|
209 int ret = dm_stdio_fopen(handle);
|
|
210 if (ret != DMERR_OK)
|
|
211 return ret;
|
|
212
|
|
213 dm_stdio_fsize(handle);
|
|
214
|
|
215 handle->data = dmMalloc(handle->dataSize);
|
|
216 if (handle->data == NULL)
|
|
217 return DMERR_MALLOC;
|
|
218
|
|
219 if (dm_stdio_fread(handle->data, sizeof(Uint8), handle->dataSize, handle) != handle->dataSize)
|
|
220 return DMERR_FREAD;
|
|
221
|
|
222 return DMERR_OK;
|
|
223 }
|
|
224
|
|
225
|
|
226 DMResourceOps dfStdioFileOps =
|
|
227 {
|
|
228 dm_stdio_ferror,
|
|
229 dm_stdio_fseek,
|
|
230 dm_stdio_fsize,
|
|
231 dm_stdio_ftell,
|
|
232 dm_stdio_feof,
|
|
233 dm_stdio_fgetc,
|
|
234 dm_stdio_fread,
|
|
235
|
|
236 dm_stdio_fopen,
|
|
237 dm_stdio_fclose,
|
|
238 dm_stdio_preload
|
|
239 };
|
|
240
|
|
241 DMResourceOps dfStdioFHOps =
|
|
242 {
|
|
243 dm_stdio_ferror,
|
|
244 dm_stdio_fseek,
|
|
245 dm_stdio_fsize,
|
|
246 dm_stdio_ftell,
|
|
247 dm_stdio_feof,
|
|
248 dm_stdio_fgetc,
|
|
249 dm_stdio_fread,
|
|
250
|
|
251 NULL,
|
|
252 NULL,
|
|
253 NULL
|
|
254 };
|
|
255 #endif
|
|
256
|
|
257
|
|
258 // Some mingw/windows headers define these as macros, which is bad for us
|
|
259 #ifdef __WIN32
|
|
260 #undef ferror
|
|
261 #undef feof
|
|
262 #endif
|
|
263
|
|
264
|
|
265 /*
|
|
266 * PACK file routines
|
|
267 */
|
|
268 #ifdef DMRES_PACKFS
|
|
269 static int dm_pack_preload(DMResource *handle)
|
|
270 {
|
|
271 DMPackEntry *node;
|
|
272 int res = DMERR_OK, cres, cdataLeft;
|
|
273 z_stream cstream;
|
|
274 Uint8 * cbuffer = NULL;
|
|
275
|
|
276 // Search PACK nodelist for file
|
|
277 if ((node = dm_pack_find(dfResPackFile->entries, handle->filename)) == NULL)
|
|
278 {
|
|
279 dmError("Entry '%s' not found in PACK file.\n", handle->filename);
|
|
280 res = DMERR_NOT_FOUND;
|
|
281 goto error;
|
|
282 }
|
|
283
|
|
284 // Seek to entry
|
|
285 if (fseek(dfResPackFile->file, node->offset, SEEK_SET) == -1)
|
|
286 {
|
|
287 dmError("Could not seek node position in PACK file.\n");
|
|
288 res = DMERR_FSEEK;
|
|
289 goto error;
|
|
290 }
|
|
291
|
|
292 // Allocate a structures and buffers
|
|
293 cbuffer = (Uint8 *) dmMalloc(DPACK_TMPSIZE);
|
|
294 if (cbuffer == NULL)
|
|
295 {
|
|
296 res = DMERR_MALLOC;
|
|
297 goto error;
|
|
298 }
|
|
299
|
|
300 // Initialize fields
|
|
301 handle->dataOffset = 0;
|
|
302 handle->dataSize = node->size;
|
|
303 handle->data = (Uint8 *) dmMalloc(node->size);
|
|
304 if (handle->data == NULL)
|
|
305 {
|
|
306 res = DMERR_MALLOC;
|
|
307 goto error;
|
|
308 }
|
|
309
|
|
310 // Initialize decompression
|
|
311 cstream.zalloc = (alloc_func) Z_NULL;
|
|
312 cstream.zfree = (free_func) Z_NULL;
|
|
313 cstream.opaque = (voidpf) Z_NULL;
|
|
314 cstream.next_out = handle->data;
|
|
315 cstream.avail_out = handle->dataSize;
|
|
316 cdataLeft = node->length;
|
|
317 cres = inflateInit(&(cstream));
|
|
318 if (cres != Z_OK)
|
|
319 {
|
|
320 dmError("Could not initialize zlib stream inflation.\n");
|
|
321 res = DMERR_INIT_FAIL;
|
|
322 goto error;
|
|
323 }
|
|
324
|
|
325 // Uncompress the data
|
|
326 while (cdataLeft > 0 &&
|
|
327 cstream.avail_out > 0 && cres == Z_OK)
|
|
328 {
|
|
329 cstream.avail_in = fread(
|
|
330 cbuffer, sizeof(Uint8),
|
|
331 (cdataLeft >= DPACK_TMPSIZE) ? DPACK_TMPSIZE : cdataLeft,
|
|
332 dfResPackFile->file);
|
|
333
|
|
334 cdataLeft -= cstream.avail_in;
|
|
335 cstream.next_in = cbuffer;
|
|
336 cres = inflate(&cstream, Z_FULL_FLUSH);
|
|
337 }
|
|
338
|
|
339 // Cleanup
|
|
340 inflateEnd(&(cstream));
|
|
341
|
|
342 error:
|
|
343 dmFree(cbuffer);
|
|
344 return res;
|
|
345 }
|
|
346 #endif
|
|
347
|
|
348
|
|
349 static void dm_mem_fclose(DMResource * f)
|
|
350 {
|
|
351 f->dataSize = 0;
|
|
352 f->dataOffset = 0;
|
|
353 dmFree(f->data);
|
|
354 f->data = NULL;
|
|
355 }
|
|
356
|
|
357
|
|
358 static int dm_mem_ferror(DMResource * f)
|
|
359 {
|
|
360 return f->error;
|
|
361 }
|
|
362
|
|
363
|
|
364 static int dm_mem_fseek(DMResource * f, const off_t offset, const int whence)
|
|
365 {
|
|
366 off_t newPos;
|
|
367
|
|
368 // Calculate the new position
|
|
369 switch (whence)
|
|
370 {
|
|
371 case SEEK_SET:
|
|
372 newPos = offset;
|
|
373 break;
|
|
374
|
|
375 case SEEK_CUR:
|
|
376 newPos = f->dataOffset + offset;
|
|
377 break;
|
|
378
|
|
379 case SEEK_END:
|
|
380 newPos = f->dataSize + offset;
|
|
381 break;
|
|
382
|
|
383 default:
|
|
384 return -1;
|
|
385 }
|
|
386
|
|
387 // Set the new position
|
|
388 f->dataOffset = newPos;
|
|
389
|
|
390 // Check the new position
|
|
391 if (newPos < 0 && (size_t) newPos >= f->dataSize)
|
|
392 return -1;
|
|
393
|
|
394 return 0;
|
|
395 }
|
|
396
|
|
397
|
|
398 static off_t dm_mem_fsize(DMResource * f)
|
|
399 {
|
|
400 return f->dataSize;
|
|
401 }
|
|
402
|
|
403
|
|
404 static off_t dm_mem_ftell(DMResource * f)
|
|
405 {
|
|
406 return f->dataOffset;
|
|
407 }
|
|
408
|
|
409
|
|
410 static BOOL dm_mem_feof(DMResource * f)
|
|
411 {
|
|
412 // Check for EOF
|
|
413 if ((size_t) f->dataOffset <= f->dataSize)
|
|
414 return FALSE;
|
|
415 else
|
|
416 return TRUE;
|
|
417 }
|
|
418
|
|
419
|
|
420 static int dm_mem_fgetc(DMResource * f)
|
|
421 {
|
|
422 // Check for EOF
|
|
423 if ((size_t) f->dataOffset < f->dataSize)
|
|
424 return (int) f->data[f->dataOffset++];
|
|
425 else
|
|
426 return EOF;
|
|
427 }
|
|
428
|
|
429
|
|
430 static size_t dm_mem_fread(void *buf, size_t size, size_t nmemb, DMResource * f)
|
|
431 {
|
|
432 size_t length = (size * nmemb);
|
|
433
|
|
434 // Check if we can read the whole chunk
|
|
435 if (((size_t) f->dataOffset + length) >= f->dataSize)
|
|
436 {
|
|
437 nmemb = (f->dataSize - f->dataOffset) / size;
|
|
438 length = size * nmemb;
|
|
439 }
|
|
440
|
|
441 memcpy(buf, f->data + f->dataOffset, length);
|
|
442 f->dataOffset += length;
|
|
443 return nmemb;
|
|
444 }
|
|
445
|
|
446
|
|
447 DMResourceOps dfPackFileOps =
|
|
448 {
|
|
449 dm_mem_ferror,
|
|
450 dm_mem_fseek,
|
|
451 dm_mem_fsize,
|
|
452 dm_mem_ftell,
|
|
453 dm_mem_feof,
|
|
454 dm_mem_fgetc,
|
|
455 dm_mem_fread,
|
|
456
|
|
457 NULL,
|
|
458 dm_mem_fclose,
|
|
459 dm_pack_preload
|
|
460 };
|
|
461
|
|
462
|
|
463 DMResourceOps dfMemIOFileOps =
|
|
464 {
|
|
465 dm_mem_ferror,
|
|
466 dm_mem_fseek,
|
|
467 dm_mem_fsize,
|
|
468 dm_mem_ftell,
|
|
469 dm_mem_feof,
|
|
470 dm_mem_fgetc,
|
|
471 dm_mem_fread,
|
|
472
|
|
473 NULL,
|
|
474 NULL,
|
|
475 NULL
|
|
476 };
|
|
477
|
|
478
|
|
479 /* FS file handling functions. These functions call the actual
|
|
480 * functions depending on where the file is located.
|
|
481 */
|
|
482 DMResource *dmf_open(const char *filename)
|
|
483 {
|
|
484 int ret;
|
|
485 DMResource *handle;
|
|
486
|
|
487 // Check master directory for resource
|
|
488 if ((handle = dmres_find(filename)) == NULL)
|
|
489 {
|
|
490 #ifdef DMRES_STDIO
|
|
491 // Hmm.. does not exist? Fall back to a stdio file
|
|
492 handle = dmres_new(filename, 0, 0);
|
|
493 if (handle == NULL)
|
|
494 return NULL;
|
|
495
|
|
496 handle->fops = &dfStdioFileOps;
|
|
497 dmres_insert(handle);
|
|
498 #else
|
|
499 // Stdio not enabled, fail
|
|
500 return NULL;
|
|
501 #endif
|
|
502 }
|
|
503
|
|
504 // Check fops
|
|
505 if (handle->fops == NULL)
|
|
506 {
|
|
507 #ifdef DMRES_PACKFS
|
|
508 if (dfResFlags & DRF_USE_PACK)
|
|
509 handle->fops = &dfPackFileOps;
|
|
510 #ifdef DMRES_STDIO
|
|
511 else
|
|
512 handle->fops = &dfStdioFileOps;
|
|
513 #else
|
|
514 handle->fops = &dfPackFileOps;
|
|
515 #endif
|
|
516
|
|
517 #else
|
|
518 handle->fops = &dfStdioFileOps;
|
|
519 #endif
|
|
520 }
|
|
521
|
|
522 // Check if the data is preloaded
|
|
523 if (handle->flags & DMF_LOADED)
|
|
524 {
|
|
525 dmres_ref(handle);
|
|
526 return handle;
|
|
527 }
|
|
528
|
|
529 // Check if we want to preload ..
|
|
530 ret = DMERR_INIT_FAIL;
|
|
531 if ((handle->flags & DMF_PRELOAD) &&
|
|
532 handle->fops->preload != NULL)
|
|
533 ret = handle->fops->preload(handle);
|
|
534 else
|
|
535 {
|
|
536 if (handle->fops->fopen != NULL)
|
|
537 ret = handle->fops->fopen(handle);
|
|
538 else
|
|
539 if (handle->fops->preload != NULL)
|
|
540 ret = handle->fops->preload(handle);
|
|
541 }
|
|
542
|
|
543 if (ret == DMERR_OK)
|
|
544 return handle;
|
|
545
|
|
546 dmres_ref(handle);
|
|
547 return NULL;
|
|
548 }
|
|
549
|
|
550
|
|
551 DMResource * dmf_open_memio(const char *filename, Uint8 *buf, size_t len)
|
|
552 {
|
|
553 DMResource *handle;
|
|
554
|
|
555 // Check master directory for resource
|
|
556 if ((handle = dmres_find(filename)) == NULL)
|
|
557 {
|
|
558 // Hmm.. does not exist? Fall back to a stdio file
|
|
559 handle = dmres_new(filename, DMF_LOADED, len);
|
|
560 if (handle == NULL)
|
|
561 return NULL;
|
|
562
|
|
563 handle->fops = &dfMemIOFileOps;
|
|
564 handle->data = buf;
|
|
565 dmres_insert(handle);
|
|
566 }
|
|
567
|
|
568 // Increase refcount
|
|
569 dmres_ref(handle);
|
|
570
|
|
571 return handle;
|
|
572 }
|
|
573
|
|
574
|
|
575 #ifdef DMRES_STDIO
|
|
576 DMResource * dmf_create_stdio(const char *filename)
|
|
577 {
|
|
578 DMResource *handle = dmres_new(filename, 0, 0);
|
|
579 if (handle == NULL)
|
|
580 return NULL;
|
|
581
|
|
582 handle->fops = &dfStdioFileOps;
|
|
583
|
|
584 handle->fh = fopen(filename, "rb");
|
|
585 handle->error = dmGetErrno();
|
|
586
|
|
587 if (handle->fh != NULL)
|
|
588 {
|
|
589 dmres_ref(handle);
|
|
590 return handle;
|
|
591 }
|
|
592 else
|
|
593 {
|
|
594 dmres_free(handle);
|
|
595 return NULL;
|
|
596 }
|
|
597 }
|
|
598
|
|
599
|
|
600 DMResource * dmf_create_stdio_stream(FILE *fh)
|
|
601 {
|
|
602 DMResource *handle = dmres_new("", 0, 0);
|
|
603 if (handle == NULL)
|
|
604 return NULL;
|
|
605
|
|
606 handle->fops = &dfStdioFHOps;
|
|
607 handle->fh = fh;
|
|
608 dmres_ref(handle);
|
|
609 return handle;
|
|
610 }
|
|
611 #endif
|
|
612
|
|
613
|
|
614 void dmf_close(DMResource * f)
|
|
615 {
|
|
616 if (f == NULL)
|
|
617 return;
|
|
618
|
|
619 if (f->fops->fclose != NULL)
|
|
620 f->fops->fclose(f);
|
|
621
|
|
622 dmres_unref(f);
|
|
623 }
|
|
624
|
|
625
|
|
626 int dmferror(DMResource * f)
|
|
627 {
|
|
628 f->atime = time(NULL);
|
|
629 return f->fops->ferror(f);
|
|
630 }
|
|
631
|
|
632 int dmfseek(DMResource * f, off_t offset, int whence)
|
|
633 {
|
|
634 f->atime = time(NULL);
|
|
635 return f->fops->fseek(f, offset, whence);
|
|
636 }
|
|
637
|
|
638 off_t dmfsize(DMResource * f)
|
|
639 {
|
|
640 f->atime = time(NULL);
|
|
641 return f->fops->fsize(f);
|
|
642 }
|
|
643
|
|
644 off_t dmftell(DMResource * f)
|
|
645 {
|
|
646 f->atime = time(NULL);
|
|
647 return f->fops->ftell(f);
|
|
648 }
|
|
649
|
|
650 BOOL dmfeof(DMResource * f)
|
|
651 {
|
|
652 f->atime = time(NULL);
|
|
653 return f->fops->feof(f);
|
|
654 }
|
|
655
|
|
656 int dmfgetc(DMResource * f)
|
|
657 {
|
|
658 f->atime = time(NULL);
|
|
659 return f->fops->fgetc(f);
|
|
660 }
|
|
661
|
|
662 size_t dmfread(void *ptr, size_t size, size_t nmemb, DMResource * f)
|
|
663 {
|
|
664 f->atime = time(NULL);
|
|
665 return f->fops->fread(ptr, size, nmemb, f);
|
|
666 }
|
|
667
|
|
668
|
|
669 int dmres_ref(DMResource *res)
|
|
670 {
|
|
671 DMRES_LOCK();
|
|
672 res->atime = time(NULL);
|
|
673 res->refcount++;
|
|
674 DMRES_UNLOCK();
|
|
675
|
|
676 return res->refcount;
|
|
677 }
|
|
678
|
|
679
|
|
680 int dmres_unref(DMResource *res)
|
|
681 {
|
|
682 DMRES_LOCK();
|
|
683 res->refcount--;
|
|
684 DMRES_UNLOCK();
|
|
685
|
|
686 return res->refcount;
|
|
687 }
|
|
688
|
|
689
|
|
690 int dmres_load_resfile(const char *filename)
|
|
691 {
|
|
692 int ret;
|
|
693 char line[256];
|
|
694 FILE *f = fopen(filename, "r");
|
|
695 if (f == NULL)
|
|
696 return DMERR_FOPEN;
|
|
697
|
|
698 DMRES_LOCK();
|
|
699
|
|
700 while (fgets(line, sizeof(line) - 1, f) != NULL)
|
|
701 {
|
|
702 int fnstart, fsep;
|
|
703 for (fnstart = 0; isspace(line[fnstart]); fnstart++);
|
|
704 for (fsep = fnstart; line[fsep] && line[fsep] != '|'; fsep++);
|
|
705 if (line[fsep] == '|')
|
|
706 {
|
|
707 int flags, i;
|
|
708 for (i = fsep - 1; i > 0 && isspace(line[i]); i--)
|
|
709 line[i] = 0;
|
|
710
|
|
711 for (i = fsep; isspace(line[i]); i++);
|
|
712
|
|
713 if (sscanf(&line[i], "%x", &flags) == 1 &&
|
|
714 strlen(&line[fnstart]) > 0)
|
|
715 {
|
|
716
|
|
717 }
|
|
718 }
|
|
719 }
|
|
720
|
|
721 DMRES_UNLOCK();
|
|
722 fclose(f);
|
|
723 return ret;
|
|
724 }
|
|
725
|
|
726
|
|
727 int dmres_write_resfile(const char *filename)
|
|
728 {
|
|
729 int ret;
|
|
730 DMResource *node;
|
|
731 FILE *f = fopen(filename, "w");
|
|
732 if (f == NULL)
|
|
733 return DMERR_FOPEN;
|
|
734
|
|
735 DMRES_LOCK();
|
|
736
|
|
737 for (node = dfResources; node != NULL; node = node->next)
|
|
738 {
|
|
739 if (fprintf(f, "%s|%08x\n", node->filename, node->flags) < 0)
|
|
740 {
|
|
741 ret = DMERR_FWRITE;
|
|
742 goto error;
|
|
743 }
|
|
744 }
|
|
745
|
|
746 error:
|
|
747 DMRES_UNLOCK();
|
|
748 fclose(f);
|
|
749 return ret;
|
|
750 }
|
|
751
|
|
752
|
|
753 /* Resources subsystem initialization and shutdown routines
|
|
754 */
|
|
755 int dmres_init(const char *filename, const char *path, int flags)
|
|
756 {
|
|
757 // Check if we are already initialized
|
|
758 if (dfResInitialized)
|
|
759 return DMERR_ALREADY_INIT;
|
|
760
|
|
761 dfResFlags = flags;
|
|
762 dfResPath = dm_strdup((path != NULL) ? path : DMRES_DATA_PATH);
|
|
763 dfResourcesMutex = dmCreateMutex();
|
|
764
|
|
765 if (flags & DRF_USE_PACK)
|
|
766 {
|
|
767 #ifdef DMRES_PACKFS
|
|
768 int ret;
|
|
769 DMPackEntry *node;
|
|
770
|
|
771 dfResPackFilename = dm_strdup((filename != NULL) ? filename : DMRES_DATA_PACK);
|
|
772
|
|
773 // Initialize PACK, open as read-only
|
|
774 ret = dm_pack_open(dfResPackFilename, &dfResPackFile, TRUE);
|
|
775 if (ret != DMERR_OK)
|
|
776 {
|
|
777 dmError("Error opening PACK file '%s', #%i: %s\n",
|
|
778 dfResPackFilename, ret, dmErrorStr(ret));
|
|
779
|
|
780 return DMERR_INIT_FAIL;
|
|
781 }
|
|
782
|
|
783 // Initialize resources from a PACK file
|
|
784 for (node = dfResPackFile->entries; node != NULL; node = node->next)
|
|
785 {
|
|
786 DMResource *res = dmres_new(node->filename, node->resFlags, node->size);
|
|
787 if (res == NULL)
|
|
788 {
|
|
789 dmError("Could not allocate memory for resource node '%s' [0x%08x], %d.\n",
|
|
790 node->filename, node->resFlags, node->size);
|
|
791 return DMERR_INIT_FAIL;
|
|
792 }
|
|
793
|
|
794 dmres_insert(res);
|
|
795 }
|
|
796
|
|
797 #else
|
|
798 // PACK not compiled in, FAIL!
|
|
799 return DMERR_INIT_FAIL;
|
|
800 #endif
|
|
801 }
|
|
802 else
|
|
803 {
|
|
804 // Initialize resources from a resource directory
|
|
805 char *resFilename = dm_strdup_printf("%s%s", dfResPath, DMRES_RES_FILE);
|
|
806 int ret = dmres_load_resfile(resFilename);
|
|
807 dmFree(resFilename);
|
|
808
|
|
809 if (ret != DMERR_OK)
|
|
810 return DMERR_INIT_FAIL;
|
|
811 }
|
|
812
|
|
813
|
|
814 // Initialization complete
|
|
815 dfResInitialized = TRUE;
|
|
816 return DMERR_OK;
|
|
817 }
|
|
818
|
|
819
|
|
820 void dmres_close(void)
|
|
821 {
|
|
822 DMResource *node;
|
|
823 DMRES_LOCK();
|
|
824
|
|
825 if (!dfResInitialized)
|
|
826 return;
|
|
827
|
|
828 // Shutdown possible subsystems
|
|
829 #ifdef DMRES_PACKFS
|
|
830 if (dfResFlags & DRF_USE_PACK)
|
|
831 {
|
|
832 int res = dm_pack_close(dfResPackFile);
|
|
833 if (res != DMERR_OK)
|
|
834 {
|
|
835 dmError("Error closing PACK, #%i: %s\n",
|
|
836 res, dmErrorStr(res));
|
|
837 }
|
|
838
|
|
839 dmFree(dfResPackFilename);
|
|
840 }
|
|
841 #endif
|
|
842
|
|
843 // Free resource entries
|
|
844 node = dfResources;
|
|
845 while (node != NULL)
|
|
846 {
|
|
847 DMResource *next = node->next;
|
|
848 dmres_free(node);
|
|
849 node = next;
|
|
850 }
|
|
851
|
|
852 // Etc.
|
|
853 dmFree(dfResPath);
|
|
854 DMRES_UNLOCK();
|
|
855 dmDestroyMutex(dfResourcesMutex);
|
|
856 dfResInitialized = FALSE;
|
|
857 }
|
|
858
|
|
859
|
|
860 BOOL dmres_preload(int *loaded, int *total)
|
|
861 {
|
|
862 static DMResource *dfPreload = NULL;
|
|
863
|
|
864 DMRES_LOCK();
|
|
865
|
|
866 if (dfPreload == NULL)
|
|
867 {
|
|
868 DMResource *node;
|
|
869 dfPreload = dfResources;
|
|
870 *loaded = 0;
|
|
871 *total = 0;
|
|
872 for (node = dfResources; node != NULL; node = node->next)
|
|
873 {
|
|
874 if (node->flags & DMF_PRELOAD)
|
|
875 (*total)++;
|
|
876 }
|
|
877 }
|
|
878
|
|
879 if (dfPreload != NULL)
|
|
880 {
|
|
881 if (dfPreload->flags & DMF_PRELOAD)
|
|
882 {
|
|
883 (*loaded)++;
|
|
884 }
|
|
885
|
|
886 dfPreload = dfPreload->next;
|
|
887 }
|
|
888
|
|
889 DMRES_UNLOCK();
|
|
890
|
|
891 return (*total) == (*loaded);
|
|
892 }
|
|
893
|
|
894
|
|
895 void dmres_prune(int agems, int flags)
|
|
896 {
|
|
897 DMResource *node, *next;
|
|
898 int currtime = time(NULL);
|
|
899 DMRES_LOCK();
|
|
900
|
|
901 node = dfResources;
|
|
902 while (node != NULL)
|
|
903 {
|
|
904 next = node->next;
|
|
905 // Check if node has refcount of 0 and is
|
|
906 // not marked as persistent resource
|
|
907 if (node->refcount == 0 && (node->flags & DMF_PERSIST) == 0)
|
|
908 {
|
|
909 // Check if we match either one of atime or mtime
|
|
910 if (((flags & DMPRUNE_ATIME) &&
|
|
911 currtime - node->atime >= agems) ||
|
|
912 ((flags & DMPRUNE_MTIME) &&
|
|
913 currtime - node->mtime >= agems))
|
|
914 {
|
|
915 dmres_delete(node);
|
|
916 }
|
|
917 }
|
|
918 node = next;
|
|
919 }
|
|
920
|
|
921 DMRES_UNLOCK();
|
|
922 }
|
|
923
|
|
924
|
|
925 /* Helper resource access routines
|
|
926 */
|
|
927 int dmf_read_str(DMResource *f, Uint8 *s, size_t l)
|
|
928 {
|
|
929 return dmfread(s, sizeof(Uint8), l, f) == l;
|
|
930 }
|
|
931
|
|
932
|
|
933 #define DM_DEFINE_FUNC(xname, xtype, xmacro) \
|
|
934 BOOL dmf_read_ ## xname (DMResource *f, xtype *v) { \
|
|
935 xtype result; \
|
|
936 if (dmfread(&result, sizeof( xtype ), 1, f) != 1) \
|
|
937 return FALSE; \
|
|
938 *v = DM_ ## xmacro ## _TO_NATIVE (result); \
|
|
939 return TRUE; \
|
|
940 }
|
|
941
|
|
942 DM_DEFINE_FUNC(le16, Uint16, LE16)
|
|
943 DM_DEFINE_FUNC(le32, Uint32, LE32)
|
|
944
|
|
945 DM_DEFINE_FUNC(be16, Uint16, BE16)
|
|
946 DM_DEFINE_FUNC(be32, Uint32, BE32)
|
|
947
|
|
948 #ifdef DM_HAVE_64BIT
|
|
949 DM_DEFINE_FUNC(le64, Uint64, LE64)
|
|
950 DM_DEFINE_FUNC(be64, Uint64, BE64)
|
|
951 #endif
|