Blender  V2.59
customdata_file.c
Go to the documentation of this file.
00001 /*
00002  * $Id: customdata_file.c 35247 2011-02-27 20:40:57Z jesterking $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * ***** END GPL LICENSE BLOCK *****
00021  */
00022 
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <string.h>
00031 
00032 #include "MEM_guardedalloc.h"
00033 
00034 #include "BLI_fileops.h"
00035 #include "BLI_string.h"
00036 #include "BLI_utildefines.h"
00037 
00038 #include "BKE_customdata_file.h"
00039 #include "BKE_global.h"
00040 
00041 
00042 /************************* File Format Definitions ***************************/
00043 
00044 #define CDF_ENDIAN_LITTLE       0
00045 #define CDF_ENDIAN_BIG          1
00046 
00047 #define CDF_DATA_FLOAT  0
00048 
00049 typedef struct CDataFileHeader {
00050         char ID[4];                                     /* "BCDF" */
00051         char endian;                            /* little, big */
00052         char version;                           /* non-compatible versions */
00053         char subversion;                        /* compatible sub versions */
00054         char pad;                                       /* padding */
00055 
00056         int structbytes;                        /* size of this struct in bytes */
00057         int type;                                       /* image, mesh */
00058         int totlayer;                           /* number of layers in the file */
00059 } CDataFileHeader;
00060 
00061 typedef struct CDataFileImageHeader {
00062         int structbytes;                        /* size of this struct in bytes */
00063         int width;                                      /* image width */
00064         int height;                                     /* image height */
00065         int tile_size;                          /* tile size (required power of 2) */
00066 } CDataFileImageHeader;
00067 
00068 typedef struct CDataFileMeshHeader {
00069         int structbytes;                        /* size of this struct in bytes */
00070 } CDataFileMeshHeader;
00071 
00072 struct CDataFileLayer {
00073         int structbytes;                                /* size of this struct in bytes */
00074         int datatype;                                   /* only float for now */
00075         uint64_t datasize;                              /* size of data in layer */
00076         int type;                                               /* layer type */
00077         char name[CDF_LAYER_NAME_MAX];  /* layer name */
00078 };
00079 
00080 /**************************** Other Definitions ******************************/
00081 
00082 #define CDF_VERSION                     0
00083 #define CDF_SUBVERSION          0
00084 #define CDF_TILE_SIZE           64
00085 
00086 struct CDataFile {
00087         int type;
00088 
00089         CDataFileHeader header;
00090         union {
00091                 CDataFileImageHeader image;
00092                 CDataFileMeshHeader mesh;
00093         } btype;
00094 
00095         CDataFileLayer *layer;
00096         int totlayer;
00097 
00098         FILE *readf;
00099         FILE *writef;
00100         int switchendian;
00101         size_t dataoffset;
00102 };
00103 
00104 /********************************* Create/Free *******************************/
00105 
00106 static int cdf_endian(void)
00107 {
00108         if(ENDIAN_ORDER == L_ENDIAN)
00109                 return CDF_ENDIAN_LITTLE;
00110         else
00111                 return CDF_ENDIAN_BIG;
00112 }
00113 
00114 /*static int cdf_data_type_size(int datatype)
00115 {
00116         if(datatype == CDF_DATA_FLOAT)
00117                 return sizeof(float);
00118         
00119         return 0;
00120 }*/
00121 
00122 CDataFile *cdf_create(int type)
00123 {
00124         CDataFile *cdf= MEM_callocN(sizeof(CDataFile), "CDataFile");
00125 
00126         cdf->type= type;
00127 
00128         return cdf;
00129 }
00130 
00131 void cdf_free(CDataFile *cdf)
00132 {
00133         cdf_read_close(cdf);
00134         cdf_write_close(cdf);
00135 
00136         if(cdf->layer)
00137                 MEM_freeN(cdf->layer);
00138 
00139         MEM_freeN(cdf);
00140 }
00141 
00142 /********************************* Read/Write ********************************/
00143 
00144 static int cdf_read_header(CDataFile *cdf)
00145 {
00146         CDataFileHeader *header;
00147         CDataFileImageHeader *image;
00148         CDataFileMeshHeader *mesh;
00149         CDataFileLayer *layer;
00150         FILE *f= cdf->readf;
00151         size_t offset = 0;
00152         int a;
00153 
00154         header= &cdf->header;
00155 
00156         if(!fread(header, sizeof(CDataFileHeader), 1, cdf->readf))
00157                 return 0;
00158         
00159         if(memcmp(header->ID, "BCDF", sizeof(header->ID)) != 0)
00160                 return 0;
00161         if(header->version > CDF_VERSION)
00162                 return 0;
00163 
00164         cdf->switchendian= header->endian != cdf_endian();
00165         header->endian= cdf_endian();
00166 
00167         if(cdf->switchendian) {
00168                 SWITCH_INT(header->type);
00169                 SWITCH_INT(header->totlayer);
00170                 SWITCH_INT(header->structbytes);
00171         }
00172 
00173         if(!ELEM(header->type, CDF_TYPE_IMAGE, CDF_TYPE_MESH))
00174                 return 0;
00175 
00176         offset += header->structbytes;
00177         header->structbytes= sizeof(CDataFileHeader);
00178 
00179         if(fseek(f, offset, SEEK_SET) != 0)
00180                 return 0;
00181         
00182         if(header->type == CDF_TYPE_IMAGE) {
00183                 image= &cdf->btype.image;
00184                 if(!fread(image, sizeof(CDataFileImageHeader), 1, f))
00185                         return 0;
00186 
00187                 if(cdf->switchendian) {
00188                         SWITCH_INT(image->width);
00189                         SWITCH_INT(image->height);
00190                         SWITCH_INT(image->tile_size);
00191                         SWITCH_INT(image->structbytes);
00192                 }
00193 
00194                 offset += image->structbytes;
00195                 image->structbytes= sizeof(CDataFileImageHeader);
00196         }
00197         else if(header->type == CDF_TYPE_MESH) {
00198                 mesh= &cdf->btype.mesh;
00199                 if(!fread(mesh, sizeof(CDataFileMeshHeader), 1, f))
00200                         return 0;
00201 
00202                 if(cdf->switchendian)
00203                         SWITCH_INT(mesh->structbytes);
00204 
00205                 offset += mesh->structbytes;
00206                 mesh->structbytes= sizeof(CDataFileMeshHeader);
00207         }
00208 
00209         if(fseek(f, offset, SEEK_SET) != 0)
00210                 return 0;
00211 
00212         cdf->layer= MEM_callocN(sizeof(CDataFileLayer)*header->totlayer, "CDataFileLayer");
00213         cdf->totlayer= header->totlayer;
00214 
00215         for(a=0; a<header->totlayer; a++) {
00216                 layer= &cdf->layer[a];
00217 
00218                 if(!fread(layer, sizeof(CDataFileLayer), 1, f))
00219                         return 0;
00220 
00221                 if(cdf->switchendian) {
00222                         SWITCH_INT(layer->type);
00223                         SWITCH_INT(layer->datatype);
00224                         SWITCH_INT64(layer->datasize);
00225                         SWITCH_INT(layer->structbytes);
00226                 }
00227 
00228                 if(layer->datatype != CDF_DATA_FLOAT)
00229                         return 0;
00230 
00231                 offset += layer->structbytes;
00232                 layer->structbytes= sizeof(CDataFileLayer);
00233 
00234                 if(fseek(f, offset, SEEK_SET) != 0)
00235                         return 0;
00236         }
00237 
00238         cdf->dataoffset= offset;
00239 
00240         return 1;
00241 }
00242 
00243 static int cdf_write_header(CDataFile *cdf)
00244 {
00245         CDataFileHeader *header;
00246         CDataFileImageHeader *image;
00247         CDataFileMeshHeader *mesh;
00248         CDataFileLayer *layer;
00249         FILE *f= cdf->writef;
00250         int a;
00251 
00252         header= &cdf->header;
00253 
00254         if(!fwrite(header, sizeof(CDataFileHeader), 1, f))
00255                 return 0;
00256         
00257         if(header->type == CDF_TYPE_IMAGE) {
00258                 image= &cdf->btype.image;
00259                 if(!fwrite(image, sizeof(CDataFileImageHeader), 1, f))
00260                         return 0;
00261         }
00262         else if(header->type == CDF_TYPE_MESH) {
00263                 mesh= &cdf->btype.mesh;
00264                 if(!fwrite(mesh, sizeof(CDataFileMeshHeader), 1, f))
00265                         return 0;
00266         }
00267 
00268         for(a=0; a<header->totlayer; a++) {
00269                 layer= &cdf->layer[a];
00270 
00271                 if(!fwrite(layer, sizeof(CDataFileLayer), 1, f))
00272                         return 0;
00273         }
00274 
00275         return 1;
00276 }
00277 
00278 int cdf_read_open(CDataFile *cdf, char *filename)
00279 {
00280         FILE *f;
00281 
00282         f= fopen(filename, "rb");
00283         if(!f)
00284                 return 0;
00285         
00286         cdf->readf= f;
00287 
00288         if(!cdf_read_header(cdf)) {
00289                 cdf_read_close(cdf);
00290                 return 0;
00291         }
00292 
00293         if(cdf->header.type != cdf->type) {
00294                 cdf_read_close(cdf);
00295                 return 0;
00296         }
00297 
00298         return 1;
00299 }
00300 
00301 int cdf_read_layer(CDataFile *cdf, CDataFileLayer *blay)
00302 {
00303         size_t offset;
00304         int a;
00305 
00306         /* seek to right location in file */
00307         offset= cdf->dataoffset;
00308         for(a=0; a<cdf->totlayer; a++) {
00309                 if(&cdf->layer[a] == blay)
00310                         break;
00311                 else
00312                         offset += cdf->layer[a].datasize;
00313         }
00314 
00315         return (fseek(cdf->readf, offset, SEEK_SET) == 0);
00316 }
00317 
00318 int cdf_read_data(CDataFile *cdf, unsigned int size, void *data)
00319 {
00320         float *fdata;
00321         unsigned int a;
00322 
00323         /* read data */
00324         if(!fread(data, size, 1, cdf->readf))
00325                 return 0;
00326 
00327         /* switch endian if necessary */
00328         if(cdf->switchendian) {
00329                 fdata= data;
00330 
00331                 for(a=0; a<size/sizeof(float); a++)
00332                         SWITCH_INT(fdata[a])
00333         }
00334 
00335         return 1;
00336 }
00337 
00338 void cdf_read_close(CDataFile *cdf)
00339 {
00340         if(cdf->readf) {
00341                 fclose(cdf->readf);
00342                 cdf->readf= NULL;
00343         }
00344 }
00345 
00346 int cdf_write_open(CDataFile *cdf, char *filename)
00347 {
00348         CDataFileHeader *header;
00349         CDataFileImageHeader *image;
00350         CDataFileMeshHeader *mesh;
00351         FILE *f;
00352 
00353         f= fopen(filename, "wb");
00354         if(!f)
00355                 return 0;
00356         
00357         cdf->writef= f;
00358 
00359         /* fill header */
00360         header= &cdf->header;
00361         /* strcpy(, "BCDF"); // terminator out of range */
00362         header->ID[0]= 'B'; header->ID[1]= 'C'; header->ID[2]= 'D'; header->ID[3]= 'F';
00363         header->endian= cdf_endian();
00364         header->version= CDF_VERSION;
00365         header->subversion= CDF_SUBVERSION;
00366 
00367         header->structbytes= sizeof(CDataFileHeader);
00368         header->type= cdf->type;
00369         header->totlayer= cdf->totlayer;
00370 
00371         if(cdf->type == CDF_TYPE_IMAGE) {
00372                 /* fill image header */
00373                 image= &cdf->btype.image;
00374                 image->structbytes= sizeof(CDataFileImageHeader);
00375                 image->tile_size= CDF_TILE_SIZE;
00376         }
00377         else if(cdf->type == CDF_TYPE_MESH) {
00378                 /* fill mesh header */
00379                 mesh= &cdf->btype.mesh;
00380                 mesh->structbytes= sizeof(CDataFileMeshHeader);
00381         }
00382 
00383         cdf_write_header(cdf);
00384 
00385         return 1;
00386 }
00387 
00388 int cdf_write_layer(CDataFile *UNUSED(cdf), CDataFileLayer *UNUSED(blay))
00389 {
00390         return 1;
00391 }
00392 
00393 int cdf_write_data(CDataFile *cdf, unsigned int size, void *data)
00394 {
00395         /* write data */
00396         if(!fwrite(data, size, 1, cdf->writef))
00397                 return 0;
00398 
00399         return 1;
00400 }
00401 
00402 void cdf_write_close(CDataFile *cdf)
00403 {
00404         if(cdf->writef) {
00405                 fclose(cdf->writef);
00406                 cdf->writef= NULL;
00407         }
00408 }
00409 
00410 void cdf_remove(char *filename)
00411 {
00412         BLI_delete(filename, 0, 0);
00413 }
00414 
00415 /********************************** Layers ***********************************/
00416 
00417 CDataFileLayer *cdf_layer_find(CDataFile *cdf, int type, char *name)
00418 {
00419         CDataFileLayer *layer;
00420         int a;
00421 
00422         for(a=0; a<cdf->totlayer; a++) {
00423                 layer= &cdf->layer[a];
00424 
00425                 if(layer->type == type && strcmp(layer->name, name) == 0)
00426                         return layer;
00427         }
00428         
00429         return NULL;
00430 }
00431 
00432 CDataFileLayer *cdf_layer_add(CDataFile *cdf, int type, char *name, size_t datasize)
00433 {
00434         CDataFileLayer *newlayer, *layer;
00435 
00436         /* expand array */
00437         newlayer= MEM_callocN(sizeof(CDataFileLayer)*(cdf->totlayer+1), "CDataFileLayer");
00438         memcpy(newlayer, cdf->layer, sizeof(CDataFileLayer)*cdf->totlayer);
00439         cdf->layer= newlayer;
00440 
00441         cdf->totlayer++;
00442 
00443         /* fill in new layer */
00444         layer= &cdf->layer[cdf->totlayer-1];
00445         layer->structbytes= sizeof(CDataFileLayer);
00446         layer->datatype= CDF_DATA_FLOAT;
00447         layer->datasize= datasize;
00448         layer->type= type;
00449         BLI_strncpy(layer->name, name, CDF_LAYER_NAME_MAX);
00450 
00451         return layer;
00452 }
00453