readfile: use regular file access when not a gzip
authorCampbell Barton <ideasman42@gmail.com>
Sun, 24 Feb 2019 01:34:41 +0000 (12:34 +1100)
committerCampbell Barton <ideasman42@gmail.com>
Sun, 24 Feb 2019 01:41:37 +0000 (12:41 +1100)
Allows for different behavior w/ compressed files,
will also make it simpler to support other compression types,
see: T56162

source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/readfile.h

index df12a4f..b04fa5d 100644 (file)
@@ -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);
                }
index 4fe6593..49ae284 100644 (file)
@@ -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;