Blender V4.5
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
8
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 = MEM_callocN<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) {
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) {
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 = MEM_calloc_arrayN<CDataFileLayer>(header->totlayer, "CDataFileLayer");
197 cdf->totlayer = header->totlayer;
198
199 if (!cdf->layer) {
200 return false;
201 }
202
203 for (a = 0; a < header->totlayer; a++) {
204 layer = &cdf->layer[a];
205
206 if (!fread(layer, sizeof(CDataFileLayer), 1, f)) {
207 return false;
208 }
209
210 if (cdf->switchendian) {
215 }
216
217 if (layer->datatype != CDF_DATA_FLOAT) {
218 return false;
219 }
220
221 offset += layer->structbytes;
222 layer->structbytes = sizeof(CDataFileLayer);
223
224 if (BLI_fseek(f, offset, SEEK_SET) != 0) {
225 return false;
226 }
227 }
228
229 cdf->dataoffset = offset;
230
231 return true;
232}
233
235{
236 CDataFileHeader *header;
239 CDataFileLayer *layer;
240 FILE *f = cdf->writef;
241 int a;
242
243 header = &cdf->header;
244
245 if (!fwrite(header, sizeof(CDataFileHeader), 1, f)) {
246 return false;
247 }
248
249 if (header->type == CDF_TYPE_IMAGE) {
250 image = &cdf->btype.image;
251 if (!fwrite(image, sizeof(CDataFileImageHeader), 1, f)) {
252 return false;
253 }
254 }
255 else if (header->type == CDF_TYPE_MESH) {
256 mesh = &cdf->btype.mesh;
257 if (!fwrite(mesh, sizeof(CDataFileMeshHeader), 1, f)) {
258 return false;
259 }
260 }
261
262 for (a = 0; a < header->totlayer; a++) {
263 layer = &cdf->layer[a];
264
265 if (!fwrite(layer, sizeof(CDataFileLayer), 1, f)) {
266 return false;
267 }
268 }
269
270 return true;
271}
272
273bool cdf_read_open(CDataFile *cdf, const char *filepath)
274{
275 FILE *f;
276
277 f = BLI_fopen(filepath, "rb");
278 if (!f) {
279 return false;
280 }
281
282 cdf->readf = f;
283
284 if (!cdf_read_header(cdf)) {
285 cdf_read_close(cdf);
286 return false;
287 }
288
289 if (cdf->header.type != cdf->type) {
290 cdf_read_close(cdf);
291 return false;
292 }
293
294 return true;
295}
296
298{
299 size_t offset;
300 int a;
301
302 /* seek to right location in file */
303 offset = cdf->dataoffset;
304 for (a = 0; a < cdf->totlayer; a++) {
305 if (&cdf->layer[a] == blay) {
306 break;
307 }
308
309 offset += cdf->layer[a].datasize;
310 }
311
312 return (BLI_fseek(cdf->readf, offset, SEEK_SET) == 0);
313}
314
316{
317 /* read data */
318 if (!fread(data, size, 1, cdf->readf)) {
319 return false;
320 }
321
322 /* switch endian if necessary */
323 if (cdf->switchendian) {
324 BLI_endian_switch_float_array(static_cast<float *>(data), size / sizeof(float));
325 }
326
327 return true;
328}
329
331{
332 if (cdf->readf) {
333 fclose(cdf->readf);
334 cdf->readf = nullptr;
335 }
336}
337
338bool cdf_write_open(CDataFile *cdf, const char *filepath)
339{
340 CDataFileHeader *header;
343 FILE *f;
344
345 f = BLI_fopen(filepath, "wb");
346 if (!f) {
347 return false;
348 }
349
350 cdf->writef = f;
351
352 /* Fill header. */
353 header = &cdf->header;
354 /* Copy "BCDF" (string terminator out of range). */
355 header->ID[0] = 'B';
356 header->ID[1] = 'C';
357 header->ID[2] = 'D';
358 header->ID[3] = 'F';
359 header->endian = cdf_endian();
360 header->version = CDF_VERSION;
361 header->subversion = CDF_SUBVERSION;
362
363 header->structbytes = sizeof(CDataFileHeader);
364 header->type = cdf->type;
365 header->totlayer = cdf->totlayer;
366
367 if (cdf->type == CDF_TYPE_IMAGE) {
368 /* fill image header */
369 image = &cdf->btype.image;
370 image->structbytes = sizeof(CDataFileImageHeader);
371 image->tile_size = CDF_TILE_SIZE;
372 }
373 else if (cdf->type == CDF_TYPE_MESH) {
374 /* fill mesh header */
375 mesh = &cdf->btype.mesh;
376 mesh->structbytes = sizeof(CDataFileMeshHeader);
377 }
378
379 cdf_write_header(cdf);
380
381 return true;
382}
383
384bool cdf_write_layer(CDataFile * /*cdf*/, CDataFileLayer * /*blay*/)
385{
386 return true;
387}
388
389bool cdf_write_data(CDataFile *cdf, uint size, const void *data)
390{
391 /* write data */
392 if (!fwrite(data, size, 1, cdf->writef)) {
393 return false;
394 }
395
396 return true;
397}
398
400{
401 if (cdf->writef) {
402 fclose(cdf->writef);
403 cdf->writef = nullptr;
404 }
405}
406
407void cdf_remove(const char *filepath)
408{
409 BLI_delete(filepath, false, false);
410}
411
412/********************************** Layers ***********************************/
413
414CDataFileLayer *cdf_layer_find(CDataFile *cdf, int type, const char *name)
415{
416 CDataFileLayer *layer;
417 int a;
418
419 for (a = 0; a < cdf->totlayer; a++) {
420 layer = &cdf->layer[a];
421
422 if (layer->type == type && STREQ(layer->name, name)) {
423 return layer;
424 }
425 }
426
427 return nullptr;
428}
429
430CDataFileLayer *cdf_layer_add(CDataFile *cdf, int type, const char *name, size_t datasize)
431{
432 CDataFileLayer *newlayer, *layer;
433
434 /* expand array */
435 newlayer = MEM_calloc_arrayN<CDataFileLayer>(size_t(cdf->totlayer) + 1, "CDataFileLayer");
436 if (cdf->totlayer > 0) {
437 memcpy(newlayer, cdf->layer, sizeof(CDataFileLayer) * cdf->totlayer);
438 }
439 cdf->layer = newlayer;
440
441 cdf->totlayer++;
442
443 /* fill in new layer */
444 layer = &cdf->layer[cdf->totlayer - 1];
445 layer->structbytes = sizeof(CDataFileLayer);
446 layer->datatype = CDF_DATA_FLOAT;
447 layer->datasize = datasize;
448 layer->type = type;
449 STRNCPY(layer->name, name);
450
451 return layer;
452}
#define CDF_TYPE_MESH
#define CDF_LAYER_NAME_MAX
#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:212
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
unsigned int uint
#define ELEM(...)
#define STREQ(a, b)
Read Guarded memory(de)allocation.
BMesh const char void * data
unsigned long long int uint64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
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:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
char name[CDF_LAYER_NAME_MAX]
CDataFileImageHeader image
CDataFileMeshHeader mesh
CDataFileLayer * layer
CDataFileHeader header
size_t dataoffset
union CDataFile::@002266126252341335304252364064144273210233167372 btype