diff options
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 95 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.h | 17 |
2 files changed, 104 insertions, 8 deletions
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index df12a4f4321..b04fa5d433e 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -1118,6 +1118,30 @@ static int *read_file_thumbnail(FileData *fd) /** \name File Data API * \{ */ +/* Regular file reading. */ + +static int fd_read_data_from_file(FileData *filedata, void *buffer, uint size) +{ + int readsize = read(filedata->filedes, buffer, size); + + if (readsize < 0) { + readsize = EOF; + } + else { + filedata->file_offset += readsize; + } + + return (readsize); +} + +static off_t fd_seek_data_from_file(FileData *filedata, off_t offset, int whence) +{ + filedata->file_offset = lseek(filedata->filedes, offset, whence); + return filedata->file_offset; +} + +/* GZip file reading. */ + static int fd_read_gzip_from_file(FileData *filedata, void *buffer, uint size) { int readsize = gzread(filedata->gzfiledes, buffer, size); @@ -1138,6 +1162,8 @@ static off_t fd_seek_gzip_from_file(FileData *filedata, off_t offset, int whence return filedata->file_offset; } +/* Memory reading. */ + static int fd_read_from_memory(FileData *filedata, void *buffer, uint size) { /* don't read more bytes then there are available in the buffer */ @@ -1149,6 +1175,8 @@ static int fd_read_from_memory(FileData *filedata, void *buffer, uint size) return (readsize); } +/* MemFile reading. */ + static int fd_read_from_memfile(FileData *filedata, void *buffer, uint size) { static size_t seek = SIZE_MAX; /* the current position */ @@ -1214,6 +1242,7 @@ static FileData *filedata_new(void) { FileData *fd = MEM_callocN(sizeof(FileData), "FileData"); + fd->filedes = -1; fd->gzfiledes = NULL; fd->memsdna = DNA_sdna_current_get(); @@ -1250,18 +1279,72 @@ static FileData *blo_decode_and_check(FileData *fd, ReportList *reports) static FileData *blo_filedata_from_file_open(const char *filepath, ReportList *reports) { + FileDataReadFn *read_fn = NULL; + FileDataSeekFn *seek_fn = NULL; /* Optional. */ + + int file = -1; + gzFile gzfile = (gzFile)Z_NULL; + + char header[7]; + + /* Regular file. */ errno = 0; - gzFile gzfile = BLI_gzopen(filepath, "rb"); - if (gzfile == (gzFile)Z_NULL) { + file = BLI_open(filepath, O_BINARY | O_RDONLY, 0); + if (file == -1) { BKE_reportf(reports, RPT_WARNING, "Unable to open '%s': %s", filepath, errno ? strerror(errno) : TIP_("unknown error reading file")); return NULL; } + else if (read(file, header, sizeof(header)) != sizeof(header)) { + BKE_reportf(reports, RPT_WARNING, "Unable to read '%s': %s", + filepath, errno ? strerror(errno) : TIP_("insufficient content")); + close(file); + return NULL; + } + else { + lseek(file, 0, SEEK_SET); + } + + /* Regular file. */ + if (memcmp(header, "BLENDER", sizeof(header)) == 0) { + read_fn = fd_read_data_from_file; + seek_fn = fd_seek_data_from_file; + } + else { + close(file); + file = -1; + } + + /* Gzip file. */ + errno = 0; + if ((read_fn == NULL) && + /* Check header magic. */ + (header[0] == 0x1f && header[1] == 0x8b)) + { + gzfile = BLI_gzopen(filepath, "rb"); + if (gzfile == (gzFile)Z_NULL) { + BKE_reportf(reports, RPT_WARNING, "Unable to open '%s': %s", + filepath, errno ? strerror(errno) : TIP_("unknown error reading file")); + return NULL; + } + else { + read_fn = fd_read_gzip_from_file; + seek_fn = fd_seek_gzip_from_file; + } + } + + if (read_fn == NULL) { + BKE_reportf(reports, RPT_WARNING, "Unrecognized file format '%s'", filepath); + return NULL; + } FileData *fd = filedata_new(); + + fd->filedes = file; fd->gzfiledes = gzfile; - fd->read = fd_read_gzip_from_file; - fd->seek = fd_seek_gzip_from_file; + + fd->read = read_fn; + fd->seek = seek_fn; return fd; } @@ -1387,6 +1470,10 @@ FileData *blo_filedata_from_memfile(MemFile *memfile, ReportList *reports) void blo_filedata_free(FileData *fd) { if (fd) { + if (fd->filedes != -1) { + close(fd->filedes); + } + if (fd->gzfiledes != NULL) { gzclose(fd->gzfiledes); } diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index 4fe65934107..49ae2849f4f 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -48,6 +48,11 @@ enum eFileDataFlag { FD_FLAGS_NOT_MY_LIBMAP = 1 << 5, }; + + +typedef int (FileDataReadFn)(struct FileData *filedata, void *buffer, unsigned int size); +typedef off_t (FileDataSeekFn)(struct FileData *filedata, off_t offset, int whence); + typedef struct FileData { /** Linked list of BHeadN's. */ ListBase listbase; @@ -55,8 +60,12 @@ typedef struct FileData { bool is_eof; int buffersize; off_t file_offset; - int (*read)(struct FileData *filedata, void *buffer, unsigned int size); - off_t (*seek)(struct FileData *filedata, off_t offset, int whence); + + FileDataReadFn *read; + FileDataSeekFn *seek; + + /** Regular file reading. */ + int filedes; /** Variables needed for reading from memory / stream. */ const char *buffer; @@ -65,12 +74,12 @@ typedef struct FileData { /** Variables needed for reading from file. */ gzFile gzfiledes; + /** Gzip stream for memory decompression. */ + z_stream strm; /** Now only in use for library appending. */ char relabase[FILE_MAX]; - /** Gzip stream for memory decompression. */ - z_stream strm; /** General reading variables. */ struct SDNA *filesdna; |