Blender V5.0
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_fileops.h"
17#include "BLI_string.h"
18#include "BLI_utildefines.h"
19
20#include "BKE_customdata_file.h"
21
22/************************* File Format Definitions ***************************/
23
24#define CDF_ENDIAN_LITTLE 0
25#define CDF_ENDIAN_BIG 1
26
27#define CDF_DATA_FLOAT 0
28
30 char ID[4]; /* "BCDF" */
31 char endian; /* little, big */
32 char version; /* non-compatible versions */
33 char subversion; /* compatible sub versions */
34 char pad; /* padding */
35
36 int structbytes; /* size of this struct in bytes */
37 int type; /* image, mesh */
38 int totlayer; /* number of layers in the file */
39};
40
42 int structbytes; /* size of this struct in bytes */
43 int width; /* image width */
44 int height; /* image height */
45 int tile_size; /* tile size (required power of 2) */
46};
47
49 int structbytes; /* size of this struct in bytes */
50};
51
53 int structbytes; /* size of this struct in bytes */
54 int datatype; /* only float for now */
55 uint64_t datasize; /* size of data in layer */
56 int type; /* layer type */
57 char name[CDF_LAYER_NAME_MAX]; /* layer name */
58};
59
60/**************************** Other Definitions ******************************/
61
62#define CDF_VERSION 0
63#define CDF_SUBVERSION 0
64#define CDF_TILE_SIZE 64
65
82
83/********************************* Create/Free *******************************/
84
85static int cdf_endian()
86{
87 BLI_STATIC_ASSERT(ENDIAN_ORDER == L_ENDIAN, "Blender only builds on little endian systems")
88 return CDF_ENDIAN_LITTLE;
89}
90
92{
93 CDataFile *cdf = MEM_callocN<CDataFile>("CDataFile");
94
95 cdf->type = type;
96
97 return cdf;
98}
99
101{
102 cdf_read_close(cdf);
103 cdf_write_close(cdf);
104
105 if (cdf->layer) {
106 MEM_freeN(cdf->layer);
107 }
108
109 MEM_freeN(cdf);
110}
111
112/********************************* Read/Write ********************************/
113
114static bool cdf_read_header(CDataFile *cdf)
115{
116 CDataFileHeader *header;
119 CDataFileLayer *layer;
120 FILE *f = cdf->readf;
121 size_t offset = 0;
122 int a;
123
124 header = &cdf->header;
125
126 if (!fread(header, sizeof(CDataFileHeader), 1, cdf->readf)) {
127 return false;
128 }
129
130 if (memcmp(header->ID, "BCDF", sizeof(header->ID)) != 0) {
131 return false;
132 }
133 if (header->version > CDF_VERSION) {
134 return false;
135 }
136 if (header->endian != cdf_endian()) {
137 return false;
138 }
139
140 header->endian = cdf_endian();
141
142 /* NOTE: this is endianness-sensitive.
143 * Some non-char `header` data would need to be switched. */
144
145 if (!ELEM(header->type, CDF_TYPE_IMAGE, CDF_TYPE_MESH)) {
146 return false;
147 }
148
149 offset += header->structbytes;
150 header->structbytes = sizeof(CDataFileHeader);
151
152 if (BLI_fseek(f, offset, SEEK_SET) != 0) {
153 return false;
154 }
155
156 if (header->type == CDF_TYPE_IMAGE) {
157 image = &cdf->btype.image;
158 if (!fread(image, sizeof(CDataFileImageHeader), 1, f)) {
159 return false;
160 }
161
162 /* NOTE: this is endianness-sensitive.
163 * Some non-char `image` data would need to be switched. */
164
165 offset += image->structbytes;
166 image->structbytes = sizeof(CDataFileImageHeader);
167 }
168 else if (header->type == CDF_TYPE_MESH) {
169 mesh = &cdf->btype.mesh;
170 if (!fread(mesh, sizeof(CDataFileMeshHeader), 1, f)) {
171 return false;
172 }
173
174 /* NOTE: this is endianness-sensitive.
175 * Some non-char `mesh` data would need to be switched. */
176
177 offset += mesh->structbytes;
178 mesh->structbytes = sizeof(CDataFileMeshHeader);
179 }
180
181 if (BLI_fseek(f, offset, SEEK_SET) != 0) {
182 return false;
183 }
184
185 cdf->layer = MEM_calloc_arrayN<CDataFileLayer>(header->totlayer, "CDataFileLayer");
186 cdf->totlayer = header->totlayer;
187
188 if (!cdf->layer) {
189 return false;
190 }
191
192 for (a = 0; a < header->totlayer; a++) {
193 layer = &cdf->layer[a];
194
195 if (!fread(layer, sizeof(CDataFileLayer), 1, f)) {
196 return false;
197 }
198
199 /* NOTE: this is endianness-sensitive.
200 * Some non-char `layer` data would need to be switched. */
201
202 if (layer->datatype != CDF_DATA_FLOAT) {
203 return false;
204 }
205
206 offset += layer->structbytes;
207 layer->structbytes = sizeof(CDataFileLayer);
208
209 if (BLI_fseek(f, offset, SEEK_SET) != 0) {
210 return false;
211 }
212 }
213
214 cdf->dataoffset = offset;
215
216 return true;
217}
218
220{
221 CDataFileHeader *header;
224 CDataFileLayer *layer;
225 FILE *f = cdf->writef;
226 int a;
227
228 header = &cdf->header;
229
230 if (!fwrite(header, sizeof(CDataFileHeader), 1, f)) {
231 return false;
232 }
233
234 if (header->type == CDF_TYPE_IMAGE) {
235 image = &cdf->btype.image;
236 if (!fwrite(image, sizeof(CDataFileImageHeader), 1, f)) {
237 return false;
238 }
239 }
240 else if (header->type == CDF_TYPE_MESH) {
241 mesh = &cdf->btype.mesh;
242 if (!fwrite(mesh, sizeof(CDataFileMeshHeader), 1, f)) {
243 return false;
244 }
245 }
246
247 for (a = 0; a < header->totlayer; a++) {
248 layer = &cdf->layer[a];
249
250 if (!fwrite(layer, sizeof(CDataFileLayer), 1, f)) {
251 return false;
252 }
253 }
254
255 return true;
256}
257
258bool cdf_read_open(CDataFile *cdf, const char *filepath)
259{
260 FILE *f;
261
262 f = BLI_fopen(filepath, "rb");
263 if (!f) {
264 return false;
265 }
266
267 cdf->readf = f;
268
269 if (!cdf_read_header(cdf)) {
270 cdf_read_close(cdf);
271 return false;
272 }
273
274 if (cdf->header.type != cdf->type) {
275 cdf_read_close(cdf);
276 return false;
277 }
278
279 return true;
280}
281
283{
284 size_t offset;
285 int a;
286
287 /* seek to right location in file */
288 offset = cdf->dataoffset;
289 for (a = 0; a < cdf->totlayer; a++) {
290 if (&cdf->layer[a] == blay) {
291 break;
292 }
293
294 offset += cdf->layer[a].datasize;
295 }
296
297 return (BLI_fseek(cdf->readf, offset, SEEK_SET) == 0);
298}
299
301{
302 /* read data */
303 if (!fread(data, size, 1, cdf->readf)) {
304 return false;
305 }
306
307 /* NOTE: this is endianness-sensitive.
308 * `data` would need to be switched. */
309
310 return true;
311}
312
314{
315 if (cdf->readf) {
316 fclose(cdf->readf);
317 cdf->readf = nullptr;
318 }
319}
320
321bool cdf_write_open(CDataFile *cdf, const char *filepath)
322{
323 CDataFileHeader *header;
326 FILE *f;
327
328 f = BLI_fopen(filepath, "wb");
329 if (!f) {
330 return false;
331 }
332
333 cdf->writef = f;
334
335 /* Fill header. */
336 header = &cdf->header;
337 /* Copy "BCDF" (string terminator out of range). */
338 header->ID[0] = 'B';
339 header->ID[1] = 'C';
340 header->ID[2] = 'D';
341 header->ID[3] = 'F';
342 header->endian = cdf_endian();
343 header->version = CDF_VERSION;
344 header->subversion = CDF_SUBVERSION;
345
346 header->structbytes = sizeof(CDataFileHeader);
347 header->type = cdf->type;
348 header->totlayer = cdf->totlayer;
349
350 if (cdf->type == CDF_TYPE_IMAGE) {
351 /* fill image header */
352 image = &cdf->btype.image;
353 image->structbytes = sizeof(CDataFileImageHeader);
354 image->tile_size = CDF_TILE_SIZE;
355 }
356 else if (cdf->type == CDF_TYPE_MESH) {
357 /* fill mesh header */
358 mesh = &cdf->btype.mesh;
359 mesh->structbytes = sizeof(CDataFileMeshHeader);
360 }
361
362 cdf_write_header(cdf);
363
364 return true;
365}
366
367bool cdf_write_layer(CDataFile * /*cdf*/, CDataFileLayer * /*blay*/)
368{
369 return true;
370}
371
372bool cdf_write_data(CDataFile *cdf, uint size, const void *data)
373{
374 /* write data */
375 if (!fwrite(data, size, 1, cdf->writef)) {
376 return false;
377 }
378
379 return true;
380}
381
383{
384 if (cdf->writef) {
385 fclose(cdf->writef);
386 cdf->writef = nullptr;
387 }
388}
389
390void cdf_remove(const char *filepath)
391{
392 BLI_delete(filepath, false, false);
393}
394
395/********************************** Layers ***********************************/
396
397CDataFileLayer *cdf_layer_find(CDataFile *cdf, int type, const char *name)
398{
399 CDataFileLayer *layer;
400 int a;
401
402 for (a = 0; a < cdf->totlayer; a++) {
403 layer = &cdf->layer[a];
404
405 if (layer->type == type && STREQ(layer->name, name)) {
406 return layer;
407 }
408 }
409
410 return nullptr;
411}
412
413CDataFileLayer *cdf_layer_add(CDataFile *cdf, int type, const char *name, size_t datasize)
414{
415 CDataFileLayer *newlayer, *layer;
416
417 /* expand array */
418 newlayer = MEM_calloc_arrayN<CDataFileLayer>(size_t(cdf->totlayer) + 1, "CDataFileLayer");
419 if (cdf->totlayer > 0) {
420 memcpy(newlayer, cdf->layer, sizeof(CDataFileLayer) * cdf->totlayer);
421 }
422 cdf->layer = newlayer;
423
424 cdf->totlayer++;
425
426 /* fill in new layer */
427 layer = &cdf->layer[cdf->totlayer - 1];
428 layer->structbytes = sizeof(CDataFileLayer);
429 layer->datatype = CDF_DATA_FLOAT;
430 layer->datasize = datasize;
431 layer->type = type;
432 STRNCPY(layer->name, name);
433
434 return layer;
435}
#define CDF_TYPE_MESH
#define CDF_LAYER_NAME_MAX
#define CDF_TYPE_IMAGE
#define BLI_STATIC_ASSERT(a, msg)
Definition BLI_assert.h:83
#define L_ENDIAN
#define ENDIAN_ORDER
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:199
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
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_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
const char * name
char name[CDF_LAYER_NAME_MAX]
union CDataFile::@351045111137014237275261270114201234354061010141 btype
CDataFileImageHeader image
CDataFileMeshHeader mesh
CDataFileLayer * layer
CDataFileHeader header
size_t dataoffset