2 * See Licensing and Copyright notice in naev.h
8 * @brief Stores data in funky format.
13 * 1.1.1) Magic Number (16 bytes)
14 * 1.1.2) Number of Files (uint32_t)
15 * 1.1.3) Files in format Name/Location
16 * 1.1.3.1) File Name (128 bytes max, ended in NUL)
17 * 1.1.3.2) File Location (uint32_t)
18 * 1.2) File data in format Size/Data
19 * 1.2.1) File Size (uint32_t)
20 * 1.2,2) File Data (char*)
21 * 1.2.3) File MD5 (16 byte char*)
27 * 2.1) Write Magic Number and Number of Files (1.1 and 1.2 above)
28 * 2,2) Write the Index
37 #include <stdio.h> /* printf() */
38 #include <fcntl.h> /* creat() and friends */
39 #include <stdint.h> /* uint32_t */
41 #include <sys/types.h> /* ssize_t */
42 #include <sys/stat.h> /* S_IRUSR */
44 #include <unistd.h> /* WRITE() */
45 #include <errno.h> /* error numbers */
46 #include <string.h> /* strlen() and friends */
47 #include <stdlib.h> /* malloc */
49 #include <arpa/inet.h> /* ntohl */
50 #endif /* HAS_POSIX */
52 #include <winsock2.h> /* ntohl */
53 #endif /* HAS_WIN32 */
62 #else /* HAS_BIGENDIAN */
63 #define htonll(x) ((((uint64_t)htonl((uint32_t)x))<<32) + htonl((uint32_t)(x>>32)))
64 #define ntohll(x) ((((uint64_t)ntohl((uint32_t)x))<<32) + ntohl((uint32_t)(x>>32)))
65 #endif /* HAS_BIGENDIAN */
69 * @brief Abstracts around packfiles.
73 int fd
; /**< file descriptor */
74 #else /* not HAS_FD */
75 FILE* fp
; /**< For non-posix. */
77 uint32_t pos
; /**< cursor position */
78 uint32_t start
; /**< File start. */
79 uint32_t end
; /**< File end. */
81 uint32_t flags
; /**< Special control flags. */
86 * @brief Allows much faster creation of packfiles.
90 int fd
; /**< file descriptor */
91 #else /* not HAS_FD */
92 FILE *fp
; /**< For non-posix. */
95 char *name
; /**< To open the file again. */
96 char **index
; /**< Cached index for faster lookups. */
97 uint32_t *start
; /**< Cached index starts. */
98 uint32_t nindex
; /**< Number of index entries. */
105 #define READ(f,b,n) if (read((f)->fd,(b),(n))!=(n)) { \
106 WARN("Fewer bytes read than expected"); \
107 return NULL; } /**< Helper define to check for errors. */
108 #else /* not HAS_FD */
109 #define READ(f,b,n) if (fread((b),1,(n),(f)->fp)!=(n)) { \
110 WARN("Fewer bytes read than expected"); \
111 return NULL; } /**< Helper define to check for errors. */
114 #undef DEBUG /* mucho spamo */
115 #define DEBUG(str, args...) do {;} while(0) /**< Hack to disable debugging. */
118 #define BLOCKSIZE 128*1024 /**< The read/write block size. */
121 #define PATH_MAX 256 /**< maximum file name length. */
126 #define PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH /**< default permissions. */
130 static const uint64_t magic
= 0x4e41455644415441ULL
; /**< File magic number: NAEVDATA */
136 #define PACKFILE_FROMCACHE (1<<0) /**< Packfile comes from a packcache. */
142 static off_t
getfilesize( const char* filename
);
144 #if SDL_VERSION_ATLEAST(1,3,0)
145 static long packrw_seek( SDL_RWops
*rw
, long offset
, int whence
);
146 static size_t packrw_read( SDL_RWops
*rw
, void *ptr
, size_t size
, size_t maxnum
);
147 static size_t packrw_write( SDL_RWops
*rw
, const void *ptr
, size_t size
, size_t num
);
148 #else /* SDL_VERSION_ATLEAST(1,3,0) */
149 static int packrw_seek( SDL_RWops
*rw
, int offset
, int whence
);
150 static int packrw_read( SDL_RWops
*rw
, void *ptr
, int size
, int maxnum
);
151 static int packrw_write( SDL_RWops
*rw
, const void *ptr
, int size
, int num
);
152 #endif /* SDL_VERSION_ATLEAST(1,3,0) */
153 static int packrw_close( SDL_RWops
*rw
);
157 * @brief Opens a Packfile as a cache.
159 * @param packfile Name of the packfile to cache.
160 * @return NULL if an error occured or the Packcache.
162 Packcache_t
* pack_openCache( const char* packfile
)
173 cache
= calloc(1, sizeof(Packcache_t
));
175 WARN("Out of Memory.");
182 cache
->name
= strdup(packfile
);
184 cache
->fd
= open( packfile
, O_RDONLY
);
185 if (cache
->fd
== -1) {
186 #else /* not HAS_FD */
187 cache
->fp
= fopen( packfile
, "rb" );
188 if (cache
->fp
== NULL
) {
190 WARN("Erroring opening %s: %s", packfile
, strerror(errno
));
195 * Check for validity.
197 READ( cache
, buf
, sizeof(magic
));
198 end64
= ntohll(magic
);
199 if (memcmp(buf
, &end64
, sizeof(magic
))) {
200 WARN("File %s is not a valid packfile", packfile
);
205 * Get number of files and allocate memory.
207 READ( cache
, &cache
->nindex
, 4 );
208 cache
->nindex
= htonl( cache
->nindex
);
209 cache
->index
= calloc( cache
->nindex
, sizeof(char*) );
210 cache
->start
= calloc( cache
->nindex
, sizeof(uint32_t) );
215 for (i
=0; i
<cache
->nindex
; i
++) { /* start to search files */
217 READ( cache
, &buf
[j
], 1 ); /* get the name */
218 while ( buf
[j
++] != '\0' )
219 READ( cache
, &buf
[j
], 1 );
221 cache
->index
[i
] = strdup(buf
);
222 READ( cache
, &cache
->start
[i
], 4 );
223 cache
->start
[i
] = htonl( cache
->start
[i
] );
224 DEBUG("'%s' found at %d", cache
->index
[i
], cache
->start
[i
]);
228 * Return the built cache.
235 * @brief Closes a Packcache.
237 * @param cache Packcache to close.
239 void pack_closeCache( Packcache_t
* cache
)
248 #else /* not HAS_FD */
256 if (cache
->nindex
> 0) {
257 for (i
=0; i
<cache
->nindex
; i
++)
258 free(cache
->index
[i
]);
267 * @brief Opens a Packfile from a Packcache.
269 * @param cache Packcache to create Packfile from.
270 * @param filename Name of the file to open in the Cache.
271 * @return A packfile for filename from cache.
273 Packfile_t
* pack_openFromCache( Packcache_t
* cache
, const char* filename
)
278 file
= calloc( 1, sizeof(Packfile_t
) );
280 for (i
=0; i
<cache
->nindex
; i
++) {
281 if (strcmp(cache
->index
[i
], filename
)==0) {
284 file
->fd
= open( cache
->name
, O_RDONLY
);
285 #else /* not HAS_FD */
286 file
->fp
= fopen( cache
->name
, "rb" );
289 /* Copy information. */
290 file
->flags
|= PACKFILE_FROMCACHE
;
291 file
->start
= cache
->start
[i
];
294 if (file
->start
) { /* go to the beginning of the file */
296 if ((uint32_t)lseek( file
->fd
, file
->start
, SEEK_SET
) != file
->start
) {
297 #else /* not HAS_FD */
298 if (fseek( file
->fp
, file
->start
, SEEK_SET
)) {
300 WARN("Failure to seek to file start: %s", strerror(errno
));
303 READ( file
, &file
->end
, 4 );
304 file
->end
= htonl( file
->end
);
306 file
->pos
= file
->start
;
307 file
->end
+= file
->start
;
308 DEBUG("Opened '%s' from cache from %u to %u (%u long)", filename
,
309 file
->start
, file
->end
, file
->end
- file
->start
);
317 WARN("File '%s' not found in packfile.", filename
);
323 * @brief Gets the file's size.
325 * @param filename File to get the size of.
326 * @return The size of the file.
328 static off_t
getfilesize( const char* filename
)
333 if (!stat( filename
, &file
))
336 WARN( "Unable to get filesize of %s", filename
);
338 #else /* not HAS_FD */
340 FILE* fp
= fopen( filename
, "rb" );
341 if (fp
== NULL
) return 0;
343 fseek( fp
, 0, SEEK_END
);
354 * @brief Checks to see if a file is a packfile.
356 * @param filename Name of the file to check.
357 * @return 0 if it is a packfile, 1 if it isn't and -1 on error.
359 int pack_check( const char* filename
)
365 buf
= malloc(sizeof(magic
));
367 /* Must convert magic. */
368 end64
= ntohll(magic
);
371 int fd
= open( filename
, O_RDONLY
);
373 WARN("Erroring opening %s: %s", filename
, strerror(errno
));
377 if (read( fd
, buf
, sizeof(magic
) ) != sizeof(magic
)) {
378 WARN("Error reading magic number: %s", strerror(errno
));
384 #else /* not HAS_FD */
385 FILE* file
= fopen( filename
, "rb" );
387 WARN("Erroring opening '%s': %s", filename
, strerror(errno
));
391 if (fread( buf
, 1, sizeof(magic
), file
) != sizeof(magic
)) {
392 WARN("Error reading magic number: %s", strerror(errno
));
401 ret
= (memcmp(buf
,&end64
,sizeof(magic
))==0) ? 0 : 1 ;
410 #define WRITE(b,n) if (write(outfd,b,n)==-1) { \
411 WARN("Error writing to file: %s", strerror(errno)); \
412 free(buf); return -1; } /**< Macro to help check for errors. */
413 #else /* not HAS_FD */
414 #define WRITE(b,n) if (fwrite(b,1,n,outf)==0) { \
415 WARN("Error writing to file: %s", strerror(errno)); \
416 free(buf); return -1; } /**< Macro to help check for errors. */
419 * @brief Packages files into a packfile.
421 * @param outfile Name of the file to output to.
422 * @param infiles Array of filenames to package.
423 * @param nfiles Number of filenames in infiles.
424 * @return 0 on success.
426 int pack_files( const char* outfile
, const char** infiles
, const uint32_t nfiles
)
437 uint32_t indexsize
, pointer
;
439 const uint8_t b
= '\0';
444 for (namesize
=0,i
=0; i
< nfiles
; i
++) { /* make sure files exist before writing */
446 if (stat(infiles
[i
], &file
)) {
447 #else /* not HAS_FD */
448 if (getfilesize(infiles
[i
]) == 0) {
450 WARN("File %s does not exist", infiles
[i
]);
453 if (strlen(infiles
[i
]) > PATH_MAX
) {
454 WARN("Filename '%s' is too long, should be only %d characters",
455 infiles
[i
], PATH_MAX
);
458 namesize
+= strlen(infiles
[i
]);
460 indexsize
= (sizeof(magic
) + 4 + /* magic number and number of files */
461 namesize
+ /* total length of file names */
462 (1+4)*nfiles
); /* file size and extra end of string char '\0' */
463 DEBUG("Index size is %d", indexsize
);
465 /* creates the output file */
467 outfd
= creat( outfile
, PERMS
);
469 #else /* not HAS_FD */
470 outf
= fopen( outfile
, "wb" );
473 WARN("Unable to open %s for writing", outfile
);
480 buf
= malloc(BLOCKSIZE
);
482 end64
= htonll(magic
);
483 WRITE( &end64
, sizeof(magic
));
484 DEBUG("Wrote magic number");
485 /* number of files */
486 end32
= htonl(nfiles
);
487 WRITE( &end32
, sizeof(nfiles
));
488 DEBUG("Wrote number of files: %d", nfiles
);
489 /* create file dependent index part */
491 for (i
=0; i
<nfiles
; i
++) {
492 WRITE( infiles
[i
], strlen(infiles
[i
]) );
493 DEBUG("File '%s' at %d", infiles
[i
], pointer
);
495 end32
= htonl(pointer
);
497 pointer
+= 4 + getfilesize( infiles
[i
] ) + 16; /* set pointer to be next file pos */
503 md5_byte_t
*md5val
= malloc(16);
504 for (i
=0; i
<nfiles
; i
++) {
505 bytes
= (uint32_t)getfilesize( infiles
[i
] );
506 end32
= htonl(bytes
);
507 WRITE( &end32
, 4 ); /* filesize */
508 DEBUG("About to write file '%s' of %d bytes", infiles
[i
], bytes
);
511 infd
= open( infiles
[i
], O_RDONLY
);
512 while ((bytes
= read( infd
, buf
, BLOCKSIZE
))) {
513 #else /* not HAS_FD */
514 inf
= fopen( infiles
[i
], "rb" );
515 while ((bytes
= fread( buf
, 1, BLOCKSIZE
, inf
))) {
517 WRITE( buf
, bytes
); /* data */
518 md5_append( &md5
, buf
, bytes
);
520 md5_finish(&md5
, md5val
);
524 #else /* not HAS_FD */
527 DEBUG("Wrote file '%s'", infiles
[i
]);
533 #else /* not HAS_FD */
538 DEBUG("Packfile success\n\t%d files\n\t%d bytes", nfiles
, (int)getfilesize(outfile
));
545 * @brief Opens a file in the packfile for reading.
547 * @param packfile Path to the real packfile.
548 * @param filename Name of the file within th. packfile.
549 * @return The newly created packfile or NULL on error.
551 Packfile_t
* pack_open( const char* packfile
, const char* filename
)
559 /* Allocate memory. */
560 file
= malloc(sizeof(Packfile_t
));
561 memset( file
, 0, sizeof(Packfile_t
) );
564 file
->fd
= open( packfile
, O_RDONLY
);
565 if (file
->fd
== -1) {
566 #else /* not HAS_FD */
567 file
->fp
= fopen( packfile
, "rb" );
568 if (file
->fp
== NULL
) {
570 WARN("Erroring opening %s: %s", filename
, strerror(errno
));
574 READ( file
, buf
, sizeof(magic
)); /* make sure it's a packfile */
575 end64
= ntohll(magic
);
576 if (memcmp(buf
, &end64
, sizeof(magic
))) {
577 WARN("File %s is not a valid packfile", filename
);
581 READ( file
, &nfiles
, 4 );
582 nfiles
= htonl(nfiles
);
583 for (i
=0; i
<nfiles
; i
++) { /* start to search files */
585 READ( file
, &buf
[j
], 1 ); /* get the name */
586 while ( buf
[j
++] != '\0' )
587 READ( file
, &buf
[j
], 1 );
589 if (strcmp(filename
, buf
)==0) { /* found file */
590 READ( file
, &file
->start
, 4 );
591 file
->start
= htonl( file
->start
);
592 DEBUG("'%s' found at %d", filename
, file
->start
);
596 lseek( file
->fd
, 4, SEEK_CUR
); /* ignore the file location */
597 #else /* not HAS_FD */
598 fseek( file
->fp
, 4, SEEK_CUR
);
602 if (file
->start
) { /* go to the beginning of the file */
604 if ((uint32_t)lseek( file
->fd
, file
->start
, SEEK_SET
) != file
->start
) {
605 #else /* not HAS_FD */
606 if (fseek( file
->fp
, file
->start
, SEEK_SET
)) {
608 WARN("Failure to seek to file start: %s", strerror(errno
));
611 READ( file
, &file
->end
, 4 );
612 file
->end
= htonl( file
->end
);
613 DEBUG("\t%d bytes", file
->end
);
615 file
->pos
= file
->start
;
616 file
->end
+= file
->start
;
619 WARN("File '%s' not found in packfile '%s'", filename
, packfile
);
628 * @brief Reads data from a packfile.
630 * Behaves like FD read.
632 * @param file Opened packfile to read data from.
633 * @param buf Allocated buffer to read into.
634 * @param count Bytes to read.
635 * @return Bytes read or -1 on error.
637 ssize_t
pack_read( Packfile_t
* file
, void* buf
, size_t count
)
641 if ((file
->pos
+ count
) > file
->end
)
642 count
= MAX(file
->end
- file
->pos
, 0); /* can't go past end */
647 if ((bytes
= read( file
->fd
, buf
, count
)) == -1) {
648 #else /* not HAS_FD */
649 if ((bytes
= fread( buf
, 1, count
, file
->fp
)) == -1) {
651 WARN("Error while reading file: %s", strerror(errno
));
656 DEBUG("Read %d bytes from packfile: offset = %u", bytes
, file
->pos
);
657 DEBUG("start: %u, pos: %u, end: %u -> %d", file
->start
, file
->pos
, file
->end
,
665 * @brief Seeks within a file inside a packfile.
667 * Behaves like lseek/fseek.
669 * @param file File to seek.
670 * @param offset Position to seek to.
671 * @param whence Either SEEK_SET, SEEK_CUR or SEEK_END.
672 * @return The position moved to.
674 off_t
pack_seek( Packfile_t
* file
, off_t offset
, int whence
)
676 uint32_t base
, target
, ret
;
678 DEBUG("attempting to seek offset: %ld, whence: %d", offset
, whence
);
680 /* Find where offset is relative to. */
695 WARN("Whence is not one of SEEK_SET, SEEK_CUR or SEEK_END");
699 /* Get the target. */
700 target
= base
+ offset
;
703 if (target
< file
->start
)
707 ret
= lseek( file
->fd
, target
, SEEK_SET
);
710 #else /* not HAS_FD */
711 ret
= fseek( file
->fp
, target
, SEEK_SET
);
714 ret
= target
; /* fseek returns 0. */
717 /* Set the position in the file. */
719 DEBUG("start: %u, pos: %u, end: %u -> %u", file
->start
, file
->pos
, file
->end
,
720 file
->pos
- file
->start
);
722 return file
->pos
- file
->start
;
727 * @brief Gets the current position in the file.
729 * @param file Packfile to get the position from.
730 * @return The current position in the file.
732 long pack_tell( Packfile_t
* file
)
734 return file
->pos
- file
->start
;
739 * @brief Reads a file from a Packfile.
741 static void* pack_readfilePack( Packfile_t
*file
,
742 const char* filename
, uint32_t *filesize
)
748 /* read the entire file */
749 size
= file
->end
- file
->start
;
750 buf
= malloc( size
+ 1 );
752 WARN("Unable to allocate %d bytes of memory!", size
+1);
756 if ((bytes
= pack_read( file
, buf
, size
)) != size
) {
757 WARN("Reading '%s' from packfile. Expected %d bytes got %d bytes",
758 filename
, size
, bytes
);
763 DEBUG("Read %d bytes from '%s'", bytes
, filename
);
765 str
[size
] = '\0'; /* append size '\0' for it to validate as a string */
769 md5_byte_t
*md5val
= malloc(16);
770 md5_byte_t
*md5fd
= malloc(16);
772 md5_append( &md5
, buf
, bytes
);
773 md5_finish(&md5
, md5val
);
775 if ((bytes
= read( file
->fd
, md5fd
, 16 )) == -1)
776 #else /* not HAS_FD */
777 if ((bytes
= fread( md5fd
, 1, 16, file
->fp
)) == -1)
779 WARN("Failure to read MD5 (Expected %d bytes got %d bytes), continuing anyways...", 16, bytes
);
780 else if (memcmp( md5val
, md5fd
, 16 ))
781 WARN("MD5 gives different value, possible memory corruption, continuing...");
787 if (pack_close( file
) == -1) {
788 WARN("Closing packfile");
792 DEBUG("Closed '%s' in packfile", filename
);
801 * @brief Reads an entire file into memory.
803 * @param packfile Name of the packfile to read frome.
804 * @param filename Name of the packed file to read.
805 * @param filesize Is set to the size of the file.
806 * @return A pointer to the data in the file or NULL if an error occurred.
808 void* pack_readfile( const char* packfile
, const char* filename
, uint32_t *filesize
)
812 /* Initialize size to 0. */
816 /* Open the packfile. */
817 file
= pack_open( packfile
, filename
);
819 WARN("Opening packfile '%s'.", packfile
);
822 DEBUG("Opened file '%s' from '%s'", filename
, packfile
);
824 return pack_readfilePack( file
, filename
, filesize
);
829 * @brief char** pack_listfiles( const char* packfile, uint32_t* nfiles )
831 * @brief Gets what files are in the packfile.
833 * Each name must be freed individually afterwarsd and the array of names too.
835 * @param packfile Packfile to query it's internal files.
836 * @param nfiles Stores the amount of files in packfile.
837 * @return An array of filenames in packfile.
839 char** pack_listfiles( const char* packfile
, uint32_t* nfiles
)
845 char* buf
= malloc(sizeof(magic
));
851 file
.fd
= open( packfile
, O_RDONLY
);
853 #else /* not HAS_FD */
854 file
.fp
= fopen( packfile
, "rb" );
855 if (file
.fp
== NULL
) {
857 WARN("Erroring opening %s: %s", packfile
, strerror(errno
));
861 READ( &file
, buf
, sizeof(magic
)); /* make sure it's a packfile */
862 end64
= ntohll( magic
);
863 if (memcmp(buf
, &end64
, sizeof(magic
))) {
864 WARN("File %s is not a valid packfile", packfile
);
868 READ( &file
, nfiles
, 4 );
869 *nfiles
= htonl( *nfiles
);
870 filenames
= malloc(((*nfiles
)+1)*sizeof(char*));
871 for (i
=0; i
<*nfiles
; i
++) { /* start to search files */
873 filenames
[i
] = malloc(PATH_MAX
*sizeof(char));
874 READ( &file
, &filenames
[i
][j
], 1 ); /* get the name */
875 while ( filenames
[i
][j
++] != '\0' )
876 READ( &file
, &filenames
[i
][j
], 1 );
877 READ( &file
, buf
, 4 ); /* skip the location */
882 #else /* not HAS_FD */
891 * @brief Reads an entire file from the cache.
893 void* pack_readfileCached( Packcache_t
* cache
, const char* filename
, uint32_t *filesize
)
897 file
= pack_openFromCache( cache
, filename
);
899 WARN("Unable to create packfile from packcache.");
902 return pack_readfilePack( file
, filename
, filesize
);
907 * @brief Gets the list of files en a Packcache.
909 * @param cache Cache to get list of files from.
910 * @param nfiles Number of files in the list.
911 * @return A read only list of files from the pack cache.
913 const char** pack_listfilesCached( Packcache_t
* cache
, uint32_t* nfiles
)
915 *nfiles
= cache
->nindex
;
916 return (const char**) cache
->index
;
921 * @brief Closes a packfile.
923 * @param file Packfile to close.
924 * @return 0 on success.
926 int pack_close( Packfile_t
* file
)
932 i
= close( file
->fd
);
933 #else /* not HAS_FD */
934 i
= fclose( file
->fp
);
940 DEBUG("Closing packfile.");
942 return (i
) ? -1 : 0 ;
946 #if SDL_VERSION_ATLEAST(1,3,0)
947 static long packrw_seek( SDL_RWops
*rw
, long offset
, int whence
)
948 #else /* SDL_VERSION_ATLEAST(1,3,0) */
949 static int packrw_seek( SDL_RWops
*rw
, int offset
, int whence
)
950 #endif /* SDL_VERSION_ATLEAST(1,3,0) */
953 Packfile_t
*packfile
;
954 packfile
= rw
->hidden
.unknown
.data1
;
956 if (whence
== RW_SEEK_SET
)
958 else if (whence
== RW_SEEK_CUR
)
960 else if (whence
== RW_SEEK_END
)
965 return pack_seek( packfile
, offset
, wh
);
967 #if SDL_VERSION_ATLEAST(1,3,0)
968 static size_t packrw_read( SDL_RWops
*rw
, void *ptr
, size_t size
, size_t maxnum
)
969 #else /* SDL_VERSION_ATLEAST(1,3,0) */
970 static int packrw_read( SDL_RWops
*rw
, void *ptr
, int size
, int maxnum
)
971 #endif /* SDL_VERSION_ATLEAST(1,3,0) */
974 Packfile_t
*packfile
;
975 packfile
= rw
->hidden
.unknown
.data1
;
978 ret
= pack_read( packfile
, ptr
, size
*maxnum
);
982 #if SDL_VERSION_ATLEAST(1,3,0)
983 static size_t packrw_write( SDL_RWops
*rw
, const void *ptr
, size_t size
, size_t num
)
984 #else /* SDL_VERSION_ATLEAST(1,3,0) */
985 static int packrw_write( SDL_RWops
*rw
, const void *ptr
, int size
, int num
)
986 #endif /* SDL_VERSION_ATLEAST(1,3,0) */
994 static int packrw_close( SDL_RWops
*rw
)
996 Packfile_t
*packfile
;
997 packfile
= rw
->hidden
.unknown
.data1
;
1002 return pack_close( packfile
);
1007 * @brief Creates a rwops from a packfile.
1009 * @param packfile Packfile to create rwops from.
1010 * @return rwops created from packfile.
1012 static SDL_RWops
*pack_rwopsRaw( Packfile_t
*packfile
)
1016 /* Create the rwops. */
1019 WARN("Unable to allocate SDL_RWops.");
1023 /* Set the functions. */
1024 rw
->seek
= packrw_seek
;
1025 rw
->read
= packrw_read
;
1026 rw
->write
= packrw_write
;
1027 rw
->close
= packrw_close
;
1029 /* Set the packfile as the hidden data. */
1030 rw
->hidden
.unknown
.data1
= packfile
;
1037 * @brief Creates an rwops for a file in a packfile.
1039 * @param packfile Packfile to get file from.
1040 * @param filename File within packfile to create rwops from.
1041 * @return SDL_RWops interacting with the file in the packfile.
1043 SDL_RWops
*pack_rwops( const char* packfile
, const char* filename
)
1047 /* Open the packfile. */
1048 pack
= pack_open( packfile
, filename
);
1052 /* Return the rwops. */
1053 return pack_rwopsRaw( pack
);
1058 * @brief Creates an rwops for a file in a packcache.
1060 * @param cache Packcache to get file from.
1061 * @param filename File within the cache to create rwops from.
1062 * @return SDL_RWops interacting with the file in the packcache.
1064 SDL_RWops
*pack_rwopsCached( Packcache_t
* cache
, const char* filename
)
1066 Packfile_t
*packfile
;
1068 /* Open the packfile. */
1069 packfile
= pack_openFromCache( cache
, filename
);
1070 if (packfile
== NULL
)
1073 /* Return the rwops. */
1074 return pack_rwopsRaw( packfile
);