/* * $Id$ * * ***** BEGIN GPL 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. * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * ***** END GPL LICENSE BLOCK ***** */ /** \file blender/blenkernel/intern/customdata_file.c * \ingroup bke */ #include #include #include #include "MEM_guardedalloc.h" #include "BLI_fileops.h" #include "BLI_string.h" #include "BLI_utildefines.h" #include "BKE_customdata_file.h" #include "BKE_global.h" /************************* File Format Definitions ***************************/ #define CDF_ENDIAN_LITTLE 0 #define CDF_ENDIAN_BIG 1 #define CDF_DATA_FLOAT 0 typedef struct CDataFileHeader { char ID[4]; /* "BCDF" */ char endian; /* little, big */ char version; /* non-compatible versions */ char subversion; /* compatible sub versions */ char pad; /* padding */ int structbytes; /* size of this struct in bytes */ int type; /* image, mesh */ int totlayer; /* number of layers in the file */ } CDataFileHeader; typedef struct CDataFileImageHeader { int structbytes; /* size of this struct in bytes */ int width; /* image width */ int height; /* image height */ int tile_size; /* tile size (required power of 2) */ } CDataFileImageHeader; typedef struct CDataFileMeshHeader { int structbytes; /* size of this struct in bytes */ } CDataFileMeshHeader; struct CDataFileLayer { int structbytes; /* size of this struct in bytes */ int datatype; /* only float for now */ uint64_t datasize; /* size of data in layer */ int type; /* layer type */ char name[CDF_LAYER_NAME_MAX]; /* layer name */ }; /**************************** Other Definitions ******************************/ #define CDF_VERSION 0 #define CDF_SUBVERSION 0 #define CDF_TILE_SIZE 64 struct CDataFile { int type; CDataFileHeader header; union { CDataFileImageHeader image; CDataFileMeshHeader mesh; } btype; CDataFileLayer *layer; int totlayer; FILE *readf; FILE *writef; int switchendian; size_t dataoffset; }; /********************************* Create/Free *******************************/ static int cdf_endian(void) { if(ENDIAN_ORDER == L_ENDIAN) return CDF_ENDIAN_LITTLE; else return CDF_ENDIAN_BIG; } /*static int cdf_data_type_size(int datatype) { if(datatype == CDF_DATA_FLOAT) return sizeof(float); return 0; }*/ CDataFile *cdf_create(int type) { CDataFile *cdf= MEM_callocN(sizeof(CDataFile), "CDataFile"); cdf->type= type; return cdf; } void cdf_free(CDataFile *cdf) { cdf_read_close(cdf); cdf_write_close(cdf); if(cdf->layer) MEM_freeN(cdf->layer); MEM_freeN(cdf); } /********************************* Read/Write ********************************/ static int cdf_read_header(CDataFile *cdf) { CDataFileHeader *header; CDataFileImageHeader *image; CDataFileMeshHeader *mesh; CDataFileLayer *layer; FILE *f= cdf->readf; size_t offset = 0; int a; header= &cdf->header; if(!fread(header, sizeof(CDataFileHeader), 1, cdf->readf)) return 0; if(memcmp(header->ID, "BCDF", sizeof(header->ID)) != 0) return 0; if(header->version > CDF_VERSION) return 0; cdf->switchendian= header->endian != cdf_endian(); header->endian= cdf_endian(); if(cdf->switchendian) { SWITCH_INT(header->type); SWITCH_INT(header->totlayer); SWITCH_INT(header->structbytes); } if(!ELEM(header->type, CDF_TYPE_IMAGE, CDF_TYPE_MESH)) return 0; offset += header->structbytes; header->structbytes= sizeof(CDataFileHeader); if(fseek(f, offset, SEEK_SET) != 0) return 0; if(header->type == CDF_TYPE_IMAGE) { image= &cdf->btype.image; if(!fread(image, sizeof(CDataFileImageHeader), 1, f)) return 0; if(cdf->switchendian) { SWITCH_INT(image->width); SWITCH_INT(image->height); SWITCH_INT(image->tile_size); SWITCH_INT(image->structbytes); } offset += image->structbytes; image->structbytes= sizeof(CDataFileImageHeader); } else if(header->type == CDF_TYPE_MESH) { mesh= &cdf->btype.mesh; if(!fread(mesh, sizeof(CDataFileMeshHeader), 1, f)) return 0; if(cdf->switchendian) SWITCH_INT(mesh->structbytes); offset += mesh->structbytes; mesh->structbytes= sizeof(CDataFileMeshHeader); } if(fseek(f, offset, SEEK_SET) != 0) return 0; cdf->layer= MEM_callocN(sizeof(CDataFileLayer)*header->totlayer, "CDataFileLayer"); cdf->totlayer= header->totlayer; for(a=0; atotlayer; a++) { layer= &cdf->layer[a]; if(!fread(layer, sizeof(CDataFileLayer), 1, f)) return 0; if(cdf->switchendian) { SWITCH_INT(layer->type); SWITCH_INT(layer->datatype); SWITCH_INT64(layer->datasize); SWITCH_INT(layer->structbytes); } if(layer->datatype != CDF_DATA_FLOAT) return 0; offset += layer->structbytes; layer->structbytes= sizeof(CDataFileLayer); if(fseek(f, offset, SEEK_SET) != 0) return 0; } cdf->dataoffset= offset; return 1; } static int cdf_write_header(CDataFile *cdf) { CDataFileHeader *header; CDataFileImageHeader *image; CDataFileMeshHeader *mesh; CDataFileLayer *layer; FILE *f= cdf->writef; int a; header= &cdf->header; if(!fwrite(header, sizeof(CDataFileHeader), 1, f)) return 0; if(header->type == CDF_TYPE_IMAGE) { image= &cdf->btype.image; if(!fwrite(image, sizeof(CDataFileImageHeader), 1, f)) return 0; } else if(header->type == CDF_TYPE_MESH) { mesh= &cdf->btype.mesh; if(!fwrite(mesh, sizeof(CDataFileMeshHeader), 1, f)) return 0; } for(a=0; atotlayer; a++) { layer= &cdf->layer[a]; if(!fwrite(layer, sizeof(CDataFileLayer), 1, f)) return 0; } return 1; } int cdf_read_open(CDataFile *cdf, char *filename) { FILE *f; f= fopen(filename, "rb"); if(!f) return 0; cdf->readf= f; if(!cdf_read_header(cdf)) { cdf_read_close(cdf); return 0; } if(cdf->header.type != cdf->type) { cdf_read_close(cdf); return 0; } return 1; } int cdf_read_layer(CDataFile *cdf, CDataFileLayer *blay) { size_t offset; int a; /* seek to right location in file */ offset= cdf->dataoffset; for(a=0; atotlayer; a++) { if(&cdf->layer[a] == blay) break; else offset += cdf->layer[a].datasize; } return (fseek(cdf->readf, offset, SEEK_SET) == 0); } int cdf_read_data(CDataFile *cdf, unsigned int size, void *data) { float *fdata; unsigned int a; /* read data */ if(!fread(data, size, 1, cdf->readf)) return 0; /* switch endian if necessary */ if(cdf->switchendian) { fdata= data; for(a=0; areadf) { fclose(cdf->readf); cdf->readf= NULL; } } int cdf_write_open(CDataFile *cdf, char *filename) { CDataFileHeader *header; CDataFileImageHeader *image; CDataFileMeshHeader *mesh; FILE *f; f= fopen(filename, "wb"); if(!f) return 0; cdf->writef= f; /* fill header */ header= &cdf->header; /* strcpy(, "BCDF"); // terminator out of range */ header->ID[0]= 'B'; header->ID[1]= 'C'; header->ID[2]= 'D'; header->ID[3]= 'F'; header->endian= cdf_endian(); header->version= CDF_VERSION; header->subversion= CDF_SUBVERSION; header->structbytes= sizeof(CDataFileHeader); header->type= cdf->type; header->totlayer= cdf->totlayer; if(cdf->type == CDF_TYPE_IMAGE) { /* fill image header */ image= &cdf->btype.image; image->structbytes= sizeof(CDataFileImageHeader); image->tile_size= CDF_TILE_SIZE; } else if(cdf->type == CDF_TYPE_MESH) { /* fill mesh header */ mesh= &cdf->btype.mesh; mesh->structbytes= sizeof(CDataFileMeshHeader); } cdf_write_header(cdf); return 1; } int cdf_write_layer(CDataFile *UNUSED(cdf), CDataFileLayer *UNUSED(blay)) { return 1; } int cdf_write_data(CDataFile *cdf, unsigned int size, void *data) { /* write data */ if(!fwrite(data, size, 1, cdf->writef)) return 0; return 1; } void cdf_write_close(CDataFile *cdf) { if(cdf->writef) { fclose(cdf->writef); cdf->writef= NULL; } } void cdf_remove(char *filename) { BLI_delete(filename, 0, 0); } /********************************** Layers ***********************************/ CDataFileLayer *cdf_layer_find(CDataFile *cdf, int type, char *name) { CDataFileLayer *layer; int a; for(a=0; atotlayer; a++) { layer= &cdf->layer[a]; if(layer->type == type && strcmp(layer->name, name) == 0) return layer; } return NULL; } CDataFileLayer *cdf_layer_add(CDataFile *cdf, int type, char *name, size_t datasize) { CDataFileLayer *newlayer, *layer; /* expand array */ newlayer= MEM_callocN(sizeof(CDataFileLayer)*(cdf->totlayer+1), "CDataFileLayer"); memcpy(newlayer, cdf->layer, sizeof(CDataFileLayer)*cdf->totlayer); cdf->layer= newlayer; cdf->totlayer++; /* fill in new layer */ layer= &cdf->layer[cdf->totlayer-1]; layer->structbytes= sizeof(CDataFileLayer); layer->datatype= CDF_DATA_FLOAT; layer->datasize= datasize; layer->type= type; BLI_strncpy(layer->name, name, CDF_LAYER_NAME_MAX); return layer; }