comparison src/dmres.c @ 812:1e5cf1144f36

Move library source under src/ subdirectory.
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 16 May 2014 03:22:39 +0300
parents dmres.c@897646df1de1
children 27949209238b
comparison
equal deleted inserted replaced
811:aebc2f8b2c2d 812:1e5cf1144f36
1 /*
2 * dmlib
3 * -- Resource management
4 * Programmed and designed by Matti 'ccr' Hamalainen
5 * (C) Copyright 2003-2013 Tecnic Software productions (TNSP)
6 */
7 #include "dmres.h"
8 #include <time.h>
9
10 #ifdef DM_USE_PACKFS
11 #include <zlib.h>
12 #endif
13
14 #ifdef DM_USE_STDIO
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <unistd.h>
18 #include <dirent.h>
19 #endif
20
21
22 DMResource *dmResourceNew(DMResourceLib *lib, const char *filename, const size_t size)
23 {
24 DMResource *node = dmMalloc0(sizeof(DMResource));
25 if (node == NULL)
26 return NULL;
27
28 node->lib = lib;
29 node->filename = dm_strdup(filename);
30 node->rawSize = size;
31
32 return node;
33 }
34
35
36 void dmResourceFreeResData(DMResource *node)
37 {
38 if (node->resData != NULL &&
39 node->rops != NULL &&
40 node->rops->free != NULL)
41 {
42 node->rops->free(node);
43 }
44
45 node->resData = NULL;
46 node->flags &= ~DMF_LOADED_RES;
47 }
48
49
50 void dmResourceFreeRawData(DMResource *node)
51 {
52 if ((node->flags & DMF_UNALLOCATED) == 0)
53 {
54 dmFree(node->rawData);
55 node->rawData = NULL;
56 node->flags &= ~DMF_LOADED_RAW;
57 }
58 }
59
60
61 void dmResourceFree(DMResource *node)
62 {
63 if (node != NULL)
64 {
65 dmResourceFreeResData(node);
66 dmResourceFreeRawData(node);
67 dmFree(node->filename);
68 dmFree(node);
69 }
70 }
71
72
73 void dmResourceInsert(DMResourceLib *lib, DMResource * node)
74 {
75 if (lib == NULL || node == NULL)
76 return;
77
78 node->lib = lib;
79
80 if (lib->resources != NULL)
81 {
82 node->prev = lib->resources->prev;
83 lib->resources->prev->next = node;
84 lib->resources->prev = node;
85 }
86 else
87 {
88 lib->resources = node->prev = node;
89 }
90
91 node->next = NULL;
92 }
93
94
95 void dmResourceDelete(DMResourceLib *lib, DMResource * node)
96 {
97 if (lib == NULL)
98 return;
99
100 if (node->prev)
101 node->prev->next = node->next;
102
103 if (node->next)
104 node->next->prev = node->prev;
105 else
106 lib->resources->prev = node->prev;
107
108 node->prev = node->next = NULL;
109 }
110
111
112 DMResource * dmResourceFind(DMResourceLib *lib, const char *filename)
113 {
114 DMResource *node, *found = NULL;
115
116 if (lib == NULL)
117 return NULL;
118
119 dmMutexLock(lib->mutex);
120
121 for (node = lib->resources; node != NULL; node = node->next)
122 {
123 if (strcmp(node->filename, filename) == 0)
124 {
125 found = node;
126 break;
127 }
128 }
129
130 dmMutexUnlock(lib->mutex);
131
132 return found;
133 }
134
135
136 #ifdef DM_USE_STDIO
137 /* Basic stdio file routines
138 */
139 static int dm_stdio_fopen(DMResource *handle)
140 {
141 char *rfilename = dm_strdup_printf("%s%s", DMRES_DATA_PATH, handle->filename);
142 if (rfilename == NULL)
143 return DMERR_MALLOC;
144
145 handle->fh = fopen(rfilename, "rb");
146 dmFree(rfilename);
147
148 handle->error = dmGetErrno();
149 return (handle->fh != NULL) ? DMERR_OK : DMERR_FOPEN;
150 }
151
152
153 static void dm_stdio_fclose(DMResource * f)
154 {
155 if (f->fh != NULL)
156 {
157 fclose(f->fh);
158 f->fh = NULL;
159 }
160 }
161
162
163 static int dm_stdio_ferror(DMResource * f)
164 {
165 return f->error;
166 }
167
168
169 static int dm_stdio_fseek(DMResource *f, const off_t pos, const int whence)
170 {
171 int ret = fseek(f->fh, pos, whence);
172 f->error = dmGetErrno();
173 return ret;
174 }
175
176
177 static int dm_stdio_freset(DMResource * f)
178 {
179 if (f->fh != NULL)
180 return dm_stdio_fseek(f, 0L, SEEK_SET);
181 else
182 return DMERR_OK;
183 }
184
185
186 static off_t dm_stdio_fsize(DMResource *f)
187 {
188 off_t savePos, fileSize;
189
190 // Check if the size is cached
191 if (f->rawSize != 0)
192 return f->rawSize;
193
194 // Get file size
195 savePos = ftello(f->fh);
196 if (fseeko(f->fh, 0L, SEEK_END) != 0)
197 {
198 f->error = dmGetErrno();
199 return -1;
200 }
201
202 fileSize = ftello(f->fh);
203 if (fseeko(f->fh, savePos, SEEK_SET) != 0)
204 {
205 f->error = dmGetErrno();
206 return -1;
207 }
208
209 f->rawSize = fileSize;
210 return fileSize;
211 }
212
213
214 static off_t dm_stdio_ftell(DMResource * f)
215 {
216 return ftell(f->fh);
217 }
218
219
220 static BOOL dm_stdio_feof(DMResource * f)
221 {
222 return feof(f->fh);
223 }
224
225
226 static int dm_stdio_fgetc(DMResource * f)
227 {
228 int ret = fgetc(f->fh);
229 f->error = dmGetErrno();
230 return ret;
231 }
232
233
234 static int dm_stdio_fputc(int v, DMResource * f)
235 {
236 int ret = fputc(v, f->fh);
237 f->error = dmGetErrno();
238 return ret;
239 }
240
241
242 static size_t dm_stdio_fread(void *ptr, size_t size, size_t nmemb, DMResource * f)
243 {
244 size_t ret = fread(ptr, size, nmemb, f->fh);
245 f->error = dmGetErrno();
246 return ret;
247 }
248
249
250 static size_t dm_stdio_fwrite(void *ptr, size_t size, size_t nmemb, DMResource * f)
251 {
252 size_t ret = fwrite(ptr, size, nmemb, f->fh);
253 f->error = dmGetErrno();
254 return ret;
255 }
256
257
258 static int dm_stdio_preload(DMResource *handle)
259 {
260 int ret = dm_stdio_fopen(handle);
261 if (ret != DMERR_OK)
262 return ret;
263
264 dm_stdio_fsize(handle);
265
266 handle->rawData = dmMalloc(handle->rawSize);
267 if (handle->rawData == NULL)
268 return DMERR_MALLOC;
269
270 if (dm_stdio_fread(handle->rawData, sizeof(Uint8), handle->rawSize, handle) != handle->rawSize)
271 return DMERR_FREAD;
272
273 return DMERR_OK;
274 }
275
276
277 DMResourceOps dfStdioFileOps =
278 {
279 "Stdio",
280
281 dm_stdio_freset,
282 dm_stdio_ferror,
283 dm_stdio_fseek,
284 dm_stdio_fsize,
285 dm_stdio_ftell,
286 dm_stdio_feof,
287 dm_stdio_fgetc,
288 dm_stdio_fputc,
289 dm_stdio_fread,
290 dm_stdio_fwrite,
291
292 dm_stdio_fopen,
293 dm_stdio_fclose,
294 dm_stdio_preload
295 };
296
297 DMResourceOps dfStdioFHOps =
298 {
299 "StdioFH",
300
301 dm_stdio_freset,
302 dm_stdio_ferror,
303 dm_stdio_fseek,
304 dm_stdio_fsize,
305 dm_stdio_ftell,
306 dm_stdio_feof,
307 dm_stdio_fgetc,
308 dm_stdio_fputc,
309 dm_stdio_fread,
310 dm_stdio_fwrite,
311
312 NULL,
313 NULL,
314 NULL
315 };
316 #endif
317
318
319 // Some mingw/windows headers define these as macros, which is bad for us
320 #ifdef __WIN32
321 #undef ferror
322 #undef feof
323 #endif
324
325
326 /*
327 * PACK file routines
328 */
329 #ifdef DM_USE_PACKFS
330 static int dm_pack_preload(DMResource *handle)
331 {
332 DMPackEntry *node;
333 int res = DMERR_OK, cres, cdataLeft;
334 z_stream cstream;
335 Uint8 * cbuffer = NULL;
336
337 if (handle->lib == NULL || handle->lib->packFile == NULL)
338 return DMERR_NULLPTR;
339
340 // Search PACK nodelist for file
341 if ((node = dmPackFind(handle->lib->packFile->entries, handle->filename)) == NULL)
342 {
343 dmError("Entry '%s' not found in PACK file.\n", handle->filename);
344 res = DMERR_NOT_FOUND;
345 goto error;
346 }
347
348 // Seek to entry
349 if (fseek(handle->lib->packFile->file, node->offset, SEEK_SET) == -1)
350 {
351 dmError("Could not seek node position in PACK file.\n");
352 res = DMERR_FSEEK;
353 goto error;
354 }
355
356 // Allocate a structures and buffers
357 cbuffer = (Uint8 *) dmMalloc(DPACK_TMPSIZE);
358 if (cbuffer == NULL)
359 {
360 res = DMERR_MALLOC;
361 goto error;
362 }
363
364 // Initialize fields
365 handle->rawOffset = 0;
366 handle->rawSize = node->size;
367 handle->rawData = (Uint8 *) dmMalloc(node->size);
368 if (handle->rawData == NULL)
369 {
370 res = DMERR_MALLOC;
371 goto error;
372 }
373
374 // Initialize decompression
375 cstream.zalloc = (alloc_func) Z_NULL;
376 cstream.zfree = (free_func) Z_NULL;
377 cstream.opaque = (voidpf) Z_NULL;
378 cstream.next_out = handle->rawData;
379 cstream.avail_out = handle->rawSize;
380 cdataLeft = node->length;
381 cres = inflateInit(&(cstream));
382 if (cres != Z_OK)
383 {
384 dmError("Could not initialize zlib stream inflation.\n");
385 res = DMERR_INIT_FAIL;
386 goto error;
387 }
388
389 // Uncompress the data
390 while (cdataLeft > 0 &&
391 cstream.avail_out > 0 && cres == Z_OK)
392 {
393 cstream.avail_in = fread(
394 cbuffer, sizeof(Uint8),
395 (cdataLeft >= DPACK_TMPSIZE) ? DPACK_TMPSIZE : cdataLeft,
396 handle->lib->packFile->file);
397
398 cdataLeft -= cstream.avail_in;
399 cstream.next_in = cbuffer;
400 cres = inflate(&cstream, Z_FULL_FLUSH);
401 }
402
403 // Cleanup
404 inflateEnd(&(cstream));
405
406 error:
407 dmFree(cbuffer);
408 return res;
409 }
410
411
412 static int dm_pack_fopen(DMResource * f)
413 {
414 if ((f->flags & DMF_LOADED_RAW) == 0)
415 {
416 int res = dm_pack_preload(f);
417 if (res == DMERR_OK)
418 f->flags |= DMF_LOADED_RAW;
419
420 return res;
421 }
422 else
423 return DMERR_OK;
424 }
425
426
427 static void dm_pack_fclose(DMResource * f)
428 {
429 if ((f->flags & DMF_PERSIST) == 0)
430 dmResourceFreeRawData(f);
431 }
432 #endif
433
434
435 static int dm_mem_freset(DMResource * f)
436 {
437 f->rawOffset = 0;
438 return DMERR_OK;
439 }
440
441
442 static int dm_mem_ferror(DMResource * f)
443 {
444 return f->error;
445 }
446
447
448 static int dm_mem_fseek(DMResource * f, const off_t offset, const int whence)
449 {
450 off_t newPos;
451
452 // Calculate the new position
453 switch (whence)
454 {
455 case SEEK_SET:
456 newPos = offset;
457 break;
458
459 case SEEK_CUR:
460 newPos = f->rawOffset + offset;
461 break;
462
463 case SEEK_END:
464 newPos = f->rawSize + offset;
465 break;
466
467 default:
468 return -1;
469 }
470
471 // Set the new position
472 f->rawOffset = newPos;
473
474 // Check the new position
475 if (newPos < 0 && (size_t) newPos >= f->rawSize)
476 return -1;
477
478 return 0;
479 }
480
481
482 static off_t dm_mem_fsize(DMResource * f)
483 {
484 return f->rawSize;
485 }
486
487
488 static off_t dm_mem_ftell(DMResource * f)
489 {
490 return f->rawOffset;
491 }
492
493
494 static BOOL dm_mem_feof(DMResource * f)
495 {
496 // Check for EOF
497 if ((size_t) f->rawOffset <= f->rawSize)
498 return FALSE;
499 else
500 return TRUE;
501 }
502
503
504 static int dm_mem_fgetc(DMResource * f)
505 {
506 // Check for EOF
507 if ((size_t) f->rawOffset < f->rawSize)
508 return f->rawData[f->rawOffset++];
509 else
510 return EOF;
511 }
512
513
514 static size_t dm_mem_fread(void *buf, size_t size, size_t nmemb, DMResource * f)
515 {
516 size_t length = (size * nmemb);
517
518 // Check if we can read the whole chunk
519 if (((size_t) f->rawOffset + length) >= f->rawSize)
520 {
521 nmemb = (f->rawSize - f->rawOffset) / size;
522 length = size * nmemb;
523 }
524
525 memcpy(buf, f->rawData + f->rawOffset, length);
526 f->rawOffset += length;
527 return nmemb;
528 }
529
530
531 static int dm_mem_fputc(int ch, DMResource * f)
532 {
533 // Check for EOF
534 if ((size_t) f->rawOffset < f->rawSize)
535 {
536 f->rawData[f->rawOffset++] = ch;
537 return ch;
538 }
539 else
540 return EOF;
541 }
542
543
544 static size_t dm_mem_fwrite(void *buf, size_t size, size_t nmemb, DMResource * f)
545 {
546 size_t length = (size * nmemb);
547
548 // Check if we can write the whole chunk
549 if (((size_t) f->rawOffset + length) >= f->rawSize)
550 {
551 nmemb = (f->rawSize - f->rawOffset) / size;
552 length = size * nmemb;
553 }
554
555 if (length > 0)
556 {
557 memcpy(f->rawData + f->rawOffset, buf, length);
558 f->rawOffset += length;
559 }
560 return nmemb;
561 }
562
563
564 #ifdef DM_USE_PACKFS
565 DMResourceOps dfPackFileOps =
566 {
567 "PackFS",
568
569 dm_mem_freset,
570 dm_mem_ferror,
571 dm_mem_fseek,
572 dm_mem_fsize,
573 dm_mem_ftell,
574 dm_mem_feof,
575 dm_mem_fgetc,
576 NULL,
577 dm_mem_fread,
578 NULL,
579
580 dm_pack_fopen,
581 dm_pack_fclose,
582 dm_pack_preload,
583 };
584 #endif
585
586
587 DMResourceOps dfMemIOFileOps =
588 {
589 "MemIO",
590
591 dm_mem_freset,
592 dm_mem_ferror,
593 dm_mem_fseek,
594 dm_mem_fsize,
595 dm_mem_ftell,
596 dm_mem_feof,
597 dm_mem_fgetc,
598 dm_mem_fputc,
599 dm_mem_fread,
600 dm_mem_fwrite,
601
602 NULL,
603 dmResourceFree,
604 NULL
605 };
606
607
608 /* FS file handling functions. These functions call the actual
609 * functions depending on where the file is located.
610 */
611 static int dmResourcePreload(DMResource *handle)
612 {
613 int ret = DMERR_OK;
614
615 // Check if we want to preload raw data?
616 if ((handle->lib->flags & DRF_PRELOAD_RAW) ||
617 handle->rops == NULL || handle->rops->load == NULL)
618 {
619 if (handle->flags & DMF_LOADED_RAW)
620 ret = DMERR_OK;
621 else
622 if (handle->fops->preload != NULL)
623 {
624 ret = handle->fops->preload(handle);
625 if (ret == DMERR_OK)
626 handle->flags |= DMF_LOADED_RAW | DMF_PERSIST;
627 }
628 else
629 ret = DMERR_INIT_FAIL;
630
631 dmfreset(handle);
632 }
633
634 // Check if resource data is to be preloaded
635 if (handle->lib->flags & DRF_PRELOAD_RES)
636 {
637 if (handle->flags & DMF_LOADED_RES)
638 ret = DMERR_OK;
639 else
640 if (handle->rops != NULL &&
641 handle->rops->load != NULL)
642 {
643 if ((ret = handle->fops->fopen(handle)) == DMERR_OK)
644 {
645 ret = handle->rops->load(handle);
646 handle->fops->fclose(handle);
647 }
648
649 if (ret == DMERR_OK)
650 handle->flags |= DMF_LOADED_RES;
651 }
652
653 dmfreset(handle);
654 }
655
656 return ret;
657 }
658
659
660 int dmf_open(DMResourceLib *lib, const char *filename, DMResource **phandle)
661 {
662 DMResource *handle;
663 int res;
664
665 // Check master directory for resource
666 if ((*phandle = handle = dmResourceFind(lib, filename)) == NULL)
667 {
668 #ifdef DM_USE_STDIO
669 if (lib->flags & DRF_USE_STDIO)
670 {
671 // Hmm.. does not exist? Fall back to a stdio file
672 *phandle = handle = dmResourceNew(lib, filename, 0);
673 if (handle == NULL)
674 return DMERR_MALLOC;
675
676 handle->fops = &dfStdioFileOps;
677 }
678 else
679 return DMERR_INIT_FAIL;
680 #else
681 // Stdio not enabled, fail
682 return DMERR_INIT_FAIL;
683 #endif
684 }
685
686 // Check if the data is preloaded
687 if ((res = handle->fops->fopen(handle)) == DMERR_OK)
688 {
689 dmResourceRef(handle);
690 if (handle->flags & DMF_TEMPORARY)
691 {
692 handle->flags &= ~DMF_TEMPORARY;
693 dmResourceInsert(lib, handle);
694 }
695 }
696 else
697 if (handle->flags & DMF_TEMPORARY)
698 {
699 dmResourceFree(handle);
700 *phandle = handle = NULL;
701 }
702
703 dmfreset(handle);
704 return res;
705 }
706
707
708 int dmf_create_memio(DMResourceLib *lib, const char *filename,
709 Uint8 *buf, const size_t size, DMResource **phandle)
710 {
711 DMResource *handle;
712
713 // Check master directory for resource
714 if ((*phandle = handle = dmResourceFind(lib, filename)) == NULL)
715 {
716 if ((*phandle = handle = dmResourceNew(lib, filename, size)) == NULL)
717 return DMERR_MALLOC;
718
719 handle->flags = DMF_LOADED_RAW | DMF_UNALLOCATED;
720 handle->fops = &dfMemIOFileOps;
721 handle->rawData = buf;
722 dmResourceInsert(lib, handle);
723 }
724
725 // Increase refcount
726 dmResourceRef(handle);
727 dmfreset(handle);
728 return DMERR_OK;
729 }
730
731
732 #ifdef DM_USE_STDIO
733 int dmf_create_stdio(const char *filename, const char *mode, DMResource **phandle)
734 {
735 DMResource *handle;
736 if ((*phandle = handle = dmResourceNew(NULL, filename, 0)) == NULL)
737 return DMERR_MALLOC;
738
739 handle->fops = &dfStdioFileOps;
740 handle->fh = fopen(filename, mode);
741 handle->error = dmGetErrno();
742
743 if (handle->fh == NULL)
744 {
745 dmResourceFree(handle);
746 return handle->error;
747 }
748
749 dmResourceRef(handle);
750 return DMERR_OK;
751 }
752
753
754 int dmf_create_stdio_stream(FILE *fh, DMResource **phandle)
755 {
756 DMResource *handle;
757 if ((*phandle = handle = dmResourceNew(NULL, "", 0)) == NULL)
758 return DMERR_MALLOC;
759
760 handle->fops = &dfStdioFHOps;
761 handle->fh = fh;
762 dmResourceRef(handle);
763 return DMERR_OK;
764 }
765 #endif
766
767
768 void dmf_close(DMResource * f)
769 {
770 if (f == NULL)
771 return;
772
773 if (f->fops->fclose != NULL)
774 f->fops->fclose(f);
775
776 dmResourceUnref(f);
777 }
778
779
780 int dmfreset(DMResource *f)
781 {
782 if (f == NULL)
783 return DMERR_NULLPTR;
784
785 if (f->fops == NULL || f->fops->freset == NULL)
786 return DMERR_OK;
787
788 return f->fops->freset(f);
789 }
790
791 int dmferror(DMResource * f)
792 {
793 f->atime = time(NULL);
794 return f->fops->ferror(f);
795 }
796
797 int dmfseek(DMResource * f, off_t offset, int whence)
798 {
799 f->atime = time(NULL);
800 return f->fops->fseek(f, offset, whence);
801 }
802
803 off_t dmfsize(DMResource * f)
804 {
805 f->atime = time(NULL);
806 return f->fops->fsize(f);
807 }
808
809 off_t dmftell(DMResource * f)
810 {
811 f->atime = time(NULL);
812 return f->fops->ftell(f);
813 }
814
815 BOOL dmfeof(DMResource * f)
816 {
817 f->atime = time(NULL);
818 return f->fops->feof(f);
819 }
820
821 int dmfgetc(DMResource * f)
822 {
823 f->atime = time(NULL);
824 return f->fops->fgetc(f);
825 }
826
827 int dmfputc(int v, DMResource * f)
828 {
829 f->atime = time(NULL);
830 return f->fops->fputc(v, f);
831 }
832
833 size_t dmfread(void *ptr, size_t size, size_t nmemb, DMResource * f)
834 {
835 f->atime = time(NULL);
836 return f->fops->fread(ptr, size, nmemb, f);
837 }
838
839 size_t dmfwrite(void *ptr, size_t size, size_t nmemb, DMResource * f)
840 {
841 f->atime = time(NULL);
842 return f->fops->fwrite(ptr, size, nmemb, f);
843 }
844
845 char *dmfgets(char *s, int size, DMResource * f)
846 {
847 char *p = s, c;
848 int n = 0;
849
850 while ((c = f->fops->fgetc(f)) != EOF)
851 {
852 n++;
853 if (c == '\n')
854 break;
855 else
856 if (n < size - 1)
857 *p++ = c;
858 }
859 *p = 0;
860
861 return (n > 0) ? s : NULL;
862 }
863
864
865 int dmResourceRef(DMResource *node)
866 {
867 if (node->lib != NULL) dmMutexLock(node->lib->mutex);
868 node->atime = time(NULL);
869 node->refcount++;
870 if (node->lib != NULL) dmMutexUnlock(node->lib->mutex);
871
872 return node->refcount;
873 }
874
875
876 int dmResourceUnref(DMResource *node)
877 {
878 if (node->lib != NULL) dmMutexLock(node->lib->mutex);
879 node->refcount--;
880 if (node->lib != NULL) dmMutexUnlock(node->lib->mutex);
881
882 return node->refcount;
883 }
884
885
886 #ifdef DM_USE_STDIO
887 static int dmResourcesLoadDirectory(DMResourceLib *lib, const char *path)
888 {
889 int res = DMERR_OK;
890 struct dirent *dh;
891 DIR *hdir = opendir(path);
892 if (hdir == NULL)
893 return dmGetErrno();
894
895 dmMutexLock(lib->mutex);
896
897 do
898 {
899 DMResource *node = NULL;
900 dh = readdir(hdir);
901 if (dh != NULL)
902 {
903 struct stat sbuf;
904 char *fname = dm_strdup_printf("%s/%s", path, dh->d_name);
905 if (stat(fname, &sbuf) == -1)
906 {
907 res = dmGetErrno();
908 dmError("Could not stat() %s, #%d: %s\n",
909 fname, res, dmErrorStr(res));
910 dmFree(fname);
911 goto out;
912 }
913
914 if (S_ISREG(sbuf.st_mode))
915 node = dmResourceNew(lib, dh->d_name, sbuf.st_size);
916 }
917
918 if (node != NULL)
919 {
920 node->fops = &dfStdioFileOps;
921 dmResourceInsert(lib, node);
922 }
923 } while (dh != NULL);
924
925 out:
926 dmMutexUnlock(lib->mutex);
927
928 #ifdef __WIN32
929 #else
930 closedir(hdir);
931 #endif
932
933 return res;
934 }
935 #endif
936
937
938 /* Resources subsystem initialization and shutdown routines
939 */
940 int dmResourcesInit(DMResourceLib **plib, const char *filename, const char *path, const int flags, int (*classifier)(DMResource *))
941 {
942 DMResourceLib *lib;
943 BOOL initialized = FALSE;
944
945 // Allocate the resource library structure
946 if ((*plib = lib = dmMalloc0(sizeof(DMResourceLib))) == NULL)
947 return DMERR_MALLOC;
948
949 // Basic data
950 lib->mutex = dmCreateMutex();
951 lib->flags = flags;
952 lib->resPath = dm_strdup((path != NULL) ? path : DMRES_DATA_PATH);
953
954
955 #ifdef DM_USE_PACKFS
956 if (flags & DRF_USE_PACK)
957 {
958 int ret;
959 DMPackEntry *node;
960
961 lib->packFilename = dm_strdup((filename != NULL) ? filename : DMRES_DATA_PACK);
962
963 // Initialize PACK, open as read-only
964 ret = dmPackOpen(lib->packFilename, &lib->packFile, TRUE);
965 if (ret != DMERR_OK)
966 {
967 if ((flags & DRF_USE_STDIO) == 0)
968 {
969 dmError("Error opening PACK file '%s', #%d: %s\n",
970 lib->packFilename, ret, dmErrorStr(ret));
971
972 return DMERR_INIT_FAIL;
973 }
974 else
975 dmError("Failed to open PACK, falling back to STDIO, '%s' %d: %s\n",
976 lib->packFilename, ret, dmErrorStr(ret));
977 }
978 else
979 {
980 // Initialize resources from a PACK file
981 for (node = lib->packFile->entries; node != NULL; node = node->next)
982 {
983 DMResource *res = dmResourceNew(lib, node->filename, node->size);
984 if (res == NULL)
985 {
986 dmError("Could not allocate memory for resource node '%s' [0x%08x], %d.\n",
987 node->filename, node->flags, node->size);
988 return DMERR_INIT_FAIL;
989 }
990
991 res->fops = &dfPackFileOps;
992 dmResourceInsert(lib, res);
993 }
994
995 initialized = TRUE;
996 }
997 }
998 #endif
999
1000 #ifdef DM_USE_STDIO
1001 if (!initialized && (flags & DRF_USE_STDIO))
1002 {
1003 // Initialize resources from a resource directory
1004 int ret = dmResourcesLoadDirectory(lib, lib->resPath);
1005 if (ret != DMERR_OK)
1006 return ret;
1007 initialized = TRUE;
1008 }
1009 #endif
1010
1011 if (!initialized)
1012 return DMERR_INIT_FAIL;
1013
1014 // Okay, classify resources
1015 if (lib->resources != NULL && classifier != NULL)
1016 {
1017 DMResource *node;
1018 for (node = lib->resources; node != NULL; node = node->next)
1019 {
1020 int ret = classifier(node);
1021 if (ret != DMERR_OK)
1022 return ret;
1023 }
1024 }
1025
1026 // Initialization complete
1027 return DMERR_OK;
1028 }
1029
1030
1031 int dmResourcesClose(DMResourceLib *lib)
1032 {
1033 DMResource *node;
1034
1035 if (lib == NULL)
1036 return DMERR_NULLPTR;
1037
1038 dmMutexLock(lib->mutex);
1039
1040 // Shutdown possible subsystems
1041 #ifdef DM_USE_PACKFS
1042 if (lib->flags & DRF_USE_PACK)
1043 {
1044 int res = dmPackClose(lib->packFile);
1045 if (res != DMERR_OK)
1046 {
1047 dmError("Error closing PACK, #%i: %s\n",
1048 res, dmErrorStr(res));
1049 }
1050
1051 dmFree(lib->packFilename);
1052 }
1053 #endif
1054
1055 // Free resource entries
1056 node = lib->resources;
1057 while (node != NULL)
1058 {
1059 DMResource *next = node->next;
1060 dmResourceFree(node);
1061 node = next;
1062 }
1063
1064 // Etc.
1065 dmFree(lib->resPath);
1066 dmMutexUnlock(lib->mutex);
1067 dmDestroyMutex(lib->mutex);
1068 return DMERR_OK;
1069 }
1070
1071
1072 int dmResourcesPreload(DMResourceLib *lib, BOOL start, int *loaded, int *total)
1073 {
1074 int ret = DMERR_OK;
1075
1076 dmMutexLock(lib->mutex);
1077
1078 // Initialize preloading
1079 if (lib->preload == NULL || start)
1080 {
1081 DMResource *node;
1082
1083 lib->preload = lib->resources;
1084 *loaded = 0;
1085 *total = 0;
1086
1087 // Calculate total number of resources to be preloaded
1088 if (lib->flags & (DRF_PRELOAD_RAW | DRF_PRELOAD_RES))
1089 {
1090 for (node = lib->resources; node != NULL; node = node->next)
1091 (*total)++;
1092 }
1093 }
1094 else
1095 if (lib->preload != NULL)
1096 {
1097 // Attempt to preload the resource
1098 if ((ret = dmResourcePreload(lib->preload)) != DMERR_OK)
1099 {
1100 dmError("Error preloading '%s', %d: %s\n",
1101 lib->preload->filename, ret, dmErrorStr(ret));
1102 goto error;
1103 }
1104
1105 (*loaded)++;
1106 lib->preload = lib->preload->next;
1107 }
1108
1109 dmMutexUnlock(lib->mutex);
1110 return (lib->preload == NULL) ? DMERR_OK : DMERR_PROGRESS;
1111
1112 error:
1113 dmMutexUnlock(lib->mutex);
1114 return ret;
1115 }
1116
1117
1118 void dmResourcePrune(DMResourceLib *lib, const int agems, int const flags)
1119 {
1120 DMResource *node;
1121 const int stamp = time(NULL);
1122 dmMutexLock(lib->mutex);
1123
1124 for (node = lib->resources; node != NULL; node = node->next)
1125 {
1126 // Check if node has refcount of 0 and is
1127 // not marked as persistent resource
1128 if (node->refcount == 0 &&
1129 (node->flags & DMF_PERSIST) == 0 &&
1130 (node->flags & (DMF_LOADED_RES | DMF_LOADED_RAW)))
1131 {
1132 if (((flags & DMPRUNE_ATIME) && stamp - node->atime >= agems) ||
1133 ((flags & DMPRUNE_MTIME) && stamp - node->mtime >= agems))
1134 {
1135 dmResourceFreeResData(node);
1136 dmResourceFreeRawData(node);
1137 }
1138 }
1139 }
1140
1141 dmMutexUnlock(lib->mutex);
1142 }
1143
1144
1145 /* Helper resource access routines
1146 */
1147 int dmf_read_str(DMResource *f, void *s, size_t l)
1148 {
1149 return dmfread(s, 1, l, f) == l;
1150 }
1151
1152 BOOL dmf_read_byte(DMResource *f, Uint8 *val)
1153 {
1154 int tmp = dmfgetc(f);
1155 *val = tmp;
1156 return tmp != EOF;
1157 }
1158
1159 #define DM_DEFINE_FUNC(xname, xtype, xmacro) \
1160 BOOL dmf_read_ ## xname (DMResource *f, xtype *v) { \
1161 xtype result; \
1162 if (dmfread(&result, sizeof( xtype ), 1, f) != 1) \
1163 return FALSE; \
1164 *v = DM_ ## xmacro ## _TO_NATIVE (result); \
1165 return TRUE; \
1166 }
1167
1168 DM_DEFINE_FUNC(le16, Uint16, LE16)
1169 DM_DEFINE_FUNC(le32, Uint32, LE32)
1170
1171 DM_DEFINE_FUNC(be16, Uint16, BE16)
1172 DM_DEFINE_FUNC(be32, Uint32, BE32)
1173
1174 #ifdef DM_HAVE_64BIT
1175 DM_DEFINE_FUNC(le64, Uint64, LE64)
1176 DM_DEFINE_FUNC(be64, Uint64, BE64)
1177 #endif