Blender  V3.3
customdata_file.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include "MEM_guardedalloc.h"
12 
13 #include "BLI_endian_defines.h"
14 #include "BLI_endian_switch.h"
15 #include "BLI_fileops.h"
16 #include "BLI_string.h"
17 #include "BLI_utildefines.h"
18 
19 #include "BKE_customdata_file.h"
20 
21 /************************* File Format Definitions ***************************/
22 
23 #define CDF_ENDIAN_LITTLE 0
24 #define CDF_ENDIAN_BIG 1
25 
26 #define CDF_DATA_FLOAT 0
27 
28 typedef struct CDataFileHeader {
29  char ID[4]; /* "BCDF" */
30  char endian; /* little, big */
31  char version; /* non-compatible versions */
32  char subversion; /* compatible sub versions */
33  char pad; /* padding */
34 
35  int structbytes; /* size of this struct in bytes */
36  int type; /* image, mesh */
37  int totlayer; /* number of layers in the file */
39 
40 typedef struct CDataFileImageHeader {
41  int structbytes; /* size of this struct in bytes */
42  int width; /* image width */
43  int height; /* image height */
44  int tile_size; /* tile size (required power of 2) */
46 
47 typedef struct CDataFileMeshHeader {
48  int structbytes; /* size of this struct in bytes */
50 
52  int structbytes; /* size of this struct in bytes */
53  int datatype; /* only float for now */
54  uint64_t datasize; /* size of data in layer */
55  int type; /* layer type */
56  char name[CDF_LAYER_NAME_MAX]; /* layer name */
57 };
58 
59 /**************************** Other Definitions ******************************/
60 
61 #define CDF_VERSION 0
62 #define CDF_SUBVERSION 0
63 #define CDF_TILE_SIZE 64
64 
65 struct CDataFile {
66  int type;
67 
69  union {
72  } btype;
73 
75  int totlayer;
76 
77  FILE *readf;
78  FILE *writef;
80  size_t dataoffset;
81 };
82 
83 /********************************* Create/Free *******************************/
84 
85 static int cdf_endian(void)
86 {
87  if (ENDIAN_ORDER == L_ENDIAN) {
88  return CDF_ENDIAN_LITTLE;
89  }
90 
91  return CDF_ENDIAN_BIG;
92 }
93 
95 {
96  CDataFile *cdf = MEM_callocN(sizeof(CDataFile), "CDataFile");
97 
98  cdf->type = type;
99 
100  return cdf;
101 }
102 
103 void cdf_free(CDataFile *cdf)
104 {
105  cdf_read_close(cdf);
106  cdf_write_close(cdf);
107 
108  if (cdf->layer) {
109  MEM_freeN(cdf->layer);
110  }
111 
112  MEM_freeN(cdf);
113 }
114 
115 /********************************* Read/Write ********************************/
116 
117 static bool cdf_read_header(CDataFile *cdf)
118 {
119  CDataFileHeader *header;
122  CDataFileLayer *layer;
123  FILE *f = cdf->readf;
124  size_t offset = 0;
125  int a;
126 
127  header = &cdf->header;
128 
129  if (!fread(header, sizeof(CDataFileHeader), 1, cdf->readf)) {
130  return false;
131  }
132 
133  if (memcmp(header->ID, "BCDF", sizeof(header->ID)) != 0) {
134  return false;
135  }
136  if (header->version > CDF_VERSION) {
137  return false;
138  }
139 
140  cdf->switchendian = header->endian != cdf_endian();
141  header->endian = cdf_endian();
142 
143  if (cdf->switchendian) {
144  BLI_endian_switch_int32(&header->type);
147  }
148 
149  if (!ELEM(header->type, CDF_TYPE_IMAGE, CDF_TYPE_MESH)) {
150  return false;
151  }
152 
153  offset += header->structbytes;
154  header->structbytes = sizeof(CDataFileHeader);
155 
156  if (BLI_fseek(f, offset, SEEK_SET) != 0) {
157  return false;
158  }
159 
160  if (header->type == CDF_TYPE_IMAGE) {
161  image = &cdf->btype.image;
162  if (!fread(image, sizeof(CDataFileImageHeader), 1, f)) {
163  return false;
164  }
165 
166  if (cdf->switchendian) {
168  BLI_endian_switch_int32(&image->height);
169  BLI_endian_switch_int32(&image->tile_size);
170  BLI_endian_switch_int32(&image->structbytes);
171  }
172 
173  offset += image->structbytes;
174  image->structbytes = sizeof(CDataFileImageHeader);
175  }
176  else if (header->type == CDF_TYPE_MESH) {
177  mesh = &cdf->btype.mesh;
178  if (!fread(mesh, sizeof(CDataFileMeshHeader), 1, f)) {
179  return false;
180  }
181 
182  if (cdf->switchendian) {
183  BLI_endian_switch_int32(&mesh->structbytes);
184  }
185 
186  offset += mesh->structbytes;
187  mesh->structbytes = sizeof(CDataFileMeshHeader);
188  }
189 
190  if (BLI_fseek(f, offset, SEEK_SET) != 0) {
191  return false;
192  }
193 
194  cdf->layer = MEM_calloc_arrayN(header->totlayer, sizeof(CDataFileLayer), "CDataFileLayer");
195  cdf->totlayer = header->totlayer;
196 
197  if (!cdf->layer) {
198  return false;
199  }
200 
201  for (a = 0; a < header->totlayer; a++) {
202  layer = &cdf->layer[a];
203 
204  if (!fread(layer, sizeof(CDataFileLayer), 1, f)) {
205  return false;
206  }
207 
208  if (cdf->switchendian) {
209  BLI_endian_switch_int32(&layer->type);
213  }
214 
215  if (layer->datatype != CDF_DATA_FLOAT) {
216  return false;
217  }
218 
219  offset += layer->structbytes;
220  layer->structbytes = sizeof(CDataFileLayer);
221 
222  if (BLI_fseek(f, offset, SEEK_SET) != 0) {
223  return false;
224  }
225  }
226 
227  cdf->dataoffset = offset;
228 
229  return true;
230 }
231 
232 static bool cdf_write_header(CDataFile *cdf)
233 {
234  CDataFileHeader *header;
237  CDataFileLayer *layer;
238  FILE *f = cdf->writef;
239  int a;
240 
241  header = &cdf->header;
242 
243  if (!fwrite(header, sizeof(CDataFileHeader), 1, f)) {
244  return false;
245  }
246 
247  if (header->type == CDF_TYPE_IMAGE) {
248  image = &cdf->btype.image;
249  if (!fwrite(image, sizeof(CDataFileImageHeader), 1, f)) {
250  return false;
251  }
252  }
253  else if (header->type == CDF_TYPE_MESH) {
254  mesh = &cdf->btype.mesh;
255  if (!fwrite(mesh, sizeof(CDataFileMeshHeader), 1, f)) {
256  return false;
257  }
258  }
259 
260  for (a = 0; a < header->totlayer; a++) {
261  layer = &cdf->layer[a];
262 
263  if (!fwrite(layer, sizeof(CDataFileLayer), 1, f)) {
264  return false;
265  }
266  }
267 
268  return true;
269 }
270 
271 bool cdf_read_open(CDataFile *cdf, const char *filepath)
272 {
273  FILE *f;
274 
275  f = BLI_fopen(filepath, "rb");
276  if (!f) {
277  return false;
278  }
279 
280  cdf->readf = f;
281 
282  if (!cdf_read_header(cdf)) {
283  cdf_read_close(cdf);
284  return false;
285  }
286 
287  if (cdf->header.type != cdf->type) {
288  cdf_read_close(cdf);
289  return false;
290  }
291 
292  return true;
293 }
294 
296 {
297  size_t offset;
298  int a;
299 
300  /* seek to right location in file */
301  offset = cdf->dataoffset;
302  for (a = 0; a < cdf->totlayer; a++) {
303  if (&cdf->layer[a] == blay) {
304  break;
305  }
306 
307  offset += cdf->layer[a].datasize;
308  }
309 
310  return (BLI_fseek(cdf->readf, offset, SEEK_SET) == 0);
311 }
312 
313 bool cdf_read_data(CDataFile *cdf, unsigned int size, void *data)
314 {
315  /* read data */
316  if (!fread(data, size, 1, cdf->readf)) {
317  return false;
318  }
319 
320  /* switch endian if necessary */
321  if (cdf->switchendian) {
322  BLI_endian_switch_float_array(data, size / sizeof(float));
323  }
324 
325  return true;
326 }
327 
329 {
330  if (cdf->readf) {
331  fclose(cdf->readf);
332  cdf->readf = NULL;
333  }
334 }
335 
336 bool cdf_write_open(CDataFile *cdf, const char *filepath)
337 {
338  CDataFileHeader *header;
341  FILE *f;
342 
343  f = BLI_fopen(filepath, "wb");
344  if (!f) {
345  return false;
346  }
347 
348  cdf->writef = f;
349 
350  /* Fill header. */
351  header = &cdf->header;
352  /* Copy "BCDF" (string terminator out of range). */
353  header->ID[0] = 'B';
354  header->ID[1] = 'C';
355  header->ID[2] = 'D';
356  header->ID[3] = 'F';
357  header->endian = cdf_endian();
358  header->version = CDF_VERSION;
359  header->subversion = CDF_SUBVERSION;
360 
361  header->structbytes = sizeof(CDataFileHeader);
362  header->type = cdf->type;
363  header->totlayer = cdf->totlayer;
364 
365  if (cdf->type == CDF_TYPE_IMAGE) {
366  /* fill image header */
367  image = &cdf->btype.image;
368  image->structbytes = sizeof(CDataFileImageHeader);
369  image->tile_size = CDF_TILE_SIZE;
370  }
371  else if (cdf->type == CDF_TYPE_MESH) {
372  /* fill mesh header */
373  mesh = &cdf->btype.mesh;
374  mesh->structbytes = sizeof(CDataFileMeshHeader);
375  }
376 
377  cdf_write_header(cdf);
378 
379  return true;
380 }
381 
383 {
384  return true;
385 }
386 
387 bool cdf_write_data(CDataFile *cdf, unsigned int size, void *data)
388 {
389  /* write data */
390  if (!fwrite(data, size, 1, cdf->writef)) {
391  return false;
392  }
393 
394  return true;
395 }
396 
398 {
399  if (cdf->writef) {
400  fclose(cdf->writef);
401  cdf->writef = NULL;
402  }
403 }
404 
405 void cdf_remove(const char *filepath)
406 {
407  BLI_delete(filepath, false, false);
408 }
409 
410 /********************************** Layers ***********************************/
411 
412 CDataFileLayer *cdf_layer_find(CDataFile *cdf, int type, const char *name)
413 {
414  CDataFileLayer *layer;
415  int a;
416 
417  for (a = 0; a < cdf->totlayer; a++) {
418  layer = &cdf->layer[a];
419 
420  if (layer->type == type && STREQ(layer->name, name)) {
421  return layer;
422  }
423  }
424 
425  return NULL;
426 }
427 
428 CDataFileLayer *cdf_layer_add(CDataFile *cdf, int type, const char *name, size_t datasize)
429 {
430  CDataFileLayer *newlayer, *layer;
431 
432  /* expand array */
433  newlayer = MEM_calloc_arrayN((cdf->totlayer + 1), sizeof(CDataFileLayer), "CDataFileLayer");
434  memcpy(newlayer, cdf->layer, sizeof(CDataFileLayer) * cdf->totlayer);
435  cdf->layer = newlayer;
436 
437  cdf->totlayer++;
438 
439  /* fill in new layer */
440  layer = &cdf->layer[cdf->totlayer - 1];
441  layer->structbytes = sizeof(CDataFileLayer);
442  layer->datatype = CDF_DATA_FLOAT;
443  layer->datasize = datasize;
444  layer->type = type;
445  BLI_strncpy(layer->name, name, CDF_LAYER_NAME_MAX);
446 
447  return layer;
448 }
#define CDF_TYPE_MESH
#define CDF_LAYER_NAME_MAX
struct CDataFileLayer CDataFileLayer
#define CDF_TYPE_IMAGE
#define L_ENDIAN
#define ENDIAN_ORDER
BLI_INLINE void BLI_endian_switch_uint64(uint64_t *val) ATTR_NONNULL(1)
void BLI_endian_switch_float_array(float *val, int size) ATTR_NONNULL(1)
Definition: endian_switch.c:51
BLI_INLINE void BLI_endian_switch_int32(int *val) ATTR_NONNULL(1)
File and directory operations.
FILE * BLI_fopen(const char *filepath, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: fileops.c:906
int BLI_delete(const char *file, bool dir, bool recursive) ATTR_NONNULL()
Definition: fileops.c:934
int BLI_fseek(FILE *stream, int64_t offset, int whence)
Definition: storage.c:160
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
#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
void cdf_remove(const char *filepath)
#define CDF_ENDIAN_LITTLE
bool cdf_write_open(CDataFile *cdf, const char *filepath)
static int cdf_endian(void)
#define CDF_TILE_SIZE
static bool cdf_read_header(CDataFile *cdf)
#define CDF_DATA_FLOAT
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)
struct CDataFileImageHeader CDataFileImageHeader
void cdf_read_close(CDataFile *cdf)
#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_read_open(CDataFile *cdf, const char *filepath)
bool cdf_write_data(CDataFile *cdf, unsigned int size, void *data)
struct CDataFileMeshHeader CDataFileMeshHeader
depth_tx normal_tx diffuse_light_tx specular_light_tx volume_light_tx environment_tx ambient_occlusion_tx aov_value_tx in_weight_img image(1, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D_ARRAY, "out_weight_img") .image(3
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:32
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
static unsigned a[3]
Definition: RandGen.cpp:78
unsigned __int64 uint64_t
Definition: stdint.h:90
char name[CDF_LAYER_NAME_MAX]
union CDataFile::@88 btype
CDataFileImageHeader image
CDataFileMeshHeader mesh
CDataFileLayer * layer
CDataFileHeader header
FILE * writef
size_t dataoffset
FILE * readf
Definition: DNA_ID.h:368