1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 /** \file
18  * \ingroup bke
19  */
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include "MEM_guardedalloc.h"
26 
27 #include "BLI_endian_switch.h"
28 #include "BLI_fileops.h"
29 #include "BLI_string.h"
30 #include "BLI_utildefines.h"
31 
32 #include "BKE_customdata_file.h"
33 #include "BKE_global.h"
34 
35 /************************* File Format Definitions ***************************/
36 
37 #define CDF_ENDIAN_LITTLE 0
38 #define CDF_ENDIAN_BIG 1
39 
40 #define CDF_DATA_FLOAT 0
41 
42 typedef struct CDataFileHeader {
43   char ID[4];      /* "BCDF" */
44   char endian;     /* little, big */
45   char version;    /* non-compatible versions */
46   char subversion; /* compatible sub versions */
47   char pad;        /* padding */
48 
49   int structbytes; /* size of this struct in bytes */
50   int type;        /* image, mesh */
51   int totlayer;    /* number of layers in the file */
52 } CDataFileHeader;
53 
54 typedef struct CDataFileImageHeader {
55   int structbytes; /* size of this struct in bytes */
56   int width;       /* image width */
57   int height;      /* image height */
58   int tile_size;   /* tile size (required power of 2) */
59 } CDataFileImageHeader;
60 
61 typedef struct CDataFileMeshHeader {
62   int structbytes; /* size of this struct in bytes */
63 } CDataFileMeshHeader;
64 
65 struct CDataFileLayer {
66   int structbytes;               /* size of this struct in bytes */
67   int datatype;                  /* only float for now */
68   uint64_t datasize;             /* size of data in layer */
69   int type;                      /* layer type */
70   char name[CDF_LAYER_NAME_MAX]; /* layer name */
71 };
72 
73 /**************************** Other Definitions ******************************/
74 
75 #define CDF_VERSION 0
76 #define CDF_SUBVERSION 0
77 #define CDF_TILE_SIZE 64
78 
79 struct CDataFile {
80   int type;
81 
82   CDataFileHeader header;
83   union {
84     CDataFileImageHeader image;
85     CDataFileMeshHeader mesh;
86   } btype;
87 
88   CDataFileLayer *layer;
89   int totlayer;
90 
91   FILE *readf;
92   FILE *writef;
93   int switchendian;
94   size_t dataoffset;
95 };
96 
97 /********************************* Create/Free *******************************/
98 
cdf_endian(void)99 static int cdf_endian(void)
100 {
101   if (ENDIAN_ORDER == L_ENDIAN) {
102     return CDF_ENDIAN_LITTLE;
103   }
104 
105   return CDF_ENDIAN_BIG;
106 }
107 
cdf_create(int type)108 CDataFile *cdf_create(int type)
109 {
110   CDataFile *cdf = MEM_callocN(sizeof(CDataFile), "CDataFile");
111 
112   cdf->type = type;
113 
114   return cdf;
115 }
116 
cdf_free(CDataFile * cdf)117 void cdf_free(CDataFile *cdf)
118 {
119   cdf_read_close(cdf);
120   cdf_write_close(cdf);
121 
122   if (cdf->layer) {
123     MEM_freeN(cdf->layer);
124   }
125 
126   MEM_freeN(cdf);
127 }
128 
129 /********************************* Read/Write ********************************/
130 
cdf_read_header(CDataFile * cdf)131 static bool cdf_read_header(CDataFile *cdf)
132 {
133   CDataFileHeader *header;
134   CDataFileImageHeader *image;
135   CDataFileMeshHeader *mesh;
136   CDataFileLayer *layer;
137   FILE *f = cdf->readf;
138   size_t offset = 0;
139   int a;
140 
141   header = &cdf->header;
142 
143   if (!fread(header, sizeof(CDataFileHeader), 1, cdf->readf)) {
144     return false;
145   }
146 
147   if (memcmp(header->ID, "BCDF", sizeof(header->ID)) != 0) {
148     return false;
149   }
150   if (header->version > CDF_VERSION) {
151     return false;
152   }
153 
154   cdf->switchendian = header->endian != cdf_endian();
155   header->endian = cdf_endian();
156 
157   if (cdf->switchendian) {
158     BLI_endian_switch_int32(&header->type);
159     BLI_endian_switch_int32(&header->totlayer);
160     BLI_endian_switch_int32(&header->structbytes);
161   }
162 
163   if (!ELEM(header->type, CDF_TYPE_IMAGE, CDF_TYPE_MESH)) {
164     return false;
165   }
166 
167   offset += header->structbytes;
168   header->structbytes = sizeof(CDataFileHeader);
169 
170   if (fseek(f, offset, SEEK_SET) != 0) {
171     return false;
172   }
173 
174   if (header->type == CDF_TYPE_IMAGE) {
175     image = &cdf->btype.image;
176     if (!fread(image, sizeof(CDataFileImageHeader), 1, f)) {
177       return false;
178     }
179 
180     if (cdf->switchendian) {
181       BLI_endian_switch_int32(&image->width);
182       BLI_endian_switch_int32(&image->height);
183       BLI_endian_switch_int32(&image->tile_size);
184       BLI_endian_switch_int32(&image->structbytes);
185     }
186 
187     offset += image->structbytes;
188     image->structbytes = sizeof(CDataFileImageHeader);
189   }
190   else if (header->type == CDF_TYPE_MESH) {
191     mesh = &cdf->btype.mesh;
192     if (!fread(mesh, sizeof(CDataFileMeshHeader), 1, f)) {
193       return false;
194     }
195 
196     if (cdf->switchendian) {
197       BLI_endian_switch_int32(&mesh->structbytes);
198     }
199 
200     offset += mesh->structbytes;
201     mesh->structbytes = sizeof(CDataFileMeshHeader);
202   }
203 
204   if (fseek(f, offset, SEEK_SET) != 0) {
205     return false;
206   }
207 
208   cdf->layer = MEM_calloc_arrayN(header->totlayer, sizeof(CDataFileLayer), "CDataFileLayer");
209   cdf->totlayer = header->totlayer;
210 
211   if (!cdf->layer) {
212     return false;
213   }
214 
215   for (a = 0; a < header->totlayer; a++) {
216     layer = &cdf->layer[a];
217 
218     if (!fread(layer, sizeof(CDataFileLayer), 1, f)) {
219       return false;
220     }
221 
222     if (cdf->switchendian) {
223       BLI_endian_switch_int32(&layer->type);
224       BLI_endian_switch_int32(&layer->datatype);
225       BLI_endian_switch_uint64(&layer->datasize);
226       BLI_endian_switch_int32(&layer->structbytes);
227     }
228 
229     if (layer->datatype != CDF_DATA_FLOAT) {
230       return false;
231     }
232 
233     offset += layer->structbytes;
234     layer->structbytes = sizeof(CDataFileLayer);
235 
236     if (fseek(f, offset, SEEK_SET) != 0) {
237       return false;
238     }
239   }
240 
241   cdf->dataoffset = offset;
242 
243   return true;
244 }
245 
cdf_write_header(CDataFile * cdf)246 static bool cdf_write_header(CDataFile *cdf)
247 {
248   CDataFileHeader *header;
249   CDataFileImageHeader *image;
250   CDataFileMeshHeader *mesh;
251   CDataFileLayer *layer;
252   FILE *f = cdf->writef;
253   int a;
254 
255   header = &cdf->header;
256 
257   if (!fwrite(header, sizeof(CDataFileHeader), 1, f)) {
258     return false;
259   }
260 
261   if (header->type == CDF_TYPE_IMAGE) {
262     image = &cdf->btype.image;
263     if (!fwrite(image, sizeof(CDataFileImageHeader), 1, f)) {
264       return false;
265     }
266   }
267   else if (header->type == CDF_TYPE_MESH) {
268     mesh = &cdf->btype.mesh;
269     if (!fwrite(mesh, sizeof(CDataFileMeshHeader), 1, f)) {
270       return false;
271     }
272   }
273 
274   for (a = 0; a < header->totlayer; a++) {
275     layer = &cdf->layer[a];
276 
277     if (!fwrite(layer, sizeof(CDataFileLayer), 1, f)) {
278       return false;
279     }
280   }
281 
282   return true;
283 }
284 
cdf_read_open(CDataFile * cdf,const char * filename)285 bool cdf_read_open(CDataFile *cdf, const char *filename)
286 {
287   FILE *f;
288 
289   f = BLI_fopen(filename, "rb");
290   if (!f) {
291     return false;
292   }
293 
294   cdf->readf = f;
295 
296   if (!cdf_read_header(cdf)) {
297     cdf_read_close(cdf);
298     return false;
299   }
300 
301   if (cdf->header.type != cdf->type) {
302     cdf_read_close(cdf);
303     return false;
304   }
305 
306   return true;
307 }
308 
cdf_read_layer(CDataFile * cdf,CDataFileLayer * blay)309 bool cdf_read_layer(CDataFile *cdf, CDataFileLayer *blay)
310 {
311   size_t offset;
312   int a;
313 
314   /* seek to right location in file */
315   offset = cdf->dataoffset;
316   for (a = 0; a < cdf->totlayer; a++) {
317     if (&cdf->layer[a] == blay) {
318       break;
319     }
320 
321     offset += cdf->layer[a].datasize;
322   }
323 
324   return (fseek(cdf->readf, offset, SEEK_SET) == 0);
325 }
326 
cdf_read_data(CDataFile * cdf,unsigned int size,void * data)327 bool cdf_read_data(CDataFile *cdf, unsigned int size, void *data)
328 {
329   /* read data */
330   if (!fread(data, size, 1, cdf->readf)) {
331     return false;
332   }
333 
334   /* switch endian if necessary */
335   if (cdf->switchendian) {
336     BLI_endian_switch_float_array(data, size / sizeof(float));
337   }
338 
339   return true;
340 }
341 
cdf_read_close(CDataFile * cdf)342 void cdf_read_close(CDataFile *cdf)
343 {
344   if (cdf->readf) {
345     fclose(cdf->readf);
346     cdf->readf = NULL;
347   }
348 }
349 
cdf_write_open(CDataFile * cdf,const char * filename)350 bool cdf_write_open(CDataFile *cdf, const char *filename)
351 {
352   CDataFileHeader *header;
353   CDataFileImageHeader *image;
354   CDataFileMeshHeader *mesh;
355   FILE *f;
356 
357   f = BLI_fopen(filename, "wb");
358   if (!f) {
359     return false;
360   }
361 
362   cdf->writef = f;
363 
364   /* fill header */
365   header = &cdf->header;
366   /* strcpy(, "BCDF"); // terminator out of range */
367   header->ID[0] = 'B';
368   header->ID[1] = 'C';
369   header->ID[2] = 'D';
370   header->ID[3] = 'F';
371   header->endian = cdf_endian();
372   header->version = CDF_VERSION;
373   header->subversion = CDF_SUBVERSION;
374 
375   header->structbytes = sizeof(CDataFileHeader);
376   header->type = cdf->type;
377   header->totlayer = cdf->totlayer;
378 
379   if (cdf->type == CDF_TYPE_IMAGE) {
380     /* fill image header */
381     image = &cdf->btype.image;
382     image->structbytes = sizeof(CDataFileImageHeader);
383     image->tile_size = CDF_TILE_SIZE;
384   }
385   else if (cdf->type == CDF_TYPE_MESH) {
386     /* fill mesh header */
387     mesh = &cdf->btype.mesh;
388     mesh->structbytes = sizeof(CDataFileMeshHeader);
389   }
390 
391   cdf_write_header(cdf);
392 
393   return true;
394 }
395 
cdf_write_layer(CDataFile * UNUSED (cdf),CDataFileLayer * UNUSED (blay))396 bool cdf_write_layer(CDataFile *UNUSED(cdf), CDataFileLayer *UNUSED(blay))
397 {
398   return true;
399 }
400 
cdf_write_data(CDataFile * cdf,unsigned int size,void * data)401 bool cdf_write_data(CDataFile *cdf, unsigned int size, void *data)
402 {
403   /* write data */
404   if (!fwrite(data, size, 1, cdf->writef)) {
405     return false;
406   }
407 
408   return true;
409 }
410 
cdf_write_close(CDataFile * cdf)411 void cdf_write_close(CDataFile *cdf)
412 {
413   if (cdf->writef) {
414     fclose(cdf->writef);
415     cdf->writef = NULL;
416   }
417 }
418 
cdf_remove(const char * filename)419 void cdf_remove(const char *filename)
420 {
421   BLI_delete(filename, false, false);
422 }
423 
424 /********************************** Layers ***********************************/
425 
cdf_layer_find(CDataFile * cdf,int type,const char * name)426 CDataFileLayer *cdf_layer_find(CDataFile *cdf, int type, const char *name)
427 {
428   CDataFileLayer *layer;
429   int a;
430 
431   for (a = 0; a < cdf->totlayer; a++) {
432     layer = &cdf->layer[a];
433 
434     if (layer->type == type && STREQ(layer->name, name)) {
435       return layer;
436     }
437   }
438 
439   return NULL;
440 }
441 
cdf_layer_add(CDataFile * cdf,int type,const char * name,size_t datasize)442 CDataFileLayer *cdf_layer_add(CDataFile *cdf, int type, const char *name, size_t datasize)
443 {
444   CDataFileLayer *newlayer, *layer;
445 
446   /* expand array */
447   newlayer = MEM_calloc_arrayN((cdf->totlayer + 1), sizeof(CDataFileLayer), "CDataFileLayer");
448   memcpy(newlayer, cdf->layer, sizeof(CDataFileLayer) * cdf->totlayer);
449   cdf->layer = newlayer;
450 
451   cdf->totlayer++;
452 
453   /* fill in new layer */
454   layer = &cdf->layer[cdf->totlayer - 1];
455   layer->structbytes = sizeof(CDataFileLayer);
456   layer->datatype = CDF_DATA_FLOAT;
457   layer->datasize = datasize;
458   layer->type = type;
459   BLI_strncpy(layer->name, name, CDF_LAYER_NAME_MAX);
460 
461   return layer;
462 }
463