Last of cgul's documentation submissions.
[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  * \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         static char *functionality_check= "\0FUNCTIONALITY_CHECK += BLO_readblenfilememory\n";
435         int magiclen = strlen(headerMagic);
436         BlendFileData *bfd = NULL;
437
438         if (!fromBuffer) {
439                 *error_r = BRE_UNABLE_TO_OPEN;
440         } else if (fromBufferSize < magiclen) {
441                 *error_r = BRE_UNABLE_TO_READ;
442         } else if (strncmp(fromBuffer, headerMagic, magiclen) != 0) {
443                 *error_r = BRE_NOT_A_BLEND;
444         } else if (fromBufferSize < magiclen+1) {
445                 *error_r = BRE_UNABLE_TO_READ;
446         } else if (fromBuffer[magiclen] != '\r' && fromBuffer[magiclen] != '\n') {
447                 *error_r = BRE_NOT_A_BLEND;
448         } else {
449                 int crnl; 
450
451                 fromBuffer+= magiclen;
452                 fromBufferSize-= magiclen;
453                 crnl = (fromBuffer[0] == '\r');
454                 fromBuffer++;
455                 fromBufferSize--;
456                 
457                 if (crnl && fromBufferSize<1) {
458                         *error_r = BRE_UNABLE_TO_READ;
459                 } else {
460                         struct BLO_readblenfileStruct *readblenfileStruct = NULL;
461
462                                 /* skip carriage return if necessary */
463                         if (crnl) {
464                                 fromBuffer++;
465                                 fromBufferSize--;
466                         }
467
468                         // Allocate all the stuff we need
469                         readblenfileStruct = calloc(sizeof(struct BLO_readblenfileStruct), 1);
470                         readblenfileStruct->fileDes        = -1;
471                         readblenfileStruct->fromBuffer     = fromBuffer;
472                         readblenfileStruct->fromBufferSize = fromBufferSize;
473                         readblenfileStruct->read                   = readfrommemory;
474
475                         readblenfileStruct->removeCR   = crnl;
476                         // fake filesize for now until we've
477                         // actually read in the filesize from the header
478                         // make sure we don't read more bytes than there
479                         // are left to handle accoding to fromBufferSize
480                         readblenfileStruct->leftToRead = readblenfileStruct->fromBufferSize;
481
482                         bfd = readblenfilegeneric(readblenfileStruct, error_r);
483
484                         free(readblenfileStruct);
485                         readblenfileStruct = 0;
486                 }
487         }
488
489         return bfd;
490 }
491
492
493 BlendFileData *
494 BLO_readblenfilehandle(
495         int fd, 
496         BlendReadError *error_r)
497 {
498         static char *functionality_check= "\0FUNCTIONALITY_CHECK += BLO_readblenfilehandle\n";
499         int magiclen = strlen(headerMagic);
500         BlendFileData *bfd = NULL;
501         char tempbuffer[256];
502         
503         if (fd==-1) {
504                 *error_r = BRE_UNABLE_TO_OPEN;
505         } else if (read(fd, tempbuffer, magiclen) != magiclen) {
506                 *error_r = BRE_UNABLE_TO_READ;
507         } else if (strncmp(tempbuffer, headerMagic, magiclen) != 0 ) {
508                 *error_r = BRE_NOT_A_BLEND;
509         } else if (read(fd, tempbuffer, 1) != 1) {
510                 *error_r = BRE_UNABLE_TO_READ;
511         } else if (tempbuffer[0] != '\r' && tempbuffer[0] != '\n') {
512                 *error_r = BRE_NOT_A_BLEND;
513         } else {
514                 int crnl = (tempbuffer[0] == '\r');
515                 
516                 if (crnl && read(fd, tempbuffer, 1)!=1) {
517                         *error_r = BRE_UNABLE_TO_READ;
518                 } else {
519                         struct BLO_readblenfileStruct *readblenfileStruct;
520
521                         // Allocate all the stuff we need
522                         readblenfileStruct = calloc(sizeof(struct BLO_readblenfileStruct), 1);
523                         readblenfileStruct->fileDes    = fd;
524                         readblenfileStruct->read       = readfromfilehandle;
525
526                         readblenfileStruct->removeCR   = crnl;
527                         // fake filesize for now until we've
528                         // actually read in the filesize from the header
529                         readblenfileStruct->leftToRead = CACHESIZE;
530
531                         bfd = readblenfilegeneric(readblenfileStruct, error_r);
532
533                         free(readblenfileStruct);
534                         readblenfileStruct = 0;
535                 }
536         }
537
538         return bfd;
539 }
540
541 BlendFileData *
542 BLO_readblenfilename(
543         char *fileName, 
544         BlendReadError *error_r)
545 {
546         static char *functionality_check= "\0FUNCTIONALITY_CHECK += BLO_readblenfilename\n";
547         BlendFileData *bfd = NULL;
548         int fd;
549
550         fd = open(fileName, O_RDONLY | O_BINARY);
551         if (fd==-1) {
552                 *error_r= BRE_UNABLE_TO_OPEN;
553         } else {
554                 bfd = BLO_readblenfilehandle(fd, error_r);
555         }
556
557         if (fd!=-1)
558                 close(fd);
559
560         return bfd;
561 }
562
563         /* Runtime reading */
564
565 static int handle_read_msb_int(int handle) {
566         unsigned char buf[4];
567
568         if (read(handle, buf, 4)!=4)
569                 return -1;
570         else
571                 return (buf[0]<<24) + (buf[1]<<16) + (buf[2]<<8) + (buf[3]<<0);
572 }
573
574 int blo_is_a_runtime(char *path) {
575         int res= 0, fd= open(path, O_BINARY|O_RDONLY, 0);
576         int datastart;
577         char buf[8];
578
579         if (fd==-1)
580                 goto cleanup;
581         
582         lseek(fd, -12, SEEK_END);
583         
584         datastart= handle_read_msb_int(fd);
585         if (datastart==-1)
586                 goto cleanup;
587         else if (read(fd, buf, 8)!=8)
588                 goto cleanup;
589         else if (memcmp(buf, "BRUNTIME", 8)!=0)
590                 goto cleanup;
591         else
592                 res= 1;
593
594 cleanup:
595         if (fd!=-1)
596                 close(fd);
597
598         return res;     
599 }
600
601 BlendFileData *
602 blo_read_runtime(
603         char *path, 
604         BlendReadError *error_r) 
605 {
606         static char *functionality_check= "\0FUNCTIONALITY_CHECK += BLO_read_runtime\n";
607         BlendFileData *bfd= NULL;
608         int fd, datastart;
609         char buf[8];
610
611         fd= open(path, O_BINARY|O_RDONLY, 0);
612         if (fd==-1) {
613                 *error_r= BRE_UNABLE_TO_OPEN;
614                 goto cleanup;
615         }
616
617         lseek(fd, -12, SEEK_END);
618
619         datastart= handle_read_msb_int(fd);
620         if (datastart==-1) {
621                 *error_r= BRE_UNABLE_TO_READ;
622                 goto cleanup;
623         } else if (read(fd, buf, 8)!=8) {
624                 *error_r= BRE_UNABLE_TO_READ;
625                 goto cleanup;
626         } else if (memcmp(buf, "BRUNTIME", 8)!=0) {
627                 *error_r= BRE_NOT_A_BLEND;
628                 goto cleanup;
629         } else {        
630                 lseek(fd, datastart, SEEK_SET);
631                 bfd= BLO_readblenfilehandle(fd, error_r);
632         }
633         
634 cleanup:
635         if (fd!=-1)
636                 close(fd);
637         
638         return bfd;
639 }
640
641 #if 0
642 static char *brs_error_to_string(int err) {
643         int errFunction = BRS_GETFUNCTION(err);
644         int errGeneric =  BRS_GETGENERR(err);
645         int errSpecific = BRS_GETSPECERR(err);
646         char *errFunctionStrings[] = {
647                 "",
648                 "The read stream",
649                 "The read stream loopback",
650                 "The key store",
651                 "The file reading",
652                 "Decompressing the file",
653                 "Decrypting the file",
654                 "Verifying the signature"};
655         char *errGenericStrings[] = {
656                 "",
657                 "generated an out of memory error",
658                 "bumped on an internal programming error",
659                 "did not recognize this as a blend file",
660                 "failed a blend file check",
661                 "bumped on corrupted data",
662                 "needed the rest of the blend file",
663                 "is not allowed in this version"};
664         char *errReadStreamGlueStrings[] = {
665                 "",
666                 "does not know how to proceed"};
667         char *errReadStreamFileStrings[] = {
668                 "",
669                 "did not recognize this as a blend file",
670                 "was busted on a read error"};
671         char *errInflateStrings[] = {
672                 "",
673                 "bumped on a decompress error"};
674         char *errDecryptStrings[] = {
675                 "",
676                 "could not make a new key",
677                 "bumped on a decrypt error",
678                 "was not allowed. This blend file is not made by you."};
679         char *errVerifyStrings[] = {
680                 "",
681                 "could not make a new key",
682                 "failed"};
683         char *errFunctionString= errFunctionStrings[errFunction];
684         char *errExtraString= "";
685         char *errString;
686         
687         if (errGeneric) {
688                 errExtraString= errGenericStrings[errGeneric];
689         } else if (errSpecific) {
690                 switch (errFunction) {
691                 case BRS_READSTREAMGLUE:
692                         errExtraString= errReadStreamGlueStrings[errSpecific];
693                         break;
694                 case BRS_READSTREAMFILE:
695                         errExtraString= errReadStreamFileStrings[errSpecific];
696                         break;
697                 case BRS_INFLATE:
698                         errExtraString= errInflateStrings[errSpecific];
699                         break;
700                 case BRS_DECRYPT:
701                         errExtraString= errDecryptStrings[errSpecific];
702                         break;
703                 case BRS_VERIFY:
704                         errExtraString= errVerifyStrings[errSpecific];
705                         break;
706                 default:
707                         break;
708                 }
709         }
710         
711         errString= MEM_mallocN(strlen(errFunctionString) + 1 + strlen(errExtraString) + 1);
712         sprintf(errString, "%s %s", errFunctionString, errExtraString);
713         
714         return errString;
715 }
716 #endif
717
718