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