Blender  V2.93
customdata_file.c
Go to the documentation of this file.
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 
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 */
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) */
60 
61 typedef struct CDataFileMeshHeader {
62  int structbytes; /* size of this struct in bytes */
64 
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 
83  union {
86  } btype;
87 
89  int totlayer;
90 
91  FILE *readf;
92  FILE *writef;
94  size_t dataoffset;
95 };
96 
97 /********************************* Create/Free *******************************/
98 
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 
109 {
110  CDataFile *cdf = MEM_callocN(sizeof(CDataFile), "CDataFile");
111 
112  cdf->type = type;
113 
114  return cdf;
115 }
116 
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 
131 static bool cdf_read_header(CDataFile *cdf)
132 {
133  CDataFileHeader *header;
134  CDataFileImageHeader *image;
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);
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) {
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);
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 
246 static bool cdf_write_header(CDataFile *cdf)
247 {
248  CDataFileHeader *header;
249  CDataFileImageHeader *image;
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 
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 
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 
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 
343 {
344  if (cdf->readf) {
345  fclose(cdf->readf);
346  cdf->readf = NULL;
347  }
348 }
349 
350 bool cdf_write_open(CDataFile *cdf, const char *filename)
351 {
352  CDataFileHeader *header;
353  CDataFileImageHeader *image;
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 
397 {
398  return true;
399 }
400 
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 
412 {
413  if (cdf->writef) {
414  fclose(cdf->writef);
415  cdf->writef = NULL;
416  }
417 }
418 
419 void cdf_remove(const char *filename)
420 {
421  BLI_delete(filename, false, false);
422 }
423 
424 /********************************** Layers ***********************************/
425 
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 
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 }
#define CDF_TYPE_MESH
#define CDF_LAYER_NAME_MAX
struct CDataFileLayer CDataFileLayer
#define CDF_TYPE_IMAGE
#define L_ENDIAN
Definition: BKE_global.h:207
#define ENDIAN_ORDER
Definition: BKE_global.h:213
BLI_INLINE void BLI_endian_switch_uint64(uint64_t *val) ATTR_NONNULL(1)
void BLI_endian_switch_float_array(float *val, const int size) ATTR_NONNULL(1)
Definition: endian_switch.c:65
BLI_INLINE void BLI_endian_switch_int32(int *val) ATTR_NONNULL(1)
File and directory operations.
int BLI_delete(const char *file, bool dir, bool recursive) ATTR_NONNULL()
Definition: fileops.c:1037
FILE * BLI_fopen(const char *filename, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: fileops.c:1003
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
#define UNUSED(x)
#define ELEM(...)
#define STREQ(a, b)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Read Guarded memory(de)allocation.
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
struct CDataFileHeader CDataFileHeader
#define CDF_ENDIAN_LITTLE
static int cdf_endian(void)
#define CDF_TILE_SIZE
static bool cdf_read_header(CDataFile *cdf)
#define CDF_DATA_FLOAT
bool cdf_read_open(CDataFile *cdf, const char *filename)
bool cdf_read_data(CDataFile *cdf, unsigned int size, void *data)
bool cdf_write_layer(CDataFile *UNUSED(cdf), CDataFileLayer *UNUSED(blay))
static bool cdf_write_header(CDataFile *cdf)
void cdf_remove(const char *filename)
struct CDataFileImageHeader CDataFileImageHeader
void cdf_read_close(CDataFile *cdf)
bool cdf_write_open(CDataFile *cdf, const char *filename)
#define CDF_ENDIAN_BIG
#define CDF_VERSION
CDataFile * cdf_create(int type)
void cdf_write_close(CDataFile *cdf)
void cdf_free(CDataFile *cdf)
#define CDF_SUBVERSION
bool cdf_read_layer(CDataFile *cdf, CDataFileLayer *blay)
CDataFileLayer * cdf_layer_add(CDataFile *cdf, int type, const char *name, size_t datasize)
CDataFileLayer * cdf_layer_find(CDataFile *cdf, int type, const char *name)
bool cdf_write_data(CDataFile *cdf, unsigned int size, void *data)
struct CDataFileMeshHeader CDataFileMeshHeader
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:46
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
static unsigned a[3]
Definition: RandGen.cpp:92
unsigned __int64 uint64_t
Definition: stdint.h:93
char name[CDF_LAYER_NAME_MAX]
union CDataFile::@85 btype
CDataFileImageHeader image
CDataFileMeshHeader mesh
CDataFileLayer * layer
CDataFileHeader header
FILE * writef
size_t dataoffset
FILE * readf
Definition: DNA_ID.h:273