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