#ifdef HAVE_CONFIG_H #include <config.h> #endif Just need to finish cpp files now :) Kent -- mein@cs.umn.edu
652 lines
15 KiB
C
652 lines
15 KiB
C
/**
|
|
* $Id$
|
|
*
|
|
* ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version. The Blender
|
|
* Foundation also sells licenses for use in proprietary software under
|
|
* the Blender License. See http://www.blender.org/BL/ for information
|
|
* about this.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
* All rights reserved.
|
|
*
|
|
* The Original Code is: all of this file.
|
|
*
|
|
* Contributor(s): none yet.
|
|
*
|
|
* ***** END GPL/BL DUAL LICENSE BLOCK *****
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
#include <io.h> // read, open
|
|
#else // ! WIN32
|
|
#include <unistd.h> // read
|
|
#endif
|
|
|
|
#include "BLO_readStreamGlue.h"
|
|
|
|
#include "BLO_readfile.h"
|
|
#include "BLO_readblenfile.h"
|
|
|
|
#include "BKE_blender.h"
|
|
|
|
#define CACHESIZE 100000
|
|
|
|
char *headerMagic = "BLENDFI";
|
|
|
|
void BLO_setversionnumber(char array[4], int version)
|
|
{
|
|
memset(array, 0, sizeof(array));
|
|
|
|
array[1] = version / 100;
|
|
array[2] = version % 100;
|
|
}
|
|
|
|
void BLO_setcurrentversionnumber(char array[4])
|
|
{
|
|
BLO_setversionnumber(array, BLENDER_VERSION);
|
|
}
|
|
|
|
#ifndef O_BINARY
|
|
#define O_BINARY 0
|
|
#endif
|
|
|
|
struct BLO_readblenfileStruct {
|
|
struct readStreamGlueStruct *streamGlue;
|
|
int fileDes;
|
|
unsigned int cacheSize;
|
|
unsigned int inCache;
|
|
unsigned int leftToRead;
|
|
unsigned int Seek;
|
|
|
|
int (*read)(struct BLO_readblenfileStruct *readblenfileStruct, void *buffer, int size);
|
|
|
|
char *readCache;
|
|
char *fromBuffer;
|
|
int fromBufferSize;
|
|
char crInBuffer;
|
|
char removeCR;
|
|
};
|
|
|
|
// declare static functions
|
|
|
|
static int readfromfilehandle(
|
|
struct BLO_readblenfileStruct *readblenfileStruct,
|
|
void *buffer,
|
|
int size);
|
|
|
|
static int readfrommemory(
|
|
struct BLO_readblenfileStruct *readblenfileStruct,
|
|
void *buffer,
|
|
int size);
|
|
|
|
static int fillcache(
|
|
struct BLO_readblenfileStruct *readblenfileStruct);
|
|
|
|
static unsigned int readfromcache(
|
|
struct BLO_readblenfileStruct *readblenfileStruct,
|
|
void * buffer,
|
|
unsigned int size);
|
|
|
|
static BlendFileData *readblenfilegeneric(
|
|
struct BLO_readblenfileStruct *readblenfileStruct,
|
|
BlendReadError *error_r);
|
|
|
|
// implementation of static functions
|
|
|
|
static int readfromfilehandle(
|
|
struct BLO_readblenfileStruct *readblenfileStruct,
|
|
void *buffer,
|
|
int size)
|
|
{
|
|
int readsize = -1;
|
|
|
|
if (readblenfileStruct->fileDes != -1) {
|
|
readsize = read(readblenfileStruct->fileDes, buffer, size);
|
|
}
|
|
|
|
return(readsize);
|
|
}
|
|
|
|
static int readfrommemory(
|
|
struct BLO_readblenfileStruct *readblenfileStruct,
|
|
void *buffer,
|
|
int size)
|
|
{
|
|
int readsize = -1;
|
|
|
|
if (readblenfileStruct->fromBuffer) {
|
|
if (size > readblenfileStruct->fromBufferSize) {
|
|
size = readblenfileStruct->fromBufferSize;
|
|
}
|
|
|
|
memcpy(buffer, readblenfileStruct->fromBuffer, size);
|
|
readblenfileStruct->fromBufferSize -= size;
|
|
readblenfileStruct->fromBuffer += size;
|
|
|
|
readsize = size;
|
|
}
|
|
|
|
return(readsize);
|
|
}
|
|
|
|
static int fillcache(
|
|
struct BLO_readblenfileStruct *readblenfileStruct)
|
|
{
|
|
int readsize;
|
|
int toread;
|
|
|
|
// how many bytes can we read ?
|
|
|
|
toread = readblenfileStruct->leftToRead;
|
|
|
|
if (toread > readblenfileStruct->cacheSize) {
|
|
toread = readblenfileStruct->cacheSize;
|
|
}
|
|
|
|
readsize = readblenfileStruct->read(readblenfileStruct, readblenfileStruct->readCache, toread);
|
|
if (readsize > 0) {
|
|
if (readblenfileStruct->removeCR) {
|
|
// do some stuff here
|
|
}
|
|
readblenfileStruct->inCache = readsize;
|
|
readblenfileStruct->leftToRead -= readsize;
|
|
}
|
|
|
|
return (readsize);
|
|
}
|
|
|
|
|
|
static unsigned int readfromcache(
|
|
struct BLO_readblenfileStruct *readblenfileStruct,
|
|
void * buffer,
|
|
unsigned int size)
|
|
{
|
|
unsigned int readsize = 0;
|
|
|
|
if (readblenfileStruct->inCache - readblenfileStruct->Seek > size) {
|
|
memcpy(buffer, readblenfileStruct->readCache + readblenfileStruct->Seek, size);
|
|
readblenfileStruct->Seek += size;
|
|
readsize = size;
|
|
} else {
|
|
// handle me
|
|
}
|
|
|
|
return(readsize);
|
|
}
|
|
|
|
static BlendReadError brs_to_bre(int err)
|
|
{
|
|
int errFunction = BRS_GETFUNCTION(err);
|
|
int errGeneric = BRS_GETGENERR(err);
|
|
int errSpecific = BRS_GETSPECERR(err);
|
|
|
|
if (errGeneric) {
|
|
switch (errGeneric) {
|
|
case BRS_MALLOC:
|
|
return BRE_OUT_OF_MEMORY;
|
|
case BRS_NULL:
|
|
return BRE_INTERNAL_ERROR;
|
|
case BRS_MAGIC:
|
|
return BRE_NOT_A_BLEND;
|
|
case BRS_CRCHEADER:
|
|
case BRS_CRCDATA:
|
|
return BRE_CORRUPT;
|
|
case BRS_DATALEN:
|
|
return BRE_INCOMPLETE;
|
|
case BRS_STUB:
|
|
return BRE_NOT_A_BLEND;
|
|
}
|
|
} else if (errSpecific) {
|
|
switch (errFunction) {
|
|
case BRS_READSTREAMGLUE:
|
|
switch (errSpecific) {
|
|
case BRS_UNKNOWN:
|
|
return BRE_INTERNAL_ERROR;
|
|
}
|
|
break;
|
|
case BRS_READSTREAMFILE:
|
|
switch (errSpecific) {
|
|
case BRS_NOTABLEND:
|
|
return BRE_NOT_A_BLEND;
|
|
case BRS_READERROR:
|
|
return BRE_UNABLE_TO_READ;
|
|
}
|
|
break;
|
|
case BRS_INFLATE:
|
|
switch (errSpecific) {
|
|
case BRS_INFLATEERROR:
|
|
return BRE_CORRUPT;
|
|
}
|
|
break;
|
|
case BRS_DECRYPT:
|
|
switch (errSpecific) {
|
|
case BRS_RSANEWERROR:
|
|
return BRE_INTERNAL_ERROR;
|
|
case BRS_DECRYPTERROR:
|
|
return BRE_INTERNAL_ERROR;
|
|
case BRS_NOTOURPUBKEY:
|
|
return BRE_NOT_ALLOWED;
|
|
}
|
|
break;
|
|
case BRS_VERIFY:
|
|
switch (errSpecific) {
|
|
case BRS_RSANEWERROR:
|
|
return BRE_INTERNAL_ERROR;
|
|
case BRS_SIGFAILED:
|
|
return BRE_INTERNAL_ERROR;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return BRE_INVALID;
|
|
}
|
|
|
|
static BlendFileData *readblenfilegeneric(
|
|
struct BLO_readblenfileStruct *readblenfileStruct,
|
|
BlendReadError *error_r)
|
|
{
|
|
BlendFileData *bfd= NULL;
|
|
unsigned char reserved[BLO_RESERVEDSIZE];
|
|
uint8_t minversion[4];
|
|
uint8_t myversion[4];
|
|
uint8_t version[4];
|
|
uint8_t flags[4];
|
|
void *parms[2];
|
|
int filesize;
|
|
|
|
parms[0]= &bfd;
|
|
parms[1]= error_r;
|
|
|
|
BLO_setcurrentversionnumber(myversion);
|
|
|
|
readblenfileStruct->cacheSize = CACHESIZE;
|
|
readblenfileStruct->readCache = malloc(readblenfileStruct->cacheSize);
|
|
|
|
if (fillcache(readblenfileStruct) <= 0) {
|
|
*error_r = BRE_UNABLE_TO_READ;
|
|
} else if (readfromcache(readblenfileStruct, minversion, sizeof(minversion)) != sizeof(minversion)) {
|
|
*error_r = BRE_UNABLE_TO_READ;
|
|
} else if (memcmp(minversion, myversion, sizeof(minversion)) > 0) {
|
|
*error_r = BRE_TOO_NEW;
|
|
} else if (readfromcache(readblenfileStruct, version, sizeof(version)) != sizeof(version)) {
|
|
*error_r = BRE_UNABLE_TO_READ;
|
|
} else if (readfromcache(readblenfileStruct, flags, sizeof(flags)) != sizeof(flags)) {
|
|
*error_r = BRE_UNABLE_TO_READ;
|
|
} else if (readfromcache(readblenfileStruct, &filesize, sizeof(filesize)) != sizeof(filesize)) {
|
|
*error_r = BRE_UNABLE_TO_READ;
|
|
} else if (readfromcache(readblenfileStruct, reserved, sizeof(reserved)) != sizeof(reserved)) {
|
|
*error_r = BRE_UNABLE_TO_READ;
|
|
} else {
|
|
filesize = ntohl(filesize);
|
|
|
|
// substract number of bytes we've
|
|
// been handling outside readfromcache()
|
|
filesize -= strlen(headerMagic);
|
|
filesize--;
|
|
|
|
if (filesize < readblenfileStruct->inCache) {
|
|
// we've allready read more than we're supposed to
|
|
readblenfileStruct->inCache = filesize;
|
|
readblenfileStruct->leftToRead = 0;
|
|
} else {
|
|
//
|
|
readblenfileStruct->leftToRead = filesize - readblenfileStruct->inCache;
|
|
}
|
|
|
|
do {
|
|
int err;
|
|
|
|
*error_r = BRE_NONE;
|
|
err = readStreamGlue(
|
|
parms,
|
|
&(readblenfileStruct->streamGlue),
|
|
readblenfileStruct->readCache + readblenfileStruct->Seek,
|
|
readblenfileStruct->inCache - readblenfileStruct->Seek);
|
|
|
|
readblenfileStruct->inCache = 0;
|
|
readblenfileStruct->Seek = 0;
|
|
|
|
if (err) {
|
|
bfd = NULL;
|
|
|
|
/* If *error_r != BRE_NONE then it is
|
|
* blo_readstreamfile_end signaling an error
|
|
* in the loading code. Otherwise it is some
|
|
* other part of the streamglue system signalling
|
|
* and error so we convert the BRS error into
|
|
* a BRE error.
|
|
*
|
|
* Does this have to be so convoluted? No.
|
|
*/
|
|
if (*error_r == BRE_NONE) {
|
|
*error_r = brs_to_bre(err);
|
|
}
|
|
|
|
break;
|
|
}
|
|
} while (fillcache(readblenfileStruct) > 0);
|
|
}
|
|
|
|
free(readblenfileStruct->readCache);
|
|
readblenfileStruct->readCache = 0;
|
|
|
|
return bfd;
|
|
}
|
|
|
|
// implementation of exported functions
|
|
|
|
BlendFileData *
|
|
BLO_readblenfilememory(
|
|
char *fromBuffer,
|
|
int fromBufferSize,
|
|
BlendReadError *error_r)
|
|
{
|
|
static char *functionality_check= "\0FUNCTIONALITY_CHECK += BLO_readblenfilememory\n";
|
|
int magiclen = strlen(headerMagic);
|
|
BlendFileData *bfd = NULL;
|
|
|
|
if (!fromBuffer) {
|
|
*error_r = BRE_UNABLE_TO_OPEN;
|
|
} else if (fromBufferSize < magiclen) {
|
|
*error_r = BRE_UNABLE_TO_READ;
|
|
} else if (strncmp(fromBuffer, headerMagic, magiclen) != 0) {
|
|
*error_r = BRE_NOT_A_BLEND;
|
|
} else if (fromBufferSize < magiclen+1) {
|
|
*error_r = BRE_UNABLE_TO_READ;
|
|
} else if (fromBuffer[magiclen] != '\r' && fromBuffer[magiclen] != '\n') {
|
|
*error_r = BRE_NOT_A_BLEND;
|
|
} else {
|
|
int crnl;
|
|
|
|
fromBuffer+= magiclen;
|
|
fromBufferSize-= magiclen;
|
|
crnl = (fromBuffer[0] == '\r');
|
|
fromBuffer++;
|
|
fromBufferSize--;
|
|
|
|
if (crnl && fromBufferSize<1) {
|
|
*error_r = BRE_UNABLE_TO_READ;
|
|
} else {
|
|
struct BLO_readblenfileStruct *readblenfileStruct = NULL;
|
|
|
|
/* skip carriage return if necessary */
|
|
if (crnl) {
|
|
fromBuffer++;
|
|
fromBufferSize--;
|
|
}
|
|
|
|
// Allocate all the stuff we need
|
|
readblenfileStruct = calloc(sizeof(struct BLO_readblenfileStruct), 1);
|
|
readblenfileStruct->fileDes = -1;
|
|
readblenfileStruct->fromBuffer = fromBuffer;
|
|
readblenfileStruct->fromBufferSize = fromBufferSize;
|
|
readblenfileStruct->read = readfrommemory;
|
|
|
|
readblenfileStruct->removeCR = crnl;
|
|
// fake filesize for now until we've
|
|
// actually read in the filesize from the header
|
|
// make sure we don't read more bytes than there
|
|
// are left to handle accoding to fromBufferSize
|
|
readblenfileStruct->leftToRead = readblenfileStruct->fromBufferSize;
|
|
|
|
bfd = readblenfilegeneric(readblenfileStruct, error_r);
|
|
|
|
free(readblenfileStruct);
|
|
readblenfileStruct = 0;
|
|
}
|
|
}
|
|
|
|
return bfd;
|
|
}
|
|
|
|
|
|
BlendFileData *
|
|
BLO_readblenfilehandle(
|
|
int fd,
|
|
BlendReadError *error_r)
|
|
{
|
|
static char *functionality_check= "\0FUNCTIONALITY_CHECK += BLO_readblenfilehandle\n";
|
|
int magiclen = strlen(headerMagic);
|
|
BlendFileData *bfd = NULL;
|
|
char tempbuffer[256];
|
|
|
|
if (fd==-1) {
|
|
*error_r = BRE_UNABLE_TO_OPEN;
|
|
} else if (read(fd, tempbuffer, magiclen) != magiclen) {
|
|
*error_r = BRE_UNABLE_TO_READ;
|
|
} else if (strncmp(tempbuffer, headerMagic, magiclen) != 0 ) {
|
|
*error_r = BRE_NOT_A_BLEND;
|
|
} else if (read(fd, tempbuffer, 1) != 1) {
|
|
*error_r = BRE_UNABLE_TO_READ;
|
|
} else if (tempbuffer[0] != '\r' && tempbuffer[0] != '\n') {
|
|
*error_r = BRE_NOT_A_BLEND;
|
|
} else {
|
|
int crnl = (tempbuffer[0] == '\r');
|
|
|
|
if (crnl && read(fd, tempbuffer, 1)!=1) {
|
|
*error_r = BRE_UNABLE_TO_READ;
|
|
} else {
|
|
struct BLO_readblenfileStruct *readblenfileStruct;
|
|
|
|
// Allocate all the stuff we need
|
|
readblenfileStruct = calloc(sizeof(struct BLO_readblenfileStruct), 1);
|
|
readblenfileStruct->fileDes = fd;
|
|
readblenfileStruct->read = readfromfilehandle;
|
|
|
|
readblenfileStruct->removeCR = crnl;
|
|
// fake filesize for now until we've
|
|
// actually read in the filesize from the header
|
|
readblenfileStruct->leftToRead = CACHESIZE;
|
|
|
|
bfd = readblenfilegeneric(readblenfileStruct, error_r);
|
|
|
|
free(readblenfileStruct);
|
|
readblenfileStruct = 0;
|
|
}
|
|
}
|
|
|
|
return bfd;
|
|
}
|
|
|
|
BlendFileData *
|
|
BLO_readblenfilename(
|
|
char *fileName,
|
|
BlendReadError *error_r)
|
|
{
|
|
static char *functionality_check= "\0FUNCTIONALITY_CHECK += BLO_readblenfilename\n";
|
|
BlendFileData *bfd = NULL;
|
|
int fd;
|
|
|
|
fd = open(fileName, O_RDONLY | O_BINARY);
|
|
if (fd==-1) {
|
|
*error_r= BRE_UNABLE_TO_OPEN;
|
|
} else {
|
|
bfd = BLO_readblenfilehandle(fd, error_r);
|
|
}
|
|
|
|
if (fd!=-1)
|
|
close(fd);
|
|
|
|
return bfd;
|
|
}
|
|
|
|
/* Runtime reading */
|
|
|
|
static int handle_read_msb_int(int handle) {
|
|
unsigned char buf[4];
|
|
|
|
if (read(handle, buf, 4)!=4)
|
|
return -1;
|
|
else
|
|
return (buf[0]<<24) + (buf[1]<<16) + (buf[2]<<8) + (buf[3]<<0);
|
|
}
|
|
|
|
int blo_is_a_runtime(char *path) {
|
|
int res= 0, fd= open(path, O_BINARY|O_RDONLY, 0);
|
|
int datastart;
|
|
char buf[8];
|
|
|
|
if (fd==-1)
|
|
goto cleanup;
|
|
|
|
lseek(fd, -12, SEEK_END);
|
|
|
|
datastart= handle_read_msb_int(fd);
|
|
if (datastart==-1)
|
|
goto cleanup;
|
|
else if (read(fd, buf, 8)!=8)
|
|
goto cleanup;
|
|
else if (memcmp(buf, "BRUNTIME", 8)!=0)
|
|
goto cleanup;
|
|
else
|
|
res= 1;
|
|
|
|
cleanup:
|
|
if (fd!=-1)
|
|
close(fd);
|
|
|
|
return res;
|
|
}
|
|
|
|
BlendFileData *
|
|
blo_read_runtime(
|
|
char *path,
|
|
BlendReadError *error_r)
|
|
{
|
|
static char *functionality_check= "\0FUNCTIONALITY_CHECK += BLO_read_runtime\n";
|
|
BlendFileData *bfd= NULL;
|
|
int fd, datastart;
|
|
char buf[8];
|
|
|
|
fd= open(path, O_BINARY|O_RDONLY, 0);
|
|
if (fd==-1) {
|
|
*error_r= BRE_UNABLE_TO_OPEN;
|
|
goto cleanup;
|
|
}
|
|
|
|
lseek(fd, -12, SEEK_END);
|
|
|
|
datastart= handle_read_msb_int(fd);
|
|
if (datastart==-1) {
|
|
*error_r= BRE_UNABLE_TO_READ;
|
|
goto cleanup;
|
|
} else if (read(fd, buf, 8)!=8) {
|
|
*error_r= BRE_UNABLE_TO_READ;
|
|
goto cleanup;
|
|
} else if (memcmp(buf, "BRUNTIME", 8)!=0) {
|
|
*error_r= BRE_NOT_A_BLEND;
|
|
goto cleanup;
|
|
} else {
|
|
lseek(fd, datastart, SEEK_SET);
|
|
bfd= BLO_readblenfilehandle(fd, error_r);
|
|
}
|
|
|
|
cleanup:
|
|
if (fd!=-1)
|
|
close(fd);
|
|
|
|
return bfd;
|
|
}
|
|
|
|
#if 0
|
|
static char *brs_error_to_string(int err) {
|
|
int errFunction = BRS_GETFUNCTION(err);
|
|
int errGeneric = BRS_GETGENERR(err);
|
|
int errSpecific = BRS_GETSPECERR(err);
|
|
char *errFunctionStrings[] = {
|
|
"",
|
|
"The read stream",
|
|
"The read stream loopback",
|
|
"The key store",
|
|
"The file reading",
|
|
"Decompressing the file",
|
|
"Decrypting the file",
|
|
"Verifying the signature"};
|
|
char *errGenericStrings[] = {
|
|
"",
|
|
"generated an out of memory error",
|
|
"bumped on an internal programming error",
|
|
"did not recognize this as a blend file",
|
|
"failed a blend file check",
|
|
"bumped on corrupted data",
|
|
"needed the rest of the blend file",
|
|
"is not allowed in this version"};
|
|
char *errReadStreamGlueStrings[] = {
|
|
"",
|
|
"does not know how to proceed"};
|
|
char *errReadStreamFileStrings[] = {
|
|
"",
|
|
"did not recognize this as a blend file",
|
|
"was busted on a read error"};
|
|
char *errInflateStrings[] = {
|
|
"",
|
|
"bumped on a decompress error"};
|
|
char *errDecryptStrings[] = {
|
|
"",
|
|
"could not make a new key",
|
|
"bumped on a decrypt error",
|
|
"was not allowed. This blend file is not made by you."};
|
|
char *errVerifyStrings[] = {
|
|
"",
|
|
"could not make a new key",
|
|
"failed"};
|
|
char *errFunctionString= errFunctionStrings[errFunction];
|
|
char *errExtraString= "";
|
|
char *errString;
|
|
|
|
if (errGeneric) {
|
|
errExtraString= errGenericStrings[errGeneric];
|
|
} else if (errSpecific) {
|
|
switch (errFunction) {
|
|
case BRS_READSTREAMGLUE:
|
|
errExtraString= errReadStreamGlueStrings[errSpecific];
|
|
break;
|
|
case BRS_READSTREAMFILE:
|
|
errExtraString= errReadStreamFileStrings[errSpecific];
|
|
break;
|
|
case BRS_INFLATE:
|
|
errExtraString= errInflateStrings[errSpecific];
|
|
break;
|
|
case BRS_DECRYPT:
|
|
errExtraString= errDecryptStrings[errSpecific];
|
|
break;
|
|
case BRS_VERIFY:
|
|
errExtraString= errVerifyStrings[errSpecific];
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
errString= MEM_mallocN(strlen(errFunctionString) + 1 + strlen(errExtraString) + 1);
|
|
sprintf(errString, "%s %s", errFunctionString, errExtraString);
|
|
|
|
return errString;
|
|
}
|
|
#endif
|