902066fbbebd1eca30ddee98a1ef43ef08e089bf
[blender.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  * \file BLO_readblenfile.c
35  * \brief This file handles the loading if .blend files
36  * \ingroup mainmodule
37  */
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <fcntl.h>
42
43 #ifdef HAVE_CONFIG_H
44 #include <config.h>
45 #endif
46
47 #ifdef WIN32
48 #include <io.h>         // read, open
49 #else // ! WIN32
50 #include <unistd.h>             // read
51 #endif
52
53 #include "BLO_readStreamGlue.h"
54
55 #include "BLO_readfile.h"
56 #include "BLO_readblenfile.h"
57
58 #include "BKE_blender.h"
59
60 #define CACHESIZE 100000
61
62 /** Magic number for the file header */
63 char *headerMagic = "BLENDFI";
64
65 /**
66  * \brief Set the version number into the array.
67  *
68  * version contains the integer number of the version
69  * i.e. 227
70  * array[1] gets set to the div of the number by 100 i.e. 2
71  * array[2] gets the remainder i.e. 27
72  */
73 void BLO_setversionnumber(char array[4], int version)
74 {
75         memset(array, 0, sizeof(array));
76
77         array[1] = version / 100;
78         array[2] = version % 100;
79 }
80
81 /**
82  * Sets version number using BLENDER_VERSION
83  * Function that calls the setversionnumber(char[],int) with 
84  * the BLENDER_VERSION constant and sets the resultant array
85  * with the version parts.  
86  * see BLO_setversionnumber(char[],int).
87  */
88 void BLO_setcurrentversionnumber(char array[4])
89 {
90         BLO_setversionnumber(array, BLENDER_VERSION);
91 }
92
93 #ifndef O_BINARY
94 #define O_BINARY 0
95 #endif
96
97 /**
98  * Defines the data struct for the .blend file
99  */
100 struct BLO_readblenfileStruct {
101         struct readStreamGlueStruct *streamGlue;
102         int fileDes;
103         unsigned int cacheSize;
104         unsigned int inCache;
105         unsigned int leftToRead;
106         unsigned int Seek;
107
108         int (*read)(struct BLO_readblenfileStruct *readblenfileStruct, void *buffer, int size);
109
110         char *readCache;
111         char *fromBuffer;
112         int  fromBufferSize;
113         char crInBuffer;
114         char removeCR;
115 };
116
117 // declare static functions
118
119 static int readfromfilehandle(
120         struct BLO_readblenfileStruct *readblenfileStruct,
121         void *buffer,
122         int size);
123
124 static int readfrommemory(
125         struct BLO_readblenfileStruct *readblenfileStruct,
126         void *buffer,
127         int size);
128
129 static int fillcache(
130         struct BLO_readblenfileStruct *readblenfileStruct);
131
132 static unsigned int readfromcache(
133         struct BLO_readblenfileStruct *readblenfileStruct,
134         void * buffer,
135         unsigned int size);
136
137 static BlendFileData *readblenfilegeneric(
138         struct BLO_readblenfileStruct *readblenfileStruct, 
139         BlendReadError *error_r);
140
141 // implementation of static functions
142
143 /**
144  * \brief Reads data from the already opened file.
145  * Given the file structure a buffer and the size of the block
146  * the function will read from the file if it is open.
147  * If not it will return -1 indicating an unopened file.
148  * 
149  * \return Returns the size of the file read, or -1.
150  */
151 static int readfromfilehandle(
152         struct BLO_readblenfileStruct *readblenfileStruct,
153         void *buffer,
154         int size)
155 {
156         int readsize = -1;
157
158         if (readblenfileStruct->fileDes != -1) {
159                 readsize = read(readblenfileStruct->fileDes, buffer, size);
160         }
161
162         return(readsize);
163 }
164
165 /**
166  * \brief Reads and erases from readblenfileStruct->fromBuffer
167  *
168  * Copies information from the from the fromBuffer to the buffer, then 
169  * decrements the size of the fromBuffer, and moves the pointer along
170  * thereby effectively removing the data forever.
171  *
172  * \return Returns the size of the read from memory
173  */     
174 static int readfrommemory(
175         struct BLO_readblenfileStruct *readblenfileStruct,
176         void *buffer,
177         int size)
178 {
179         int readsize = -1;
180
181         if (readblenfileStruct->fromBuffer) {
182                 if (size > readblenfileStruct->fromBufferSize) {
183                         size = readblenfileStruct->fromBufferSize;
184                 }
185
186                 memcpy(buffer, readblenfileStruct->fromBuffer, size);
187                 readblenfileStruct->fromBufferSize -= size;
188                 readblenfileStruct->fromBuffer += size;
189
190                 readsize = size;
191         }
192
193         return(readsize);
194 }
195
196 /**
197  * Read in data from the file into a cache.
198  *
199  * \return Returns the size of the read.
200  *
201  * \attention Note: there is some code missing to return CR if the 
202  * structure indicates it.
203 */
204 static int fillcache(
205         struct BLO_readblenfileStruct *readblenfileStruct)
206 {
207         int readsize;
208         int toread;
209
210         // how many bytes can we read ?
211
212         toread = readblenfileStruct->leftToRead;
213
214         if (toread > readblenfileStruct->cacheSize) {
215                 toread = readblenfileStruct->cacheSize;
216         }
217
218         readsize = readblenfileStruct->read(readblenfileStruct, readblenfileStruct->readCache, toread);
219         if (readsize > 0) {
220                 if (readblenfileStruct->removeCR) {
221                         // do some stuff here
222                 }
223                 readblenfileStruct->inCache = readsize;
224                 readblenfileStruct->leftToRead -= readsize;
225         }
226
227         return (readsize);
228 }
229
230 /**
231  * \brief Read data from the cache into a buffer.
232  * Marks the last read location with a seek value.
233  *
234  * \return Returns the size of the read from the cache.
235  *
236  * \attention Note: missing some handling code if the location is
237  * \attention outside of the cache.
238  */
239 static unsigned int readfromcache(
240         struct BLO_readblenfileStruct *readblenfileStruct,
241         void * buffer,
242         unsigned int size)
243 {
244         unsigned int readsize = 0;
245
246         if (readblenfileStruct->inCache - readblenfileStruct->Seek > size) {
247                 memcpy(buffer, readblenfileStruct->readCache + readblenfileStruct->Seek, size);
248                 readblenfileStruct->Seek += size;
249                 readsize = size;
250         } else {
251                 // handle me
252         }
253
254         return(readsize);
255 }
256
257 /**
258  * \brief Converts from BRS error code to BRE error code.
259  *
260  * Error conversion method to convert from
261  * the BRS type errors and return a BRE 
262  * type error code.
263  * Decodes based on the function, the generic,
264  * and the specific portions of the error.
265  */
266 static BlendReadError brs_to_bre(int err)
267 {
268         int errFunction = BRS_GETFUNCTION(err);
269         int errGeneric =  BRS_GETGENERR(err);
270         int errSpecific = BRS_GETSPECERR(err);
271
272         if (errGeneric) {
273                 switch (errGeneric) {
274                 case BRS_MALLOC:
275                         return BRE_OUT_OF_MEMORY;
276                 case BRS_NULL:
277                         return BRE_INTERNAL_ERROR;
278                 case BRS_MAGIC:
279                         return BRE_NOT_A_BLEND;
280                 case BRS_CRCHEADER:
281                 case BRS_CRCDATA:
282                         return BRE_CORRUPT;
283                 case BRS_DATALEN:
284                         return BRE_INCOMPLETE;
285                 case BRS_STUB:
286                         return BRE_NOT_A_BLEND;
287                 }
288         } else if (errSpecific) {
289                 switch (errFunction) {
290                 case BRS_READSTREAMGLUE:
291                         switch (errSpecific) {
292                         case BRS_UNKNOWN:
293                                 return BRE_INTERNAL_ERROR;
294                         }
295                         break;
296                 case BRS_READSTREAMFILE:
297                         switch (errSpecific) {
298                         case BRS_NOTABLEND:
299                                 return BRE_NOT_A_BLEND;
300                         case BRS_READERROR:
301                                 return BRE_UNABLE_TO_READ;
302                         }
303                         break;
304                 case BRS_INFLATE:
305                         switch (errSpecific) {
306                         case BRS_INFLATEERROR:
307                                 return BRE_CORRUPT;
308                         }
309                         break;
310                 case BRS_DECRYPT:
311                         switch (errSpecific) {
312                         case BRS_RSANEWERROR:
313                                 return BRE_INTERNAL_ERROR;
314                         case BRS_DECRYPTERROR:
315                                 return BRE_INTERNAL_ERROR;
316                         case BRS_NOTOURPUBKEY:
317                                 return BRE_NOT_ALLOWED;
318                         }
319                         break;
320                 case BRS_VERIFY:
321                         switch (errSpecific) {
322                         case BRS_RSANEWERROR:
323                                 return BRE_INTERNAL_ERROR;
324                         case BRS_SIGFAILED:
325                                 return BRE_INTERNAL_ERROR;
326                         }
327                         break;
328                 }
329         }
330         
331         return BRE_INVALID;
332 }
333
334 static BlendFileData *readblenfilegeneric(
335         struct BLO_readblenfileStruct *readblenfileStruct, 
336         BlendReadError *error_r)
337 {
338         BlendFileData *bfd= NULL;
339         unsigned char reserved[BLO_RESERVEDSIZE];
340         uint8_t minversion[4];
341         uint8_t myversion[4];
342         uint8_t version[4];
343         uint8_t flags[4];
344         void *parms[2];
345         int filesize;
346         
347         parms[0]= &bfd;
348         parms[1]= error_r;
349
350         BLO_setcurrentversionnumber(myversion);
351
352         readblenfileStruct->cacheSize      = CACHESIZE;
353         readblenfileStruct->readCache      = malloc(readblenfileStruct->cacheSize);
354
355         if (fillcache(readblenfileStruct) <= 0) {
356                 *error_r = BRE_UNABLE_TO_READ;
357         } else if (readfromcache(readblenfileStruct, minversion, sizeof(minversion)) != sizeof(minversion)) {
358                 *error_r = BRE_UNABLE_TO_READ;
359         } else if (memcmp(minversion, myversion, sizeof(minversion)) > 0) {
360                 *error_r = BRE_TOO_NEW;
361         } else if (readfromcache(readblenfileStruct, version,  sizeof(version)) != sizeof(version)) {
362                 *error_r = BRE_UNABLE_TO_READ;
363         } else if (readfromcache(readblenfileStruct, flags,    sizeof(flags)) != sizeof(flags)) {
364                 *error_r = BRE_UNABLE_TO_READ;
365         } else if (readfromcache(readblenfileStruct, &filesize, sizeof(filesize)) != sizeof(filesize)) {
366                 *error_r = BRE_UNABLE_TO_READ;
367         } else if (readfromcache(readblenfileStruct, reserved, sizeof(reserved)) != sizeof(reserved)) {
368                 *error_r = BRE_UNABLE_TO_READ;
369         }  else {
370                 filesize = ntohl(filesize);
371
372                 // substract number of bytes we've
373                 // been handling outside readfromcache()
374                 filesize -= strlen(headerMagic);
375                 filesize--;
376
377                 if (filesize < readblenfileStruct->inCache) {
378                         // we've allready read more than we're supposed to
379                         readblenfileStruct->inCache   = filesize;
380                         readblenfileStruct->leftToRead = 0;                                                                     
381                 } else {
382                         // 
383                         readblenfileStruct->leftToRead = filesize - readblenfileStruct->inCache;
384                 }
385
386                 do {
387                         int err;
388
389                         *error_r = BRE_NONE;
390                         err = readStreamGlue(
391                                 parms,
392                                 &(readblenfileStruct->streamGlue),
393                                 readblenfileStruct->readCache + readblenfileStruct->Seek,
394                                 readblenfileStruct->inCache - readblenfileStruct->Seek);
395
396                         readblenfileStruct->inCache = 0;
397                         readblenfileStruct->Seek = 0;
398
399                         if (err) {
400                                 bfd = NULL;
401
402                                         /* If *error_r != BRE_NONE then it is
403                                          * blo_readstreamfile_end signaling an error
404                                          * in the loading code. Otherwise it is some
405                                          * other part of the streamglue system signalling
406                                          * and error so we convert the BRS error into
407                                          * a BRE error.
408                                          * 
409                                          * Does this have to be so convoluted? No.
410                                          */
411                                 if (*error_r == BRE_NONE) {
412                                         *error_r = brs_to_bre(err);
413                                 }
414                                 
415                                 break;
416                         }
417                 } while (fillcache(readblenfileStruct) > 0);
418         }
419
420         free(readblenfileStruct->readCache);
421         readblenfileStruct->readCache = 0;
422
423         return bfd;
424 }
425
426 // implementation of exported functions
427
428 BlendFileData *
429 BLO_readblenfilememory(
430         char *fromBuffer, 
431         int fromBufferSize, 
432         BlendReadError *error_r)
433 {
434         int magiclen = strlen(headerMagic);
435         BlendFileData *bfd = NULL;
436
437         if (!fromBuffer) {
438                 *error_r = BRE_UNABLE_TO_OPEN;
439         } else if (fromBufferSize < magiclen) {
440                 *error_r = BRE_UNABLE_TO_READ;
441         } else if (strncmp(fromBuffer, headerMagic, magiclen) != 0) {
442                 *error_r = BRE_NOT_A_BLEND;
443         } else if (fromBufferSize < magiclen+1) {
444                 *error_r = BRE_UNABLE_TO_READ;
445         } else if (fromBuffer[magiclen] != '\r' && fromBuffer[magiclen] != '\n') {
446                 *error_r = BRE_NOT_A_BLEND;
447         } else {
448                 int crnl; 
449
450                 fromBuffer+= magiclen;
451                 fromBufferSize-= magiclen;
452                 crnl = (fromBuffer[0] == '\r');
453                 fromBuffer++;
454                 fromBufferSize--;
455                 
456                 if (crnl && fromBufferSize<1) {
457                         *error_r = BRE_UNABLE_TO_READ;
458                 } else {
459                         struct BLO_readblenfileStruct *readblenfileStruct = NULL;
460
461                                 /* skip carriage return if necessary */
462                         if (crnl) {
463                                 fromBuffer++;
464                                 fromBufferSize--;
465                         }
466
467                         // Allocate all the stuff we need
468                         readblenfileStruct = calloc(sizeof(struct BLO_readblenfileStruct), 1);
469                         readblenfileStruct->fileDes        = -1;
470                         readblenfileStruct->fromBuffer     = fromBuffer;
471                         readblenfileStruct->fromBufferSize = fromBufferSize;
472                         readblenfileStruct->read                   = readfrommemory;
473
474                         readblenfileStruct->removeCR   = crnl;
475                         // fake filesize for now until we've
476                         // actually read in the filesize from the header
477                         // make sure we don't read more bytes than there
478                         // are left to handle accoding to fromBufferSize
479                         readblenfileStruct->leftToRead = readblenfileStruct->fromBufferSize;
480
481                         bfd = readblenfilegeneric(readblenfileStruct, error_r);
482
483                         free(readblenfileStruct);
484                         readblenfileStruct = 0;
485                 }
486         }
487
488         return bfd;
489 }
490
491
492 BlendFileData *
493 BLO_readblenfilehandle(
494         int fd, 
495         BlendReadError *error_r)
496 {
497         int magiclen = strlen(headerMagic);
498         BlendFileData *bfd = NULL;
499         char tempbuffer[256];
500         
501         if (fd==-1) {
502                 *error_r = BRE_UNABLE_TO_OPEN;
503         } else if (read(fd, tempbuffer, magiclen) != magiclen) {
504                 *error_r = BRE_UNABLE_TO_READ;
505         } else if (strncmp(tempbuffer, headerMagic, magiclen) != 0 ) {
506                 *error_r = BRE_NOT_A_BLEND;
507         } else if (read(fd, tempbuffer, 1) != 1) {
508                 *error_r = BRE_UNABLE_TO_READ;
509         } else if (tempbuffer[0] != '\r' && tempbuffer[0] != '\n') {
510                 *error_r = BRE_NOT_A_BLEND;
511         } else {
512                 int crnl = (tempbuffer[0] == '\r');
513                 
514                 if (crnl && read(fd, tempbuffer, 1)!=1) {
515                         *error_r = BRE_UNABLE_TO_READ;
516                 } else {
517                         struct BLO_readblenfileStruct *readblenfileStruct;
518
519                         // Allocate all the stuff we need
520                         readblenfileStruct = calloc(sizeof(struct BLO_readblenfileStruct), 1);
521                         readblenfileStruct->fileDes    = fd;
522                         readblenfileStruct->read       = readfromfilehandle;
523
524                         readblenfileStruct->removeCR   = crnl;
525                         // fake filesize for now until we've
526                         // actually read in the filesize from the header
527                         readblenfileStruct->leftToRead = CACHESIZE;
528
529                         bfd = readblenfilegeneric(readblenfileStruct, error_r);
530
531                         free(readblenfileStruct);
532                         readblenfileStruct = 0;
533                 }
534         }
535
536         return bfd;
537 }
538
539 BlendFileData *
540 BLO_readblenfilename(
541         char *fileName, 
542         BlendReadError *error_r)
543 {
544         BlendFileData *bfd = NULL;
545         int fd;
546
547         fd = open(fileName, O_RDONLY | O_BINARY);
548         if (fd==-1) {
549                 *error_r= BRE_UNABLE_TO_OPEN;
550         } else {
551                 bfd = BLO_readblenfilehandle(fd, error_r);
552         }
553
554         if (fd!=-1)
555                 close(fd);
556
557         return bfd;
558 }
559
560         /* Runtime reading */
561
562 static int handle_read_msb_int(int handle) {
563         unsigned char buf[4];
564
565         if (read(handle, buf, 4)!=4)
566                 return -1;
567         else
568                 return (buf[0]<<24) + (buf[1]<<16) + (buf[2]<<8) + (buf[3]<<0);
569 }
570
571 int blo_is_a_runtime(char *path) {
572         int res= 0, fd= open(path, O_BINARY|O_RDONLY, 0);
573         int datastart;
574         char buf[8];
575
576         if (fd==-1)
577                 goto cleanup;
578         
579         lseek(fd, -12, SEEK_END);
580         
581         datastart= handle_read_msb_int(fd);
582         if (datastart==-1)
583                 goto cleanup;
584         else if (read(fd, buf, 8)!=8)
585                 goto cleanup;
586         else if (memcmp(buf, "BRUNTIME", 8)!=0)
587                 goto cleanup;
588         else
589                 res= 1;
590
591 cleanup:
592         if (fd!=-1)
593                 close(fd);
594
595         return res;     
596 }
597
598 BlendFileData *
599 blo_read_runtime(
600         char *path, 
601         BlendReadError *error_r) 
602 {
603         BlendFileData *bfd= NULL;
604         int fd, datastart;
605         char buf[8];
606
607         fd= open(path, O_BINARY|O_RDONLY, 0);
608         if (fd==-1) {
609                 *error_r= BRE_UNABLE_TO_OPEN;
610                 goto cleanup;
611         }
612
613         lseek(fd, -12, SEEK_END);
614
615         datastart= handle_read_msb_int(fd);
616         if (datastart==-1) {
617                 *error_r= BRE_UNABLE_TO_READ;
618                 goto cleanup;
619         } else if (read(fd, buf, 8)!=8) {
620                 *error_r= BRE_UNABLE_TO_READ;
621                 goto cleanup;
622         } else if (memcmp(buf, "BRUNTIME", 8)!=0) {
623                 *error_r= BRE_NOT_A_BLEND;
624                 goto cleanup;
625         } else {        
626                 lseek(fd, datastart, SEEK_SET);
627                 bfd= BLO_readblenfilehandle(fd, error_r);
628         }
629         
630 cleanup:
631         if (fd!=-1)
632                 close(fd);
633         
634         return bfd;
635 }
636
637 #if 0
638 static char *brs_error_to_string(int err) {
639         int errFunction = BRS_GETFUNCTION(err);
640         int errGeneric =  BRS_GETGENERR(err);
641         int errSpecific = BRS_GETSPECERR(err);
642         char *errFunctionStrings[] = {
643                 "",
644                 "The read stream",
645                 "The read stream loopback",
646                 "The key store",
647                 "The file reading",
648                 "Decompressing the file",
649                 "Decrypting the file",
650                 "Verifying the signature"};
651         char *errGenericStrings[] = {
652                 "",
653                 "generated an out of memory error",
654                 "bumped on an internal programming error",
655                 "did not recognize this as a blend file",
656                 "failed a blend file check",
657                 "bumped on corrupted data",
658                 "needed the rest of the blend file",
659                 "is not allowed in this version"};
660         char *errReadStreamGlueStrings[] = {
661                 "",
662                 "does not know how to proceed"};
663         char *errReadStreamFileStrings[] = {
664                 "",
665                 "did not recognize this as a blend file",
666                 "was busted on a read error"};
667         char *errInflateStrings[] = {
668                 "",
669                 "bumped on a decompress error"};
670         char *errDecryptStrings[] = {
671                 "",
672                 "could not make a new key",
673                 "bumped on a decrypt error",
674                 "was not allowed. This blend file is not made by you."};
675         char *errVerifyStrings[] = {
676                 "",
677                 "could not make a new key",
678                 "failed"};
679         char *errFunctionString= errFunctionStrings[errFunction];
680         char *errExtraString= "";
681         char *errString;
682         
683         if (errGeneric) {
684                 errExtraString= errGenericStrings[errGeneric];
685         } else if (errSpecific) {
686                 switch (errFunction) {
687                 case BRS_READSTREAMGLUE:
688                         errExtraString= errReadStreamGlueStrings[errSpecific];
689                         break;
690                 case BRS_READSTREAMFILE:
691                         errExtraString= errReadStreamFileStrings[errSpecific];
692                         break;
693                 case BRS_INFLATE:
694                         errExtraString= errInflateStrings[errSpecific];
695                         break;
696                 case BRS_DECRYPT:
697                         errExtraString= errDecryptStrings[errSpecific];
698                         break;
699                 case BRS_VERIFY:
700                         errExtraString= errVerifyStrings[errSpecific];
701                         break;
702                 default:
703                         break;
704                 }
705         }
706         
707         errString= MEM_mallocN(strlen(errFunctionString) + 1 + strlen(errExtraString) + 1);
708         sprintf(errString, "%s %s", errFunctionString, errExtraString);
709         
710         return errString;
711 }
712 #endif
713
714