* Fix compiler warning. Struct QuicktimeCodecData had to be declared.
[blender-staging.git] / source / blender / readblenfile / intern / BLO_readblenfile.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  *
32  */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <fcntl.h>
38
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
42
43 #ifdef WIN32
44 #include <io.h>         // read, open
45 #else // ! WIN32
46 #include <unistd.h>             // read
47 #endif
48
49 #include "BLO_readStreamGlue.h"
50
51 #include "BLO_readfile.h"
52 #include "BLO_readblenfile.h"
53
54 #include "BKE_blender.h"
55
56 #define CACHESIZE 100000
57
58 char *headerMagic = "BLENDFI";
59
60 void BLO_setversionnumber(char array[4], int version)
61 {
62         memset(array, 0, sizeof(array));
63
64         array[1] = version / 100;
65         array[2] = version % 100;
66 }
67
68 void BLO_setcurrentversionnumber(char array[4])
69 {
70         BLO_setversionnumber(array, BLENDER_VERSION);
71 }
72
73 #ifndef O_BINARY
74 #define O_BINARY 0
75 #endif
76
77 struct BLO_readblenfileStruct {
78         struct readStreamGlueStruct *streamGlue;
79         int fileDes;
80         unsigned int cacheSize;
81         unsigned int inCache;
82         unsigned int leftToRead;
83         unsigned int Seek;
84
85         int (*read)(struct BLO_readblenfileStruct *readblenfileStruct, void *buffer, int size);
86
87         char *readCache;
88         char *fromBuffer;
89         int  fromBufferSize;
90         char crInBuffer;
91         char removeCR;
92 };
93
94 // declare static functions
95
96 static int readfromfilehandle(
97         struct BLO_readblenfileStruct *readblenfileStruct,
98         void *buffer,
99         int size);
100
101 static int readfrommemory(
102         struct BLO_readblenfileStruct *readblenfileStruct,
103         void *buffer,
104         int size);
105
106 static int fillcache(
107         struct BLO_readblenfileStruct *readblenfileStruct);
108
109 static unsigned int readfromcache(
110         struct BLO_readblenfileStruct *readblenfileStruct,
111         void * buffer,
112         unsigned int size);
113
114 static BlendFileData *readblenfilegeneric(
115         struct BLO_readblenfileStruct *readblenfileStruct, 
116         BlendReadError *error_r);
117
118 // implementation of static functions
119
120 static int readfromfilehandle(
121         struct BLO_readblenfileStruct *readblenfileStruct,
122         void *buffer,
123         int size)
124 {
125         int readsize = -1;
126
127         if (readblenfileStruct->fileDes != -1) {
128                 readsize = read(readblenfileStruct->fileDes, buffer, size);
129         }
130
131         return(readsize);
132 }
133
134 static int readfrommemory(
135         struct BLO_readblenfileStruct *readblenfileStruct,
136         void *buffer,
137         int size)
138 {
139         int readsize = -1;
140
141         if (readblenfileStruct->fromBuffer) {
142                 if (size > readblenfileStruct->fromBufferSize) {
143                         size = readblenfileStruct->fromBufferSize;
144                 }
145
146                 memcpy(buffer, readblenfileStruct->fromBuffer, size);
147                 readblenfileStruct->fromBufferSize -= size;
148                 readblenfileStruct->fromBuffer += size;
149
150                 readsize = size;
151         }
152
153         return(readsize);
154 }
155
156 static int fillcache(
157         struct BLO_readblenfileStruct *readblenfileStruct)
158 {
159         int readsize;
160         int toread;
161
162         // how many bytes can we read ?
163
164         toread = readblenfileStruct->leftToRead;
165
166         if (toread > readblenfileStruct->cacheSize) {
167                 toread = readblenfileStruct->cacheSize;
168         }
169
170         readsize = readblenfileStruct->read(readblenfileStruct, readblenfileStruct->readCache, toread);
171         if (readsize > 0) {
172                 if (readblenfileStruct->removeCR) {
173                         // do some stuff here
174                 }
175                 readblenfileStruct->inCache = readsize;
176                 readblenfileStruct->leftToRead -= readsize;
177         }
178
179         return (readsize);
180 }
181
182
183 static unsigned int readfromcache(
184         struct BLO_readblenfileStruct *readblenfileStruct,
185         void * buffer,
186         unsigned int size)
187 {
188         unsigned int readsize = 0;
189
190         if (readblenfileStruct->inCache - readblenfileStruct->Seek > size) {
191                 memcpy(buffer, readblenfileStruct->readCache + readblenfileStruct->Seek, size);
192                 readblenfileStruct->Seek += size;
193                 readsize = size;
194         } else {
195                 // handle me
196         }
197
198         return(readsize);
199 }
200
201 static BlendReadError brs_to_bre(int err)
202 {
203         int errFunction = BRS_GETFUNCTION(err);
204         int errGeneric =  BRS_GETGENERR(err);
205         int errSpecific = BRS_GETSPECERR(err);
206
207         if (errGeneric) {
208                 switch (errGeneric) {
209                 case BRS_MALLOC:
210                         return BRE_OUT_OF_MEMORY;
211                 case BRS_NULL:
212                         return BRE_INTERNAL_ERROR;
213                 case BRS_MAGIC:
214                         return BRE_NOT_A_BLEND;
215                 case BRS_CRCHEADER:
216                 case BRS_CRCDATA:
217                         return BRE_CORRUPT;
218                 case BRS_DATALEN:
219                         return BRE_INCOMPLETE;
220                 case BRS_STUB:
221                         return BRE_NOT_A_BLEND;
222                 }
223         } else if (errSpecific) {
224                 switch (errFunction) {
225                 case BRS_READSTREAMGLUE:
226                         switch (errSpecific) {
227                         case BRS_UNKNOWN:
228                                 return BRE_INTERNAL_ERROR;
229                         }
230                         break;
231                 case BRS_READSTREAMFILE:
232                         switch (errSpecific) {
233                         case BRS_NOTABLEND:
234                                 return BRE_NOT_A_BLEND;
235                         case BRS_READERROR:
236                                 return BRE_UNABLE_TO_READ;
237                         }
238                         break;
239                 case BRS_INFLATE:
240                         switch (errSpecific) {
241                         case BRS_INFLATEERROR:
242                                 return BRE_CORRUPT;
243                         }
244                         break;
245                 case BRS_DECRYPT:
246                         switch (errSpecific) {
247                         case BRS_RSANEWERROR:
248                                 return BRE_INTERNAL_ERROR;
249                         case BRS_DECRYPTERROR:
250                                 return BRE_INTERNAL_ERROR;
251                         case BRS_NOTOURPUBKEY:
252                                 return BRE_NOT_ALLOWED;
253                         }
254                         break;
255                 case BRS_VERIFY:
256                         switch (errSpecific) {
257                         case BRS_RSANEWERROR:
258                                 return BRE_INTERNAL_ERROR;
259                         case BRS_SIGFAILED:
260                                 return BRE_INTERNAL_ERROR;
261                         }
262                         break;
263                 }
264         }
265         
266         return BRE_INVALID;
267 }
268
269 static BlendFileData *readblenfilegeneric(
270         struct BLO_readblenfileStruct *readblenfileStruct, 
271         BlendReadError *error_r)
272 {
273         BlendFileData *bfd= NULL;
274         unsigned char reserved[BLO_RESERVEDSIZE];
275         uint8_t minversion[4];
276         uint8_t myversion[4];
277         uint8_t version[4];
278         uint8_t flags[4];
279         void *parms[2];
280         int filesize;
281         
282         parms[0]= &bfd;
283         parms[1]= error_r;
284
285         BLO_setcurrentversionnumber(myversion);
286
287         readblenfileStruct->cacheSize      = CACHESIZE;
288         readblenfileStruct->readCache      = malloc(readblenfileStruct->cacheSize);
289
290         if (fillcache(readblenfileStruct) <= 0) {
291                 *error_r = BRE_UNABLE_TO_READ;
292         } else if (readfromcache(readblenfileStruct, minversion, sizeof(minversion)) != sizeof(minversion)) {
293                 *error_r = BRE_UNABLE_TO_READ;
294         } else if (memcmp(minversion, myversion, sizeof(minversion)) > 0) {
295                 *error_r = BRE_TOO_NEW;
296         } else if (readfromcache(readblenfileStruct, version,  sizeof(version)) != sizeof(version)) {
297                 *error_r = BRE_UNABLE_TO_READ;
298         } else if (readfromcache(readblenfileStruct, flags,    sizeof(flags)) != sizeof(flags)) {
299                 *error_r = BRE_UNABLE_TO_READ;
300         } else if (readfromcache(readblenfileStruct, &filesize, sizeof(filesize)) != sizeof(filesize)) {
301                 *error_r = BRE_UNABLE_TO_READ;
302         } else if (readfromcache(readblenfileStruct, reserved, sizeof(reserved)) != sizeof(reserved)) {
303                 *error_r = BRE_UNABLE_TO_READ;
304         }  else {
305                 filesize = ntohl(filesize);
306
307                 // substract number of bytes we've
308                 // been handling outside readfromcache()
309                 filesize -= strlen(headerMagic);
310                 filesize--;
311
312                 if (filesize < readblenfileStruct->inCache) {
313                         // we've allready read more than we're supposed to
314                         readblenfileStruct->inCache   = filesize;
315                         readblenfileStruct->leftToRead = 0;                                                                     
316                 } else {
317                         // 
318                         readblenfileStruct->leftToRead = filesize - readblenfileStruct->inCache;
319                 }
320
321                 do {
322                         int err;
323
324                         *error_r = BRE_NONE;
325                         err = readStreamGlue(
326                                 parms,
327                                 &(readblenfileStruct->streamGlue),
328                                 readblenfileStruct->readCache + readblenfileStruct->Seek,
329                                 readblenfileStruct->inCache - readblenfileStruct->Seek);
330
331                         readblenfileStruct->inCache = 0;
332                         readblenfileStruct->Seek = 0;
333
334                         if (err) {
335                                 bfd = NULL;
336
337                                         /* If *error_r != BRE_NONE then it is
338                                          * blo_readstreamfile_end signaling an error
339                                          * in the loading code. Otherwise it is some
340                                          * other part of the streamglue system signalling
341                                          * and error so we convert the BRS error into
342                                          * a BRE error.
343                                          * 
344                                          * Does this have to be so convoluted? No.
345                                          */
346                                 if (*error_r == BRE_NONE) {
347                                         *error_r = brs_to_bre(err);
348                                 }
349                                 
350                                 break;
351                         }
352                 } while (fillcache(readblenfileStruct) > 0);
353         }
354
355         free(readblenfileStruct->readCache);
356         readblenfileStruct->readCache = 0;
357
358         return bfd;
359 }
360
361 // implementation of exported functions
362
363 BlendFileData *
364 BLO_readblenfilememory(
365         char *fromBuffer, 
366         int fromBufferSize, 
367         BlendReadError *error_r)
368 {
369         static char *functionality_check= "\0FUNCTIONALITY_CHECK += BLO_readblenfilememory\n";
370         int magiclen = strlen(headerMagic);
371         BlendFileData *bfd = NULL;
372
373         if (!fromBuffer) {
374                 *error_r = BRE_UNABLE_TO_OPEN;
375         } else if (fromBufferSize < magiclen) {
376                 *error_r = BRE_UNABLE_TO_READ;
377         } else if (strncmp(fromBuffer, headerMagic, magiclen) != 0) {
378                 *error_r = BRE_NOT_A_BLEND;
379         } else if (fromBufferSize < magiclen+1) {
380                 *error_r = BRE_UNABLE_TO_READ;
381         } else if (fromBuffer[magiclen] != '\r' && fromBuffer[magiclen] != '\n') {
382                 *error_r = BRE_NOT_A_BLEND;
383         } else {
384                 int crnl; 
385
386                 fromBuffer+= magiclen;
387                 fromBufferSize-= magiclen;
388                 crnl = (fromBuffer[0] == '\r');
389                 fromBuffer++;
390                 fromBufferSize--;
391                 
392                 if (crnl && fromBufferSize<1) {
393                         *error_r = BRE_UNABLE_TO_READ;
394                 } else {
395                         struct BLO_readblenfileStruct *readblenfileStruct = NULL;
396
397                                 /* skip carriage return if necessary */
398                         if (crnl) {
399                                 fromBuffer++;
400                                 fromBufferSize--;
401                         }
402
403                         // Allocate all the stuff we need
404                         readblenfileStruct = calloc(sizeof(struct BLO_readblenfileStruct), 1);
405                         readblenfileStruct->fileDes        = -1;
406                         readblenfileStruct->fromBuffer     = fromBuffer;
407                         readblenfileStruct->fromBufferSize = fromBufferSize;
408                         readblenfileStruct->read                   = readfrommemory;
409
410                         readblenfileStruct->removeCR   = crnl;
411                         // fake filesize for now until we've
412                         // actually read in the filesize from the header
413                         // make sure we don't read more bytes than there
414                         // are left to handle accoding to fromBufferSize
415                         readblenfileStruct->leftToRead = readblenfileStruct->fromBufferSize;
416
417                         bfd = readblenfilegeneric(readblenfileStruct, error_r);
418
419                         free(readblenfileStruct);
420                         readblenfileStruct = 0;
421                 }
422         }
423
424         return bfd;
425 }
426
427
428 BlendFileData *
429 BLO_readblenfilehandle(
430         int fd, 
431         BlendReadError *error_r)
432 {
433         static char *functionality_check= "\0FUNCTIONALITY_CHECK += BLO_readblenfilehandle\n";
434         int magiclen = strlen(headerMagic);
435         BlendFileData *bfd = NULL;
436         char tempbuffer[256];
437         
438         if (fd==-1) {
439                 *error_r = BRE_UNABLE_TO_OPEN;
440         } else if (read(fd, tempbuffer, magiclen) != magiclen) {
441                 *error_r = BRE_UNABLE_TO_READ;
442         } else if (strncmp(tempbuffer, headerMagic, magiclen) != 0 ) {
443                 *error_r = BRE_NOT_A_BLEND;
444         } else if (read(fd, tempbuffer, 1) != 1) {
445                 *error_r = BRE_UNABLE_TO_READ;
446         } else if (tempbuffer[0] != '\r' && tempbuffer[0] != '\n') {
447                 *error_r = BRE_NOT_A_BLEND;
448         } else {
449                 int crnl = (tempbuffer[0] == '\r');
450                 
451                 if (crnl && read(fd, tempbuffer, 1)!=1) {
452                         *error_r = BRE_UNABLE_TO_READ;
453                 } else {
454                         struct BLO_readblenfileStruct *readblenfileStruct;
455
456                         // Allocate all the stuff we need
457                         readblenfileStruct = calloc(sizeof(struct BLO_readblenfileStruct), 1);
458                         readblenfileStruct->fileDes    = fd;
459                         readblenfileStruct->read       = readfromfilehandle;
460
461                         readblenfileStruct->removeCR   = crnl;
462                         // fake filesize for now until we've
463                         // actually read in the filesize from the header
464                         readblenfileStruct->leftToRead = CACHESIZE;
465
466                         bfd = readblenfilegeneric(readblenfileStruct, error_r);
467
468                         free(readblenfileStruct);
469                         readblenfileStruct = 0;
470                 }
471         }
472
473         return bfd;
474 }
475
476 BlendFileData *
477 BLO_readblenfilename(
478         char *fileName, 
479         BlendReadError *error_r)
480 {
481         static char *functionality_check= "\0FUNCTIONALITY_CHECK += BLO_readblenfilename\n";
482         BlendFileData *bfd = NULL;
483         int fd;
484
485         fd = open(fileName, O_RDONLY | O_BINARY);
486         if (fd==-1) {
487                 *error_r= BRE_UNABLE_TO_OPEN;
488         } else {
489                 bfd = BLO_readblenfilehandle(fd, error_r);
490         }
491
492         if (fd!=-1)
493                 close(fd);
494
495         return bfd;
496 }
497
498         /* Runtime reading */
499
500 static int handle_read_msb_int(int handle) {
501         unsigned char buf[4];
502
503         if (read(handle, buf, 4)!=4)
504                 return -1;
505         else
506                 return (buf[0]<<24) + (buf[1]<<16) + (buf[2]<<8) + (buf[3]<<0);
507 }
508
509 int blo_is_a_runtime(char *path) {
510         int res= 0, fd= open(path, O_BINARY|O_RDONLY, 0);
511         int datastart;
512         char buf[8];
513
514         if (fd==-1)
515                 goto cleanup;
516         
517         lseek(fd, -12, SEEK_END);
518         
519         datastart= handle_read_msb_int(fd);
520         if (datastart==-1)
521                 goto cleanup;
522         else if (read(fd, buf, 8)!=8)
523                 goto cleanup;
524         else if (memcmp(buf, "BRUNTIME", 8)!=0)
525                 goto cleanup;
526         else
527                 res= 1;
528
529 cleanup:
530         if (fd!=-1)
531                 close(fd);
532
533         return res;     
534 }
535
536 BlendFileData *
537 blo_read_runtime(
538         char *path, 
539         BlendReadError *error_r) 
540 {
541         static char *functionality_check= "\0FUNCTIONALITY_CHECK += BLO_read_runtime\n";
542         BlendFileData *bfd= NULL;
543         int fd, datastart;
544         char buf[8];
545
546         fd= open(path, O_BINARY|O_RDONLY, 0);
547         if (fd==-1) {
548                 *error_r= BRE_UNABLE_TO_OPEN;
549                 goto cleanup;
550         }
551
552         lseek(fd, -12, SEEK_END);
553
554         datastart= handle_read_msb_int(fd);
555         if (datastart==-1) {
556                 *error_r= BRE_UNABLE_TO_READ;
557                 goto cleanup;
558         } else if (read(fd, buf, 8)!=8) {
559                 *error_r= BRE_UNABLE_TO_READ;
560                 goto cleanup;
561         } else if (memcmp(buf, "BRUNTIME", 8)!=0) {
562                 *error_r= BRE_NOT_A_BLEND;
563                 goto cleanup;
564         } else {        
565                 lseek(fd, datastart, SEEK_SET);
566                 bfd= BLO_readblenfilehandle(fd, error_r);
567         }
568         
569 cleanup:
570         if (fd!=-1)
571                 close(fd);
572         
573         return bfd;
574 }
575
576 #if 0
577 static char *brs_error_to_string(int err) {
578         int errFunction = BRS_GETFUNCTION(err);
579         int errGeneric =  BRS_GETGENERR(err);
580         int errSpecific = BRS_GETSPECERR(err);
581         char *errFunctionStrings[] = {
582                 "",
583                 "The read stream",
584                 "The read stream loopback",
585                 "The key store",
586                 "The file reading",
587                 "Decompressing the file",
588                 "Decrypting the file",
589                 "Verifying the signature"};
590         char *errGenericStrings[] = {
591                 "",
592                 "generated an out of memory error",
593                 "bumped on an internal programming error",
594                 "did not recognize this as a blend file",
595                 "failed a blend file check",
596                 "bumped on corrupted data",
597                 "needed the rest of the blend file",
598                 "is not allowed in this version"};
599         char *errReadStreamGlueStrings[] = {
600                 "",
601                 "does not know how to proceed"};
602         char *errReadStreamFileStrings[] = {
603                 "",
604                 "did not recognize this as a blend file",
605                 "was busted on a read error"};
606         char *errInflateStrings[] = {
607                 "",
608                 "bumped on a decompress error"};
609         char *errDecryptStrings[] = {
610                 "",
611                 "could not make a new key",
612                 "bumped on a decrypt error",
613                 "was not allowed. This blend file is not made by you."};
614         char *errVerifyStrings[] = {
615                 "",
616                 "could not make a new key",
617                 "failed"};
618         char *errFunctionString= errFunctionStrings[errFunction];
619         char *errExtraString= "";
620         char *errString;
621         
622         if (errGeneric) {
623                 errExtraString= errGenericStrings[errGeneric];
624         } else if (errSpecific) {
625                 switch (errFunction) {
626                 case BRS_READSTREAMGLUE:
627                         errExtraString= errReadStreamGlueStrings[errSpecific];
628                         break;
629                 case BRS_READSTREAMFILE:
630                         errExtraString= errReadStreamFileStrings[errSpecific];
631                         break;
632                 case BRS_INFLATE:
633                         errExtraString= errInflateStrings[errSpecific];
634                         break;
635                 case BRS_DECRYPT:
636                         errExtraString= errDecryptStrings[errSpecific];
637                         break;
638                 case BRS_VERIFY:
639                         errExtraString= errVerifyStrings[errSpecific];
640                         break;
641                 default:
642                         break;
643                 }
644         }
645         
646         errString= MEM_mallocN(strlen(errFunctionString) + 1 + strlen(errExtraString) + 1);
647         sprintf(errString, "%s %s", errFunctionString, errExtraString);
648         
649         return errString;
650 }
651 #endif