SDDSlib
Loading...
Searching...
No Matches
SDDS_binary.c
Go to the documentation of this file.
1/**
2 * @file SDDS_binary.c
3 * @brief SDDS binary data input and output routines
4 *
5 * This file contains the implementation of binary file handling functions
6 * for the SDDS (Self-Describing Data Sets) library. It includes functions
7 * for reading and writing binary data files in the SDDS format.
8 *
9 * @copyright
10 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
11 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
12 *
13 * @license
14 * This file is distributed under the terms of the Software License Agreement
15 * found in the file LICENSE included with this distribution.
16 *
17 * @author M. Borland, C. Saunders, R. Soliday, H. Shang
18 */
19
20#include "SDDS.h"
21#include "SDDS_internal.h"
22#include "mdb.h"
23#include <string.h>
24#include <errno.h>
25
26#undef DEBUG
27
28#if defined(_WIN32)
29# include <windows.h>
30# define sleep(sec) Sleep(sec * 1000)
31#else
32# include <unistd.h>
33#endif
34#if defined(vxWorks)
35# include <time.h>
36#endif
37
38#if SDDS_VERSION != 5
39# error "SDDS_VERSION does not match the version number of this file"
40#endif
41
42double makeFloat64FromFloat80(unsigned char x[16], int32_t byteOrder);
43
44static int32_t defaultIOBufferSize = SDDS_FILEBUFFER_SIZE;
45
46/* this routine is obsolete. Use SDDS_SetDefaultIOBufferSize(0) to effectively turn
47 * off buffering.
48 */
49int32_t SDDS_SetBufferedRead(int32_t dummy) {
50 return 0;
51}
52
53/**
54 * Sets the default I/O buffer size used for file operations.
55 *
56 * This function updates the global `defaultIOBufferSize` variable, which determines the size of the I/O buffer
57 * used for file read/write operations. The initial default is `SDDS_FILEBUFFER_SIZE`, which is 262144 bytes.
58 *
59 * @param newValue The new default I/O buffer size in bytes. If `newValue` is negative, the function returns
60 * the current buffer size without changing it. If `newValue` is between 0 and 128 (inclusive),
61 * it is treated as 0, effectively disabling buffering.
62 *
63 * @return The previous default I/O buffer size if `newValue` is greater than or equal to 0; otherwise,
64 * returns the current default buffer size without changing it.
65 */
66int32_t SDDS_SetDefaultIOBufferSize(int32_t newValue) {
67 int32_t previous;
68 if (newValue < 0)
69 return defaultIOBufferSize;
70 if (newValue < 128) /* arbitrary limit */
71 newValue = 0;
72 previous = defaultIOBufferSize;
73 defaultIOBufferSize = newValue;
74 return previous;
75}
76
77/**
78 * Reads data from a file into a buffer, optimizing performance with buffering.
79 *
80 * This function reads `targetSize` bytes from the file `fp` into the memory pointed to by `target`.
81 * It uses the provided `fBuffer` to buffer file data, improving read performance. If the data type
82 * is `SDDS_LONGDOUBLE` and the `long double` precision is not 18 digits, it handles conversion to
83 * double precision if the environment variable `SDDS_LONGDOUBLE_64BITS` is not set.
84 *
85 * If `target` is NULL, the function skips over `targetSize` bytes in the file.
86 *
87 * @param target Pointer to the memory location where the data will be stored. If NULL, the data is skipped.
88 * @param targetSize The number of bytes to read from the file.
89 * @param fp The file pointer from which data is read.
90 * @param fBuffer Pointer to an `SDDS_FILEBUFFER` structure used for buffering file data.
91 * @param type The SDDS data type of the data being read (e.g., `SDDS_LONGDOUBLE`).
92 * @param byteOrder The byte order of the data (`SDDS_LITTLEENDIAN` or `SDDS_BIGENDIAN`).
93 *
94 * @return Returns 1 on success; returns 0 on error.
95 */
96int32_t SDDS_BufferedRead(void *target, int64_t targetSize, FILE *fp, SDDS_FILEBUFFER *fBuffer, int32_t type, int32_t byteOrder) {
97 int float80tofloat64 = 0;
98 if ((LDBL_DIG != 18) && (type == SDDS_LONGDOUBLE)) {
99 if (getenv("SDDS_LONGDOUBLE_64BITS") == NULL) {
100 targetSize *= 2;
101 float80tofloat64 = 1;
102 }
103 }
104 if (!fBuffer->bufferSize) {
105 /* just read into users buffer or seek if no buffer given */
106 if (!target)
107 return !fseek(fp, (long)targetSize, SEEK_CUR);
108 else {
109 if (float80tofloat64) {
110 unsigned char x[16];
111 double d;
112 int64_t shift = 0;
113 while (shift < targetSize) {
114 if (fread(&x, (size_t)1, 16, fp) != 16)
115 return 0;
116 d = makeFloat64FromFloat80(x, byteOrder);
117 memcpy((char *)target + shift, &d, 8);
118 shift += 16;
119 }
120 return 1;
121 } else {
122 return fread(target, (size_t)1, (size_t)targetSize, fp) == targetSize;
123 }
124 }
125 }
126 if ((fBuffer->bytesLeft -= targetSize) >= 0) {
127 /* sufficient data is already in the buffer */
128 if (target) {
129 if (float80tofloat64) {
130 unsigned char x[16];
131 double d;
132 int64_t shift = 0;
133 while (shift < targetSize) {
134 memcpy(x, (char *)fBuffer->data + shift, 16);
135 d = makeFloat64FromFloat80(x, byteOrder);
136 memcpy((char *)target + shift, &d, 8);
137 shift += 16;
138 }
139 } else {
140 memcpy((char *)target, (char *)fBuffer->data, targetSize);
141 }
142 }
143 fBuffer->data += targetSize;
144 return 1;
145 } else {
146 /* need to read additional data into buffer */
147 int64_t bytesNeeded, offset;
148 fBuffer->bytesLeft += targetSize; /* adds back amount subtracted above */
149
150 /* first, use the data that is already available. this cleans out the buffer */
151 if ((offset = fBuffer->bytesLeft)) {
152 /* some data is available in the buffer */
153 if (target) {
154 if (float80tofloat64) {
155 unsigned char x[16];
156 double d;
157 int64_t shift = 0;
158 while (shift < offset) {
159 memcpy(x, (char *)fBuffer->data + shift, 16);
160 d = makeFloat64FromFloat80(x, byteOrder);
161 memcpy((char *)target + shift, &d, 8);
162 shift += 16;
163 }
164 } else {
165 memcpy((char *)target, (char *)fBuffer->data, offset);
166 }
167 }
168 bytesNeeded = targetSize - offset;
169 fBuffer->bytesLeft = 0;
170 } else {
171 bytesNeeded = targetSize;
172 }
173 fBuffer->data = fBuffer->buffer;
174
175 if (fBuffer->bufferSize < bytesNeeded) {
176 /* just read what is needed directly into user's memory or seek */
177 if (!target)
178 return !fseek(fp, (long)bytesNeeded, SEEK_CUR);
179 else {
180 if (float80tofloat64) {
181 unsigned char x[16];
182 double d;
183 int64_t shift = 0;
184 while (shift < bytesNeeded) {
185 if (fread(&x, (size_t)1, 16, fp) != 16)
186 return 0;
187 d = makeFloat64FromFloat80(x, byteOrder);
188 memcpy((char *)target + offset + shift, &d, 8);
189 shift += 16;
190 }
191 return 1;
192 } else {
193 return fread((char *)target + offset, (size_t)1, (size_t)bytesNeeded, fp) == bytesNeeded;
194 }
195 }
196 }
197
198 /* fill the buffer */
199 if ((fBuffer->bytesLeft = fread(fBuffer->data, (size_t)1, (size_t)fBuffer->bufferSize, fp)) < bytesNeeded)
200 return 0;
201 if (target) {
202 if (float80tofloat64) {
203 unsigned char x[16];
204 double d;
205 int64_t shift = 0;
206 while (shift < bytesNeeded) {
207 memcpy(x, (char *)fBuffer->data + shift, 16);
208 d = makeFloat64FromFloat80(x, byteOrder);
209 memcpy((char *)target + offset + shift, &d, 8);
210 shift += 16;
211 }
212 } else {
213 memcpy((char *)target + offset, (char *)fBuffer->data, bytesNeeded);
214 }
215 }
216 fBuffer->data += bytesNeeded;
217 fBuffer->bytesLeft -= bytesNeeded;
218 return 1;
219 }
220}
221
222/**
223 * Reads data from an LZMA-compressed file into a buffer, optimizing performance with buffering.
224 *
225 * This function reads `targetSize` bytes from the LZMA-compressed file `lzmafp` into the memory
226 * pointed to by `target`. It uses the provided `fBuffer` to buffer file data, improving read performance.
227 * If the data type is `SDDS_LONGDOUBLE` and the `long double` precision is not 18 digits, it handles
228 * conversion to double precision if the environment variable `SDDS_LONGDOUBLE_64BITS` is not set.
229 *
230 * If `target` is NULL, the function skips over `targetSize` bytes in the file.
231 *
232 * @param target Pointer to the memory location where the data will be stored. If NULL, the data is skipped.
233 * @param targetSize The number of bytes to read from the file.
234 * @param lzmafp The LZMA file pointer from which data is read.
235 * @param fBuffer Pointer to an `SDDS_FILEBUFFER` structure used for buffering file data.
236 * @param type The SDDS data type of the data being read (e.g., `SDDS_LONGDOUBLE`).
237 * @param byteOrder The byte order of the data (`SDDS_LITTLEENDIAN` or `SDDS_BIGENDIAN`).
238 *
239 * @return Returns 1 on success; returns 0 on error.
240 *
241 * @note This function requires that `fBuffer->bufferSize` is non-zero. If it is zero, an error is set.
242 */
243int32_t SDDS_LZMABufferedRead(void *target, int64_t targetSize, struct lzmafile *lzmafp, SDDS_FILEBUFFER *fBuffer, int32_t type, int32_t byteOrder) {
244 int float80tofloat64 = 0;
245 if (!fBuffer->bufferSize) {
246 SDDS_SetError("You must presently have a nonzero file buffer to use LZMA (reading/writing .lzma or .xz files)");
247 return 0;
248 }
249 if ((LDBL_DIG != 18) && (type == SDDS_LONGDOUBLE)) {
250 if (getenv("SDDS_LONGDOUBLE_64BITS") == NULL) {
251 targetSize *= 2;
252 float80tofloat64 = 1;
253 }
254 }
255 if ((fBuffer->bytesLeft -= targetSize) >= 0) {
256 if (target) {
257 if (float80tofloat64) {
258 unsigned char x[16];
259 double d;
260 int64_t shift = 0;
261 while (shift < targetSize) {
262 memcpy(x, (char *)fBuffer->data + shift, 16);
263 d = makeFloat64FromFloat80(x, byteOrder);
264 memcpy((char *)target + shift, &d, 8);
265 shift += 16;
266 }
267 } else {
268 memcpy((char *)target, (char *)fBuffer->data, targetSize);
269 }
270 }
271 fBuffer->data += targetSize;
272 return 1;
273 } else {
274 int64_t bytesNeeded, offset;
275 fBuffer->bytesLeft += targetSize;
276 if ((offset = fBuffer->bytesLeft)) {
277 if (target) {
278 if (float80tofloat64) {
279 unsigned char x[16];
280 double d;
281 int64_t shift = 0;
282 while (shift < offset) {
283 memcpy(x, (char *)fBuffer->data + shift, 16);
284 d = makeFloat64FromFloat80(x, byteOrder);
285 memcpy((char *)target + shift, &d, 8);
286 shift += 16;
287 }
288 } else {
289 memcpy((char *)target, (char *)fBuffer->data, offset);
290 }
291 }
292 bytesNeeded = targetSize - offset;
293 fBuffer->bytesLeft = 0;
294 } else {
295 bytesNeeded = targetSize;
296 }
297 fBuffer->data = fBuffer->buffer;
298
299 if (fBuffer->bufferSize < bytesNeeded) {
300 /* just read what is needed directly into user's memory or seek */
301 if (!target)
302 return !lzma_seek(lzmafp, (long)bytesNeeded, SEEK_CUR);
303 else {
304 if (float80tofloat64) {
305 unsigned char x[16];
306 double d;
307 int64_t shift = 0;
308 while (shift < bytesNeeded) {
309 if (lzma_read(lzmafp, &x, 16) != 16)
310 return 0;
311 d = makeFloat64FromFloat80(x, byteOrder);
312 memcpy((char *)target + offset + shift, &d, 8);
313 shift += 16;
314 }
315 return 1;
316 } else {
317 return lzma_read(lzmafp, (char *)target + offset, (size_t)bytesNeeded) == bytesNeeded;
318 }
319 }
320 }
321
322 if ((fBuffer->bytesLeft = lzma_read(lzmafp, fBuffer->data, (size_t)fBuffer->bufferSize)) < bytesNeeded)
323 return 0;
324 if (target) {
325 if (float80tofloat64) {
326 unsigned char x[16];
327 double d;
328 int64_t shift = 0;
329 while (shift < bytesNeeded) {
330 memcpy(x, (char *)fBuffer->data + shift, 16);
331 d = makeFloat64FromFloat80(x, byteOrder);
332 memcpy((char *)target + offset + shift, &d, 8);
333 shift += 16;
334 }
335 } else {
336 memcpy((char *)target + offset, (char *)fBuffer->data, bytesNeeded);
337 }
338 }
339 fBuffer->data += bytesNeeded;
340 fBuffer->bytesLeft -= bytesNeeded;
341 return 1;
342 }
343}
344
345#if defined(zLib)
346/**
347 * Reads data from a GZIP-compressed file into a buffer, optimizing performance with buffering.
348 *
349 * This function reads `targetSize` bytes from the GZIP-compressed file `gzfp` into the memory
350 * pointed to by `target`. It uses the provided `fBuffer` to buffer file data, improving read performance.
351 * If the data type is `SDDS_LONGDOUBLE` and the `long double` precision is not 18 digits, it handles
352 * conversion to double precision if the environment variable `SDDS_LONGDOUBLE_64BITS` is not set.
353 *
354 * If `target` is NULL, the function skips over `targetSize` bytes in the file.
355 *
356 * @param target Pointer to the memory location where the data will be stored. If NULL, the data is skipped.
357 * @param targetSize The number of bytes to read from the file.
358 * @param gzfp The GZIP file pointer from which data is read.
359 * @param fBuffer Pointer to an `SDDS_FILEBUFFER` structure used for buffering file data.
360 * @param type The SDDS data type of the data being read (e.g., `SDDS_LONGDOUBLE`).
361 * @param byteOrder The byte order of the data (`SDDS_LITTLEENDIAN` or `SDDS_BIGENDIAN`).
362 *
363 * @return Returns 1 on success; returns 0 on error.
364 *
365 * @note This function requires that `fBuffer->bufferSize` is non-zero. If it is zero, an error is set.
366 */
367int32_t SDDS_GZipBufferedRead(void *target, int64_t targetSize, gzFile gzfp, SDDS_FILEBUFFER *fBuffer, int32_t type, int32_t byteOrder) {
368 int float80tofloat64 = 0;
369 if (!fBuffer->bufferSize) {
370 SDDS_SetError("You must presently have a nonzero file buffer to use zLib (reading/writing .gz files)");
371 return 0;
372 }
373 if ((LDBL_DIG != 18) && (type == SDDS_LONGDOUBLE)) {
374 if (getenv("SDDS_LONGDOUBLE_64BITS") == NULL) {
375 targetSize *= 2;
376 float80tofloat64 = 1;
377 }
378 }
379 if ((fBuffer->bytesLeft -= targetSize) >= 0) {
380 if (target) {
381 if (float80tofloat64) {
382 unsigned char x[16];
383 double d;
384 int64_t shift = 0;
385 while (shift < targetSize) {
386 memcpy(x, (char *)fBuffer->data + shift, 16);
387 d = makeFloat64FromFloat80(x, byteOrder);
388 memcpy((char *)target + shift, &d, 8);
389 shift += 16;
390 }
391 } else {
392 memcpy((char *)target, (char *)fBuffer->data, targetSize);
393 }
394 }
395 fBuffer->data += targetSize;
396 return 1;
397 } else {
398 int64_t bytesNeeded, offset;
399 fBuffer->bytesLeft += targetSize;
400 if ((offset = fBuffer->bytesLeft)) {
401 if (target) {
402 if (float80tofloat64) {
403 unsigned char x[16];
404 double d;
405 int64_t shift = 0;
406 while (shift < offset) {
407 memcpy(x, (char *)fBuffer->data + shift, 16);
408 d = makeFloat64FromFloat80(x, byteOrder);
409 memcpy((char *)target + shift, &d, 8);
410 shift += 16;
411 }
412 } else {
413 memcpy((char *)target, (char *)fBuffer->data, offset);
414 }
415 }
416 bytesNeeded = targetSize - offset;
417 fBuffer->bytesLeft = 0;
418 } else {
419 bytesNeeded = targetSize;
420 }
421 fBuffer->data = fBuffer->buffer;
422
423 if (fBuffer->bufferSize < bytesNeeded) {
424 /* just read what is needed directly into user's memory or seek */
425 if (!target)
426 return !gzseek(gzfp, bytesNeeded, SEEK_CUR);
427 else {
428 if (float80tofloat64) {
429 unsigned char x[16];
430 double d;
431 int64_t shift = 0;
432 while (shift < bytesNeeded) {
433 if (gzread(gzfp, &x, 16) != 16)
434 return 0;
435 d = makeFloat64FromFloat80(x, byteOrder);
436 memcpy((char *)target + offset + shift, &d, 8);
437 shift += 16;
438 }
439 return 1;
440 } else {
441 return gzread(gzfp, (char *)target + offset, bytesNeeded) == bytesNeeded;
442 }
443 }
444 }
445
446 if ((fBuffer->bytesLeft = gzread(gzfp, fBuffer->data, fBuffer->bufferSize)) < bytesNeeded)
447 return 0;
448 if (target) {
449 if (float80tofloat64) {
450 unsigned char x[16];
451 double d;
452 int64_t shift = 0;
453 while (shift < bytesNeeded) {
454 memcpy(x, (char *)fBuffer->data + shift, 16);
455 d = makeFloat64FromFloat80(x, byteOrder);
456 memcpy((char *)target + offset + shift, &d, 8);
457 shift += 16;
458 }
459 } else {
460 memcpy((char *)target + offset, (char *)fBuffer->data, bytesNeeded);
461 }
462 }
463 fBuffer->data += bytesNeeded;
464 fBuffer->bytesLeft -= bytesNeeded;
465 return 1;
466 }
467}
468#endif
469
470/**
471 * Writes data to a file using a buffer to optimize performance.
472 *
473 * This function writes `targetSize` bytes from the memory pointed to by `target` to the file `fp`.
474 * It uses the provided `fBuffer` to buffer file data, improving write performance. If the buffer
475 * is full, it flushes the buffer to the file before writing more data.
476 *
477 * @param target Pointer to the memory location of the data to write.
478 * @param targetSize The number of bytes to write to the file.
479 * @param fp The file pointer to which data is written.
480 * @param fBuffer Pointer to an `SDDS_FILEBUFFER` structure used for buffering file data.
481 *
482 * @return Returns 1 on success; returns 0 on error.
483 */
484int32_t SDDS_BufferedWrite(void *target, int64_t targetSize, FILE *fp, SDDS_FILEBUFFER *fBuffer) {
485 if (!fBuffer->bufferSize) {
486 return fwrite(target, (size_t)1, (size_t)targetSize, fp) == targetSize;
487 }
488 if ((fBuffer->bytesLeft -= targetSize) >= 0) {
489 memcpy((char *)fBuffer->data, (char *)target, targetSize);
490 fBuffer->data += targetSize;
491#ifdef DEBUG
492 fprintf(stderr, "SDDS_BufferedWrite of %" PRId64 " bytes done in-memory, %" PRId64 " bytes left\n", targetSize, fBuffer->bytesLeft);
493#endif
494 return 1;
495 } else {
496 int64_t lastLeft;
497 /* add back what was subtracted in test above.
498 * lastLeft is the number of bytes left in the buffer before doing anything
499 * and also the number of bytes from the users data that get copied into the buffer.
500 */
501 lastLeft = (fBuffer->bytesLeft += targetSize);
502 /* copy part of the data into the buffer and write the buffer out */
503 memcpy((char *)fBuffer->data, (char *)target, (size_t)fBuffer->bytesLeft);
504 if (fwrite(fBuffer->buffer, (size_t)1, (size_t)fBuffer->bufferSize, fp) != fBuffer->bufferSize)
505 return 0;
506 if (fflush(fp)) {
507 SDDS_SetError("Problem flushing file (SDDS_BufferedWrite)");
508 SDDS_SetError(strerror(errno));
509 return 0;
510 }
511 /* reset the data pointer and the bytesLeft value.
512 * also, determine if the remaining data is too large for the buffer.
513 * if so, just write it out.
514 */
515 fBuffer->data = fBuffer->buffer;
516 if ((targetSize -= lastLeft) > (fBuffer->bytesLeft = fBuffer->bufferSize)) {
517 return fwrite((char *)target + lastLeft, (size_t)1, (size_t)targetSize, fp) == targetSize;
518 }
519 /* copy remaining data into the buffer.
520 * could do this with a recursive call, but this is more efficient.
521 */
522 memcpy((char *)fBuffer->data, (char *)target + lastLeft, targetSize);
523 fBuffer->data += targetSize;
524 fBuffer->bytesLeft -= targetSize;
525 return 1;
526 }
527}
528
529/**
530 * Writes data to an LZMA-compressed file using a buffer to optimize performance.
531 *
532 * This function writes `targetSize` bytes from the memory pointed to by `target` to the LZMA-compressed
533 * file referenced by `lzmafp`. It uses the provided `fBuffer` to buffer data before writing to the file,
534 * which can improve write performance by reducing the number of write operations.
535 *
536 * If there is enough space in the buffer (`fBuffer`), the data is copied into the buffer. If the buffer
537 * does not have enough space to hold the data, the buffer is flushed to the file, and the function
538 * recursively calls itself to handle the remaining data.
539 *
540 * @param target Pointer to the memory location of the data to write.
541 * @param targetSize The number of bytes to write to the file.
542 * @param lzmafp The LZMA file pointer to which data is written.
543 * @param fBuffer Pointer to an `SDDS_FILEBUFFER` structure used for buffering data.
544 *
545 * @return Returns 1 on success; returns 0 on error.
546 *
547 * @note This function requires that `fBuffer->bufferSize` is non-zero. If it is zero, the function
548 * sets an error message and returns 0.
549 */
550int32_t SDDS_LZMABufferedWrite(void *target, int64_t targetSize, struct lzmafile *lzmafp, SDDS_FILEBUFFER *fBuffer) {
551 if (!fBuffer->bufferSize) {
552 SDDS_SetError("You must presently have a nonzero file buffer to use lzma (reading/writing .xz files)");
553 return 0;
554 }
555 if ((fBuffer->bytesLeft -= targetSize) >= 0) {
556 memcpy((char *)fBuffer->data, (char *)target, targetSize);
557 fBuffer->data += targetSize;
558 return 1;
559 } else {
560 int64_t lastLeft;
561 lastLeft = (fBuffer->bytesLeft += targetSize);
562 memcpy((char *)fBuffer->data, (char *)target, (size_t)fBuffer->bytesLeft);
563 if (lzma_write(lzmafp, fBuffer->buffer, (size_t)fBuffer->bufferSize) != fBuffer->bufferSize)
564 return 0;
565 fBuffer->bytesLeft = fBuffer->bufferSize;
566 fBuffer->data = fBuffer->buffer;
567 return SDDS_LZMABufferedWrite((char *)target + lastLeft, targetSize - lastLeft, lzmafp, fBuffer);
568 }
569}
570
571#if defined(zLib)
572/**
573 * Writes data to a GZIP-compressed file using a buffer to optimize performance.
574 *
575 * This function writes `targetSize` bytes from the memory pointed to by `target` to the GZIP-compressed
576 * file referenced by `gzfp`. It uses the provided `fBuffer` to buffer data before writing to the file,
577 * which can improve write performance by reducing the number of write operations.
578 *
579 * If there is enough space in the buffer (`fBuffer`), the data is copied into the buffer. If the buffer
580 * does not have enough space to hold the data, the buffer is flushed to the file, and the function
581 * recursively calls itself to handle the remaining data.
582 *
583 * @param target Pointer to the memory location of the data to write.
584 * @param targetSize The number of bytes to write to the file.
585 * @param gzfp The GZIP file pointer to which data is written.
586 * @param fBuffer Pointer to an `SDDS_FILEBUFFER` structure used for buffering data.
587 *
588 * @return Returns 1 on success; returns 0 on error.
589 *
590 * @note This function requires that `fBuffer->bufferSize` is non-zero. If it is zero, the function
591 * sets an error message and returns 0.
592 */
593int32_t SDDS_GZipBufferedWrite(void *target, int64_t targetSize, gzFile gzfp, SDDS_FILEBUFFER *fBuffer) {
594 if (!fBuffer->bufferSize) {
595 SDDS_SetError("You must presently have a nonzero file buffer to use zLib (reading/writing .gz files}");
596 return 0;
597 }
598 if ((fBuffer->bytesLeft -= targetSize) >= 0) {
599 memcpy((char *)fBuffer->data, (char *)target, targetSize);
600 fBuffer->data += targetSize;
601 return 1;
602 } else {
603 int64_t lastLeft;
604 lastLeft = (fBuffer->bytesLeft + targetSize);
605 memcpy((char *)fBuffer->data, (char *)target, lastLeft);
606 if (gzwrite(gzfp, fBuffer->buffer, fBuffer->bufferSize) != fBuffer->bufferSize)
607 return 0;
608 /*gzflush(gzfp, Z_FULL_FLUSH); */
609 fBuffer->bytesLeft = fBuffer->bufferSize;
610 fBuffer->data = fBuffer->buffer;
611 return SDDS_GZipBufferedWrite((char *)target + lastLeft, targetSize - lastLeft, gzfp, fBuffer);
612 }
613}
614#endif
615
616/**
617 * Flushes the buffered data to a file to ensure all data is written.
618 *
619 * This function writes any remaining data in the buffer (`fBuffer`) to the file pointed to by `fp`. If the
620 * buffer contains data, it writes the data to the file, resets the buffer, and flushes the file's output
621 * buffer using `fflush`. This ensures that all buffered data is physically written to the file.
622 *
623 * @param fp The file pointer to which buffered data will be written.
624 * @param fBuffer Pointer to an `SDDS_FILEBUFFER` structure containing the buffered data.
625 *
626 * @return Returns 1 on success; returns 0 on error.
627 *
628 * @note If `fBuffer->bufferSize` is zero, the function will only call `fflush(fp)`.
629 *
630 * @warning If `fp` or `fBuffer` is `NULL`, the function sets an error message and returns 0.
631 */
632int32_t SDDS_FlushBuffer(FILE *fp, SDDS_FILEBUFFER *fBuffer) {
633 int64_t writeBytes;
634 if (!fp) {
635 SDDS_SetError("Unable to flush buffer: file pointer is NULL. (SDDS_FlushBuffer)");
636 return 0;
637 }
638 if (!fBuffer->bufferSize) {
639 if (fflush(fp)) {
640 SDDS_SetError("Problem flushing file (SDDS_FlushBuffer.1)");
641 SDDS_SetError(strerror(errno));
642 return 0;
643 }
644 return 1;
645 }
646 if (!fBuffer) {
647 SDDS_SetError("Unable to flush buffer: buffer pointer is NULL. (SDDS_FlushBuffer)");
648 return 0;
649 }
650 if ((writeBytes = fBuffer->bufferSize - fBuffer->bytesLeft)) {
651 if (writeBytes < 0) {
652 SDDS_SetError("Unable to flush buffer: negative byte count (SDDS_FlushBuffer).");
653 return 0;
654 }
655#ifdef DEBUG
656 fprintf(stderr, "Writing %" PRId64 " bytes to disk\n", writeBytes);
657#endif
658 if (fwrite(fBuffer->buffer, 1, writeBytes, fp) != writeBytes) {
659 SDDS_SetError("Unable to flush buffer: write operation failed (SDDS_FlushBuffer).");
660 return 0;
661 }
662 fBuffer->bytesLeft = fBuffer->bufferSize;
663 fBuffer->data = fBuffer->buffer;
664 }
665 if (fflush(fp)) {
666 SDDS_SetError("Problem flushing file (SDDS_FlushBuffer.2)");
667 SDDS_SetError(strerror(errno));
668 return 0;
669 }
670 return 1;
671}
672
673/**
674 * Flushes the buffered data to an LZMA-compressed file to ensure all data is written.
675 *
676 * This function writes any remaining data in the buffer (`fBuffer`) to the LZMA-compressed file pointed
677 * to by `lzmafp`. If the buffer contains data, it writes the data to the file, resets the buffer,
678 * ensuring that all buffered data is physically written to the file.
679 *
680 * @param lzmafp The LZMA file pointer to which buffered data will be written.
681 * @param fBuffer Pointer to an `SDDS_FILEBUFFER` structure containing the buffered data.
682 *
683 * @return Returns 1 on success; returns 0 on error.
684 *
685 * @note This function assumes that `fBuffer->bufferSize` is non-zero and `fBuffer` is properly initialized.
686 */
687int32_t SDDS_LZMAFlushBuffer(struct lzmafile *lzmafp, SDDS_FILEBUFFER *fBuffer) {
688 int32_t writeBytes;
689 if ((writeBytes = fBuffer->bufferSize - fBuffer->bytesLeft)) {
690 if (lzma_write(lzmafp, fBuffer->buffer, writeBytes) != writeBytes)
691 return 0;
692 fBuffer->bytesLeft = fBuffer->bufferSize;
693 fBuffer->data = fBuffer->buffer;
694 }
695 return 1;
696}
697
698#if defined(zLib)
699/**
700 * Flushes the buffered data to a GZIP-compressed file to ensure all data is written.
701 *
702 * This function writes any remaining data in the buffer (`fBuffer`) to the GZIP-compressed file pointed
703 * to by `gzfp`. If the buffer contains data, it writes the data to the file, resets the buffer,
704 * ensuring that all buffered data is physically written to the file.
705 *
706 * @param gzfp The GZIP file pointer to which buffered data will be written.
707 * @param fBuffer Pointer to an `SDDS_FILEBUFFER` structure containing the buffered data.
708 *
709 * @return Returns 1 on success; returns 0 on error.
710 *
711 * @note This function assumes that `fBuffer->bufferSize` is non-zero and `fBuffer` is properly initialized.
712 */
713int32_t SDDS_GZipFlushBuffer(gzFile gzfp, SDDS_FILEBUFFER *fBuffer) {
714 int32_t writeBytes;
715 if ((writeBytes = fBuffer->bufferSize - fBuffer->bytesLeft)) {
716 if (gzwrite(gzfp, fBuffer->buffer, writeBytes) != writeBytes)
717 return 0;
718 fBuffer->bytesLeft = fBuffer->bufferSize;
719 fBuffer->data = fBuffer->buffer;
720 }
721 /*gzflush(gzfp, Z_FULL_FLUSH); */
722 return 1;
723}
724#endif
725
726/**
727 * Writes a binary page of data to an SDDS dataset, handling compression and buffering.
728 *
729 * This function writes a binary page (including parameters, arrays, and row data) to the SDDS dataset
730 * pointed to by `SDDS_dataset`. It handles different file types, including regular files, LZMA-compressed
731 * files, and GZIP-compressed files, and uses buffering to improve write performance.
732 *
733 * The function performs the following steps:
734 * - Checks for output endianess and writes a non-native binary page if needed.
735 * - Determines the number of rows to write and calculates any fixed row counts.
736 * - Writes the number of rows to the file.
737 * - Writes parameters, arrays, and column data using the appropriate write functions.
738 * - Flushes the buffer to ensure all data is written.
739 *
740 * It uses the appropriate buffered write functions (`SDDS_BufferedWrite`, `SDDS_LZMABufferedWrite`, or
741 * `SDDS_GZipBufferedWrite`) depending on the file type.
742 *
743 * @param SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the SDDS dataset to write to.
744 *
745 * @return Returns 1 on success; returns 0 on error.
746 *
747 * @note The function sets error messages using `SDDS_SetError` if any step fails.
748 */
749int32_t SDDS_WriteBinaryPage(SDDS_DATASET *SDDS_dataset) {
750#if defined(zLib)
751 gzFile gzfp;
752#endif
753 FILE *fp;
754 struct lzmafile *lzmafp;
755 int64_t i, rows, fixed_rows;
756 int32_t min32 = INT32_MIN, rows32;
757 /* static char buffer[SDDS_MAXLINE]; */
758 SDDS_FILEBUFFER *fBuffer;
759 char *outputEndianess = NULL;
760
761 if ((outputEndianess = getenv("SDDS_OUTPUT_ENDIANESS"))) {
762 if (((strncmp(outputEndianess, "big", 3) == 0) && (SDDS_IsBigEndianMachine() == 0)) || ((strncmp(outputEndianess, "little", 6) == 0) && (SDDS_IsBigEndianMachine() == 1)))
763 return SDDS_WriteNonNativeBinaryPage(SDDS_dataset);
764 }
765
766 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WriteBinaryPage"))
767 return (0);
768
769#if defined(zLib)
770 if (SDDS_dataset->layout.gzipFile) {
771 if (!(gzfp = SDDS_dataset->layout.gzfp)) {
772 SDDS_SetError("Unable to write page--file pointer is NULL (SDDS_WriteBinaryPage)");
773 return (0);
774 }
775 fBuffer = &SDDS_dataset->fBuffer;
776
777 if (!fBuffer->buffer) {
778 if (!(fBuffer->buffer = fBuffer->data = SDDS_Malloc(sizeof(char) * (defaultIOBufferSize + 1)))) {
779 SDDS_SetError("Unable to do buffered read--allocation failure (SDDS_WriteBinaryPage)");
780 return 0;
781 }
782 fBuffer->bufferSize = defaultIOBufferSize;
783 fBuffer->bytesLeft = defaultIOBufferSize;
784 }
785
786 rows = SDDS_CountRowsOfInterest(SDDS_dataset);
787 SDDS_dataset->rowcount_offset = gztell(gzfp);
788 if (SDDS_dataset->layout.data_mode.fixed_row_count) {
789 fixed_rows = ((rows / SDDS_dataset->layout.data_mode.fixed_row_increment) + 2) * SDDS_dataset->layout.data_mode.fixed_row_increment;
790 if (fixed_rows > INT32_MAX) {
791 if (!SDDS_GZipBufferedWrite(&min32, sizeof(min32), gzfp, fBuffer)) {
792 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteBinaryPage)");
793 return (0);
794 }
795 if (!SDDS_GZipBufferedWrite(&fixed_rows, sizeof(fixed_rows), gzfp, fBuffer)) {
796 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteBinaryPage)");
797 return (0);
798 }
799 } else {
800 rows32 = (int32_t)fixed_rows;
801 if (!SDDS_GZipBufferedWrite(&rows32, sizeof(rows32), gzfp, fBuffer)) {
802 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteBinaryPage)");
803 return (0);
804 }
805 }
806 } else {
807 if (rows > INT32_MAX) {
808 if (!SDDS_GZipBufferedWrite(&min32, sizeof(min32), gzfp, fBuffer)) {
809 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteBinaryPage)");
810 return (0);
811 }
812 if (!SDDS_GZipBufferedWrite(&rows, sizeof(rows), gzfp, fBuffer)) {
813 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteBinaryPage)");
814 return (0);
815 }
816 } else {
817 rows32 = (int32_t)rows;
818 if (!SDDS_GZipBufferedWrite(&rows32, sizeof(rows32), gzfp, fBuffer)) {
819 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteBinaryPage)");
820 return (0);
821 }
822 }
823 }
824 if (!SDDS_WriteBinaryParameters(SDDS_dataset)) {
825 SDDS_SetError("Unable to write page--parameter writing problem (SDDS_WriteBinaryPage)");
826 return 0;
827 }
828 if (!SDDS_WriteBinaryArrays(SDDS_dataset)) {
829 SDDS_SetError("Unable to write page--array writing problem (SDDS_WriteBinaryPage)");
830 return 0;
831 }
832 if (SDDS_dataset->layout.n_columns) {
833 if (SDDS_dataset->layout.data_mode.column_major) {
834 if (!SDDS_WriteBinaryColumns(SDDS_dataset)) {
835 SDDS_SetError("Unable to write page--column writing problem (SDDS_WriteBinaryPage)");
836 return 0;
837 }
838 } else {
839 for (i = 0; i < SDDS_dataset->n_rows; i++) {
840 if (SDDS_dataset->row_flag[i] && !SDDS_WriteBinaryRow(SDDS_dataset, i)) {
841 SDDS_SetError("Unable to write page--row writing problem (SDDS_WriteBinaryPage)");
842 return 0;
843 }
844 }
845 }
846 }
847 if (!SDDS_GZipFlushBuffer(gzfp, fBuffer)) {
848 SDDS_SetError("Unable to write page--buffer flushing problem (SDDS_WriteBinaryPage)");
849 return 0;
850 }
851 SDDS_dataset->last_row_written = SDDS_dataset->n_rows - 1;
852 SDDS_dataset->n_rows_written = rows;
853 SDDS_dataset->writing_page = 1;
854 } else {
855#endif
856 if (SDDS_dataset->layout.lzmaFile) {
857 if (!(lzmafp = SDDS_dataset->layout.lzmafp)) {
858 SDDS_SetError("Unable to write page--file pointer is NULL (SDDS_WriteBinaryPage)");
859 return (0);
860 }
861 fBuffer = &SDDS_dataset->fBuffer;
862
863 if (!fBuffer->buffer) {
864 if (!(fBuffer->buffer = fBuffer->data = SDDS_Malloc(sizeof(char) * (defaultIOBufferSize + 1)))) {
865 SDDS_SetError("Unable to do buffered read--allocation failure (SDDS_WriteBinaryPage)");
866 return 0;
867 }
868 fBuffer->bufferSize = defaultIOBufferSize;
869 fBuffer->bytesLeft = defaultIOBufferSize;
870 }
871 rows = SDDS_CountRowsOfInterest(SDDS_dataset);
872 SDDS_dataset->rowcount_offset = lzma_tell(lzmafp);
873 if (SDDS_dataset->layout.data_mode.fixed_row_count) {
874 fixed_rows = ((rows / SDDS_dataset->layout.data_mode.fixed_row_increment) + 2) * SDDS_dataset->layout.data_mode.fixed_row_increment;
875 if (fixed_rows > INT32_MAX) {
876 if (!SDDS_LZMABufferedWrite(&min32, sizeof(min32), lzmafp, fBuffer)) {
877 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteBinaryPage)");
878 return (0);
879 }
880 if (!SDDS_LZMABufferedWrite(&fixed_rows, sizeof(fixed_rows), lzmafp, fBuffer)) {
881 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteBinaryPage)");
882 return (0);
883 }
884 } else {
885 rows32 = (int32_t)fixed_rows;
886 if (!SDDS_LZMABufferedWrite(&rows32, sizeof(rows32), lzmafp, fBuffer)) {
887 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteBinaryPage)");
888 return (0);
889 }
890 }
891 } else {
892 if (rows > INT32_MAX) {
893 if (!SDDS_LZMABufferedWrite(&min32, sizeof(min32), lzmafp, fBuffer)) {
894 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteBinaryPage)");
895 return (0);
896 }
897 if (!SDDS_LZMABufferedWrite(&rows, sizeof(rows), lzmafp, fBuffer)) {
898 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteBinaryPage)");
899 return (0);
900 }
901 } else {
902 rows32 = (int32_t)rows;
903 if (!SDDS_LZMABufferedWrite(&rows32, sizeof(rows32), lzmafp, fBuffer)) {
904 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteBinaryPage)");
905 return (0);
906 }
907 }
908 }
909 if (!SDDS_WriteBinaryParameters(SDDS_dataset)) {
910 SDDS_SetError("Unable to write page--parameter writing problem (SDDS_WriteBinaryPage)");
911 return 0;
912 }
913 if (!SDDS_WriteBinaryArrays(SDDS_dataset)) {
914 SDDS_SetError("Unable to write page--array writing problem (SDDS_WriteBinaryPage)");
915 return 0;
916 }
917 if (SDDS_dataset->layout.n_columns) {
918 if (SDDS_dataset->layout.data_mode.column_major) {
919 if (!SDDS_WriteBinaryColumns(SDDS_dataset)) {
920 SDDS_SetError("Unable to write page--column writing problem (SDDS_WriteBinaryPage)");
921 return 0;
922 }
923 } else {
924 for (i = 0; i < SDDS_dataset->n_rows; i++) {
925 if (SDDS_dataset->row_flag[i] && !SDDS_WriteBinaryRow(SDDS_dataset, i)) {
926 SDDS_SetError("Unable to write page--row writing problem (SDDS_WriteBinaryPage)");
927 return 0;
928 }
929 }
930 }
931 }
932 if (!SDDS_LZMAFlushBuffer(lzmafp, fBuffer)) {
933 SDDS_SetError("Unable to write page--buffer flushing problem (SDDS_WriteBinaryPage)");
934 return 0;
935 }
936 SDDS_dataset->last_row_written = SDDS_dataset->n_rows - 1;
937 SDDS_dataset->n_rows_written = rows;
938 SDDS_dataset->writing_page = 1;
939 } else {
940 if (!(fp = SDDS_dataset->layout.fp)) {
941 SDDS_SetError("Unable to write page--file pointer is NULL (SDDS_WriteBinaryPage)");
942 return (0);
943 }
944 fBuffer = &SDDS_dataset->fBuffer;
945
946 if (!fBuffer->buffer) {
947 if (!(fBuffer->buffer = fBuffer->data = SDDS_Malloc(sizeof(char) * (defaultIOBufferSize + 1)))) {
948 SDDS_SetError("Unable to do buffered read--allocation failure (SDDS_WriteBinaryPage)");
949 return 0;
950 }
951 fBuffer->bufferSize = defaultIOBufferSize;
952 fBuffer->bytesLeft = defaultIOBufferSize;
953 }
954
955 /* Flush any existing data in the output buffer so we can determine the
956 * row count offset for the file. This is probably unnecessary.
957 */
958 if (!SDDS_FlushBuffer(fp, fBuffer)) {
959 SDDS_SetError("Unable to write page--buffer flushing problem (SDDS_WriteBinaryPage)");
960 return 0;
961 }
962
963 /* output the row count and determine its byte offset in the file */
964 rows = SDDS_CountRowsOfInterest(SDDS_dataset);
965 SDDS_dataset->rowcount_offset = ftell(fp);
966 if (SDDS_dataset->layout.data_mode.fixed_row_count) {
967 fixed_rows = ((rows / SDDS_dataset->layout.data_mode.fixed_row_increment) + 2) * SDDS_dataset->layout.data_mode.fixed_row_increment;
968#if defined(DEBUG)
969 fprintf(stderr, "setting %" PRId64 " fixed rows\n", fixed_rows);
970#endif
971 if (fixed_rows > INT32_MAX) {
972 if (!SDDS_BufferedWrite(&min32, sizeof(min32), fp, fBuffer)) {
973 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteBinaryPage)");
974 return (0);
975 }
976 if (!SDDS_BufferedWrite(&fixed_rows, sizeof(fixed_rows), fp, fBuffer)) {
977 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteBinaryPage)");
978 return (0);
979 }
980 } else {
981 rows32 = (int32_t)fixed_rows;
982 if (!SDDS_BufferedWrite(&rows32, sizeof(rows32), fp, fBuffer)) {
983 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteBinaryPage)");
984 return (0);
985 }
986 }
987 } else {
988#if defined(DEBUG)
989 fprintf(stderr, "setting %" PRId64 " rows\n", rows);
990#endif
991 if (rows > INT32_MAX) {
992 if (!SDDS_BufferedWrite(&min32, sizeof(min32), fp, fBuffer)) {
993 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteBinaryPage)");
994 return (0);
995 }
996 if (!SDDS_BufferedWrite(&rows, sizeof(rows), fp, fBuffer)) {
997 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteBinaryPage)");
998 return (0);
999 }
1000 } else {
1001 rows32 = (int32_t)rows;
1002 if (!SDDS_BufferedWrite(&rows32, sizeof(rows32), fp, fBuffer)) {
1003 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteBinaryPage)");
1004 return (0);
1005 }
1006 }
1007 }
1008
1009 /* write the data, using buffered I/O */
1010 if (!SDDS_WriteBinaryParameters(SDDS_dataset)) {
1011 SDDS_SetError("Unable to write page--parameter writing problem (SDDS_WriteBinaryPage)");
1012 return 0;
1013 }
1014 if (!SDDS_WriteBinaryArrays(SDDS_dataset)) {
1015 SDDS_SetError("Unable to write page--array writing problem (SDDS_WriteBinaryPage)");
1016 return 0;
1017 }
1018 if (SDDS_dataset->layout.n_columns) {
1019 if (SDDS_dataset->layout.data_mode.column_major) {
1020 if (!SDDS_WriteBinaryColumns(SDDS_dataset)) {
1021 SDDS_SetError("Unable to write page--column writing problem (SDDS_WriteBinaryPage)");
1022 return 0;
1023 }
1024 } else {
1025 for (i = 0; i < SDDS_dataset->n_rows; i++) {
1026 if (SDDS_dataset->row_flag[i] && !SDDS_WriteBinaryRow(SDDS_dataset, i)) {
1027 SDDS_SetError("Unable to write page--row writing problem (SDDS_WriteBinaryPage)");
1028 return 0;
1029 }
1030 }
1031 }
1032 }
1033 /* flush the page */
1034 if (!SDDS_FlushBuffer(fp, fBuffer)) {
1035 SDDS_SetError("Unable to write page--buffer flushing problem (SDDS_WriteBinaryPage)");
1036 return 0;
1037 }
1038 SDDS_dataset->last_row_written = SDDS_dataset->n_rows - 1;
1039 SDDS_dataset->n_rows_written = rows;
1040 SDDS_dataset->writing_page = 1;
1041 }
1042#if defined(zLib)
1043 }
1044#endif
1045 return (1);
1046}
1047
1048/**
1049 * @brief Updates the binary page of an SDDS dataset.
1050 *
1051 * This function updates the binary page of the specified SDDS dataset based on the provided mode.
1052 * It handles writing the dataset's binary data to the associated file, managing buffering, and
1053 * handling different file formats such as gzip and LZMA if applicable.
1054 *
1055 * @param SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset to update.
1056 * @param mode Bitmask indicating the update mode. It can be:
1057 * - `0` for a standard update.
1058 * - `FLUSH_TABLE` to flush the table after updating.
1059 *
1060 * @return
1061 * - Returns `1` on successful update.
1062 * - Returns `0` if an error occurs during the update process.
1063 *
1064 * @details
1065 * The function performs several checks before updating:
1066 * - Checks the environment variable `SDDS_OUTPUT_ENDIANESS` to determine if a non-native
1067 * binary update is required.
1068 * - Validates the dataset structure.
1069 * - Ensures that the dataset is not using gzip or LZMA compression, or is not in column-major
1070 * data mode.
1071 * - Handles writing the binary page, updating row counts, and managing buffer flushing.
1072 *
1073 * @note
1074 * - The function is not thread-safe and should be called in a synchronized context.
1075 * - Requires that the dataset has been properly initialized and populated with data.
1076 */
1077int32_t SDDS_UpdateBinaryPage(SDDS_DATASET *SDDS_dataset, uint32_t mode) {
1078 FILE *fp;
1079 int64_t i, rows, offset, code, fixed_rows;
1080 int32_t min32 = INT32_MIN, rows32;
1081 SDDS_FILEBUFFER *fBuffer;
1082 char *outputEndianess = NULL;
1083
1084 if ((outputEndianess = getenv("SDDS_OUTPUT_ENDIANESS"))) {
1085 if (((strncmp(outputEndianess, "big", 3) == 0) && (SDDS_IsBigEndianMachine() == 0)) || ((strncmp(outputEndianess, "little", 6) == 0) && (SDDS_IsBigEndianMachine() == 1)))
1086 return SDDS_UpdateNonNativeBinaryPage(SDDS_dataset, mode);
1087 }
1088
1089#ifdef DEBUG
1090 fprintf(stderr, "%" PRId64 " virtual rows present, first=%" PRId64 "\n", SDDS_CountRowsOfInterest(SDDS_dataset), SDDS_dataset->first_row_in_mem);
1091#endif
1092 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_UpdateBinaryPage"))
1093 return (0);
1094#if defined(zLib)
1095 if (SDDS_dataset->layout.gzipFile) {
1096 SDDS_SetError("Unable to perform page updates on a gzip file (SDDS_UpdateBinaryPage)");
1097 return 0;
1098 }
1099#endif
1100 if (SDDS_dataset->layout.lzmaFile) {
1101 SDDS_SetError("Unable to perform page updates on an .lzma or .xz file (SDDS_UpdateBinaryPage)");
1102 return 0;
1103 }
1104 if (SDDS_dataset->layout.data_mode.column_major) {
1105 SDDS_SetError("Unable to perform page updates on column major order file. (SDDS_UpdateBinaryPage)");
1106 return 0;
1107 }
1108 if (!SDDS_dataset->writing_page) {
1109#ifdef DEBUG
1110 fprintf(stderr, "Page not being written---calling SDDS_UpdateBinaryPage\n");
1111#endif
1112 if (!(code = SDDS_WriteBinaryPage(SDDS_dataset)))
1113 return 0;
1114 if (mode & FLUSH_TABLE) {
1115 SDDS_FreeTableStrings(SDDS_dataset);
1116 SDDS_dataset->first_row_in_mem = SDDS_CountRowsOfInterest(SDDS_dataset);
1117 SDDS_dataset->last_row_written = -1;
1118 SDDS_dataset->n_rows = 0;
1119 }
1120 return code;
1121 }
1122
1123 if (!(fp = SDDS_dataset->layout.fp)) {
1124 SDDS_SetError("Unable to update page--file pointer is NULL (SDDS_UpdateBinaryPage)");
1125 return (0);
1126 }
1127 fBuffer = &SDDS_dataset->fBuffer;
1128 if (!SDDS_FlushBuffer(fp, fBuffer)) {
1129 SDDS_SetError("Unable to write page--buffer flushing problem (SDDS_UpdateBinaryPage)");
1130 return 0;
1131 }
1132 offset = ftell(fp);
1133
1134 rows = SDDS_CountRowsOfInterest(SDDS_dataset) + SDDS_dataset->first_row_in_mem;
1135#ifdef DEBUG
1136 fprintf(stderr, "%" PRId64 " rows stored in table, %" PRId64 " already written\n", rows, SDDS_dataset->n_rows_written);
1137#endif
1138 if (rows == SDDS_dataset->n_rows_written)
1139 return (1);
1140 if (rows < SDDS_dataset->n_rows_written) {
1141 SDDS_SetError("Unable to update page--new number of rows less than previous number (SDDS_UpdateBinaryPage)");
1142 return (0);
1143 }
1144 if ((!SDDS_dataset->layout.data_mode.fixed_row_count) || (((rows + rows - SDDS_dataset->n_rows_written) / SDDS_dataset->layout.data_mode.fixed_row_increment) != (rows / SDDS_dataset->layout.data_mode.fixed_row_increment))) {
1145 if (SDDS_fseek(fp, SDDS_dataset->rowcount_offset, 0) == -1) {
1146 SDDS_SetError("Unable to update page--failure doing fseek (SDDS_UpdateBinaryPage)");
1147 return (0);
1148 }
1149 if (SDDS_dataset->layout.data_mode.fixed_row_count) {
1150 if ((rows - SDDS_dataset->n_rows_written) + 1 > SDDS_dataset->layout.data_mode.fixed_row_increment) {
1151 SDDS_dataset->layout.data_mode.fixed_row_increment = (rows - SDDS_dataset->n_rows_written) + 1;
1152 }
1153 fixed_rows = ((rows / SDDS_dataset->layout.data_mode.fixed_row_increment) + 2) * SDDS_dataset->layout.data_mode.fixed_row_increment;
1154#if defined(DEBUG)
1155 fprintf(stderr, "Setting %" PRId64 " fixed rows\n", fixed_rows);
1156#endif
1157 if ((fixed_rows > INT32_MAX) && (SDDS_dataset->n_rows_written <= INT32_MAX)) {
1158 SDDS_SetError("Unable to update page--crossed the INT32_MAX row boundary (SDDS_UpdateBinaryPage)");
1159 return (0);
1160 }
1161 if (fixed_rows > INT32_MAX) {
1162 if (fwrite(&min32, sizeof(min32), 1, fp) != 1) {
1163 SDDS_SetError("Unable to update page--failure writing number of rows (SDDS_UpdateBinaryPage)");
1164 return (0);
1165 }
1166 if (fwrite(&fixed_rows, sizeof(fixed_rows), 1, fp) != 1) {
1167 SDDS_SetError("Unable to update page--failure writing number of rows (SDDS_UpdateBinaryPage)");
1168 return (0);
1169 }
1170 } else {
1171 rows32 = (int32_t)fixed_rows;
1172 if (fwrite(&fixed_rows, sizeof(rows32), 1, fp) != 1) {
1173 SDDS_SetError("Unable to update page--failure writing number of rows (SDDS_UpdateBinaryPage)");
1174 return (0);
1175 }
1176 }
1177 } else {
1178#if defined(DEBUG)
1179 fprintf(stderr, "Setting %" PRId64 " rows\n", rows);
1180#endif
1181 if ((rows > INT32_MAX) && (SDDS_dataset->n_rows_written <= INT32_MAX)) {
1182 SDDS_SetError("Unable to update page--crossed the INT32_MAX row boundary (SDDS_UpdateBinaryPage)");
1183 return (0);
1184 }
1185 if (rows > INT32_MAX) {
1186 if (fwrite(&min32, sizeof(min32), 1, fp) != 1) {
1187 SDDS_SetError("Unable to update page--failure writing number of rows (SDDS_UpdateBinaryPage)");
1188 return (0);
1189 }
1190 if (fwrite(&rows, sizeof(rows), 1, fp) != 1) {
1191 SDDS_SetError("Unable to update page--failure writing number of rows (SDDS_UpdateBinaryPage)");
1192 return (0);
1193 }
1194 } else {
1195 rows32 = (int32_t)rows;
1196 if (fwrite(&rows32, sizeof(rows32), 1, fp) != 1) {
1197 SDDS_SetError("Unable to update page--failure writing number of rows (SDDS_UpdateBinaryPage)");
1198 return (0);
1199 }
1200 }
1201 }
1202 if (SDDS_fseek(fp, offset, 0) == -1) {
1203 SDDS_SetError("Unable to update page--failure doing fseek to end of page (SDDS_UpdateBinaryPage)");
1204 return (0);
1205 }
1206 }
1207 for (i = SDDS_dataset->last_row_written + 1; i < SDDS_dataset->n_rows; i++)
1208 if (SDDS_dataset->row_flag[i] && !SDDS_WriteBinaryRow(SDDS_dataset, i)) {
1209 SDDS_SetError("Unable to update page--failure writing row (SDDS_UpdateBinaryPage)");
1210 return (0);
1211 }
1212#ifdef DEBUG
1213 fprintf(stderr, "Flushing buffer\n");
1214#endif
1215 if (!SDDS_FlushBuffer(fp, fBuffer)) {
1216 SDDS_SetError("Unable to write page--buffer flushing problem (SDDS_UpdateBinaryPage)");
1217 return 0;
1218 }
1219 SDDS_dataset->last_row_written = SDDS_dataset->n_rows - 1;
1220 SDDS_dataset->n_rows_written = rows;
1221 if (mode & FLUSH_TABLE) {
1222 SDDS_FreeTableStrings(SDDS_dataset);
1223 SDDS_dataset->first_row_in_mem = rows;
1224 SDDS_dataset->last_row_written = -1;
1225 SDDS_dataset->n_rows = 0;
1226 }
1227 return (1);
1228}
1229
1230#define FSEEK_TRIES 10
1231/**
1232 * @brief Sets the file position indicator for a given file stream with retry logic.
1233 *
1234 * Attempts to set the file position indicator for the specified file stream (`fp`) to a new position
1235 * defined by `offset` and `dir`. The function retries the `fseek` operation up to `FSEEK_TRIES`
1236 * times in case of transient failures, implementing a delay between attempts.
1237 *
1238 * @param fp Pointer to the `FILE` stream whose position indicator is to be set.
1239 * @param offset Number of bytes to offset from the position specified by `dir`.
1240 * @param dir Positioning directive, which can be one of:
1241 * - `SEEK_SET` to set the position relative to the beginning of the file,
1242 * - `SEEK_CUR` to set the position relative to the current position,
1243 * - `SEEK_END` to set the position relative to the end of the file.
1244 *
1245 * @return
1246 * - Returns `0` if the operation is successful.
1247 * - Returns `-1` if all retry attempts fail to set the file position.
1248 *
1249 * @details
1250 * The function attempts to set the file position using `fseek`. If `fseek` fails, it sleeps for 1 second
1251 * (or 1 second using `nanosleep` on vxWorks systems) before retrying. After `FSEEK_TRIES` unsuccessful
1252 * attempts, it reports a warning and returns `-1`.
1253 *
1254 * @note
1255 * - The function is designed to handle temporary file access issues by retrying the `fseek` operation.
1256 * - It is not suitable for non-recoverable `fseek` errors, which will cause it to fail after retries.
1257 */
1258int32_t SDDS_fseek(FILE *fp, int64_t offset, int32_t dir) {
1259 int32_t try;
1260#if defined(vxWorks)
1261 struct timespec rqtp;
1262 rqtp.tv_sec = 1;
1263 rqtp.tv_nsec = 0;
1264#endif
1265 for (try = 0; try < FSEEK_TRIES; try++) {
1266 if (fseek(fp, offset, dir) == -1) {
1267#if defined(vxWorks)
1268 nanosleep(&rqtp, NULL);
1269#else
1270 sleep(1);
1271#endif
1272 } else
1273 break;
1274 }
1275 if (try == 0)
1276 return 0;
1277 if (try == FSEEK_TRIES) {
1278 fputs("warning: fseek problems--unable to recover\n", stderr);
1279 return -1;
1280 }
1281 fputs("warning: fseek problems--recovered\n", stderr);
1282 return 0;
1283}
1284
1285/**
1286 * @brief Sets the file position indicator for a given LZMA file stream with retry logic.
1287 *
1288 * Attempts to set the file position indicator for the specified LZMA file stream (`lzmafp`) to a new position
1289 * defined by `offset` and `dir`. The function retries the `lzma_seek` operation up to `FSEEK_TRIES`
1290 * times in case of transient failures, implementing a delay between attempts.
1291 *
1292 * @param lzmafp Pointer to the `lzmafile` stream whose position indicator is to be set.
1293 * @param offset Number of bytes to offset from the position specified by `dir`.
1294 * @param dir Positioning directive, which can be one of:
1295 * - `SEEK_SET` to set the position relative to the beginning of the file,
1296 * - `SEEK_CUR` to set the position relative to the current position,
1297 * - `SEEK_END` to set the position relative to the end of the file.
1298 *
1299 * @return
1300 * - Returns `0` if the operation is successful.
1301 * - Returns `-1` if all retry attempts fail to set the file position.
1302 *
1303 * @details
1304 * The function attempts to set the file position using `lzma_seek`. If `lzma_seek` fails, it sleeps for 1 second
1305 * (or 1 second using `nanosleep` on vxWorks systems) before retrying. After `FSEEK_TRIES` unsuccessful
1306 * attempts, it reports a warning and returns `-1`.
1307 *
1308 * @note
1309 * - The function is designed to handle temporary file access issues by retrying the `lzma_seek` operation.
1310 * - It is not suitable for non-recoverable `lzma_seek` errors, which will cause it to fail after retries.
1311 */
1312int32_t SDDS_lzmaseek(struct lzmafile *lzmafp, int64_t offset, int32_t dir) {
1313 int32_t try;
1314#if defined(vxWorks)
1315 struct timespec rqtp;
1316 rqtp.tv_sec = 1;
1317 rqtp.tv_nsec = 0;
1318#endif
1319 for (try = 0; try < FSEEK_TRIES; try++) {
1320 if (lzma_seek(lzmafp, offset, dir) == -1) {
1321#if defined(vxWorks)
1322 nanosleep(&rqtp, NULL);
1323#else
1324 sleep(1);
1325#endif
1326 } else
1327 break;
1328 }
1329 if (try == 0)
1330 return 0;
1331 if (try == FSEEK_TRIES) {
1332 fputs("warning: lzma_seek problems--unable to recover\n", stderr);
1333 return -1;
1334 }
1335 fputs("warning: lzma_seek problems--recovered\n", stderr);
1336 return 0;
1337}
1338
1339#if defined(zLib)
1340/**
1341 * @brief Sets the file position indicator for a given GZIP file stream with retry logic.
1342 *
1343 * Attempts to set the file position indicator for the specified GZIP file stream (`gzfp`) to a new position
1344 * defined by `offset` and `dir`. The function retries the `gzseek` operation up to `FSEEK_TRIES`
1345 * times in case of transient failures, implementing a delay between attempts.
1346 *
1347 * @param gzfp Pointer to the `gzFile` stream whose position indicator is to be set.
1348 * @param offset Number of bytes to offset from the position specified by `dir`.
1349 * @param dir Positioning directive, which can be one of:
1350 * - `SEEK_SET` to set the position relative to the beginning of the file,
1351 * - `SEEK_CUR` to set the position relative to the current position,
1352 * - `SEEK_END` to set the position relative to the end of the file.
1353 *
1354 * @return
1355 * - Returns `0` if the operation is successful.
1356 * - Returns `-1` if all retry attempts fail to set the file position.
1357 *
1358 * @details
1359 * The function attempts to set the file position using `gzseek`. If `gzseek` fails, it sleeps for 1 second
1360 * (or 1 second using `nanosleep` on vxWorks systems) before retrying. After `FSEEK_TRIES` unsuccessful
1361 * attempts, it reports a warning and returns `-1`.
1362 *
1363 * @note
1364 * - The function is designed to handle temporary file access issues by retrying the `gzseek` operation.
1365 * - It is not suitable for non-recoverable `gzseek` errors, which will cause it to fail after retries.
1366 */
1367int32_t SDDS_gzseek(gzFile gzfp, int64_t offset, int32_t dir) {
1368 int32_t try;
1369# if defined(vxWorks)
1370 struct timespec rqtp;
1371 rqtp.tv_sec = 1;
1372 rqtp.tv_nsec = 0;
1373# endif
1374 for (try = 0; try < FSEEK_TRIES; try++) {
1375 if (gzseek(gzfp, offset, dir) == -1) {
1376# if defined(vxWorks)
1377 nanosleep(&rqtp, NULL);
1378# else
1379 sleep(1);
1380# endif
1381 } else
1382 break;
1383 }
1384 if (try == 0)
1385 return 0;
1386 if (try == FSEEK_TRIES) {
1387 fputs("warning: gzseek problems--unable to recover\n", stderr);
1388 return -1;
1389 }
1390 fputs("warning: gzseek problems--recovered\n", stderr);
1391 return 0;
1392}
1393#endif
1394
1395/**
1396 * @brief Writes the binary parameters of the SDDS dataset.
1397 *
1398 * This function writes all non-fixed parameters of the SDDS dataset to the associated binary file.
1399 * It handles different compression formats such as gzip and LZMA if enabled.
1400 *
1401 * @param SDDS_dataset Pointer to the `SDDS_DATASET` structure containing the dataset to write.
1402 *
1403 * @return
1404 * - Returns `1` on successful write of all parameters.
1405 * - Returns `0` if an error occurs during the writing process.
1406 *
1407 * @details
1408 * The function performs the following steps:
1409 * - Validates the dataset structure.
1410 * - Iterates over all parameters defined in the dataset layout.
1411 * - For each parameter:
1412 * - If it is a fixed value, it is skipped.
1413 * - If the parameter is of type `SDDS_STRING`, it writes the string using the appropriate
1414 * compression method.
1415 * - Otherwise, it writes the parameter's value using buffered write functions.
1416 *
1417 * The function handles different file formats:
1418 * - For gzip files, it uses `SDDS_GZipWriteBinaryString` and `SDDS_GZipBufferedWrite`.
1419 * - For LZMA files, it uses `SDDS_LZMAWriteBinaryString` and `SDDS_LZMABufferedWrite`.
1420 * - For standard binary files, it uses `SDDS_WriteBinaryString` and `SDDS_BufferedWrite`.
1421 *
1422 * @note
1423 * - The function assumes that the dataset has been properly initialized and that all parameters are correctly allocated.
1424 * - Compression support (`zLib` or LZMA) must be enabled during compilation for handling compressed files.
1425 */
1427 int32_t i;
1428 SDDS_LAYOUT *layout;
1429 /* char *predefined_format; */
1430 /* static char buffer[SDDS_MAXLINE]; */
1431#if defined(zLib)
1432 gzFile gzfp;
1433#endif
1434 FILE *fp;
1435 struct lzmafile *lzmafp;
1436 SDDS_FILEBUFFER *fBuffer;
1437
1438 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WriteBinaryParameters"))
1439 return (0);
1440 layout = &SDDS_dataset->layout;
1441#if defined(zLib)
1442 if (SDDS_dataset->layout.gzipFile) {
1443 gzfp = layout->gzfp;
1444 fBuffer = &SDDS_dataset->fBuffer;
1445 for (i = 0; i < layout->n_parameters; i++) {
1446 if (layout->parameter_definition[i].fixed_value)
1447 continue;
1448 if (layout->parameter_definition[i].type == SDDS_STRING) {
1449 if (!SDDS_GZipWriteBinaryString(*((char **)SDDS_dataset->parameter[i]), gzfp, fBuffer)) {
1450 SDDS_SetError("Unable to write parameters--failure writing string (SDDS_WriteBinaryParameters)");
1451 return (0);
1452 }
1453 } else if (!SDDS_GZipBufferedWrite(SDDS_dataset->parameter[i], SDDS_type_size[layout->parameter_definition[i].type - 1], gzfp, fBuffer)) {
1454 SDDS_SetError("Unable to write parameters--failure writing value (SDDS_WriteBinaryParameters)");
1455 return (0);
1456 }
1457 }
1458 } else {
1459#endif
1460 if (SDDS_dataset->layout.lzmaFile) {
1461 lzmafp = layout->lzmafp;
1462 fBuffer = &SDDS_dataset->fBuffer;
1463 for (i = 0; i < layout->n_parameters; i++) {
1464 if (layout->parameter_definition[i].fixed_value)
1465 continue;
1466 if (layout->parameter_definition[i].type == SDDS_STRING) {
1467 if (!SDDS_LZMAWriteBinaryString(*((char **)SDDS_dataset->parameter[i]), lzmafp, fBuffer)) {
1468 SDDS_SetError("Unable to write parameters--failure writing string (SDDS_WriteBinaryParameters)");
1469 return (0);
1470 }
1471 } else if (!SDDS_LZMABufferedWrite(SDDS_dataset->parameter[i], SDDS_type_size[layout->parameter_definition[i].type - 1], lzmafp, fBuffer)) {
1472 SDDS_SetError("Unable to write parameters--failure writing value (SDDS_WriteBinaryParameters)");
1473 return (0);
1474 }
1475 }
1476 } else {
1477 fp = layout->fp;
1478 fBuffer = &SDDS_dataset->fBuffer;
1479 for (i = 0; i < layout->n_parameters; i++) {
1480 if (layout->parameter_definition[i].fixed_value)
1481 continue;
1482 if (layout->parameter_definition[i].type == SDDS_STRING) {
1483 if (!SDDS_WriteBinaryString(*((char **)SDDS_dataset->parameter[i]), fp, fBuffer)) {
1484 SDDS_SetError("Unable to write parameters--failure writing string (SDDS_WriteBinaryParameters)");
1485 return (0);
1486 }
1487 } else if (!SDDS_BufferedWrite(SDDS_dataset->parameter[i], SDDS_type_size[layout->parameter_definition[i].type - 1], fp, fBuffer)) {
1488 SDDS_SetError("Unable to write parameters--failure writing value (SDDS_WriteBinaryParameters)");
1489 return (0);
1490 }
1491 }
1492 }
1493#if defined(zLib)
1494 }
1495#endif
1496 return (1);
1497}
1498
1499/**
1500 * @brief Writes the binary arrays of the SDDS dataset to a file.
1501 *
1502 * This function writes all arrays defined in the SDDS dataset to the associated binary file.
1503 * It handles arrays with and without dimensions, and manages different compression formats
1504 * such as gzip and LZMA if enabled.
1505 *
1506 * @param SDDS_dataset Pointer to the `SDDS_DATASET` structure containing the dataset to write.
1507 *
1508 * @return
1509 * - Returns `1` on successful write of all arrays.
1510 * - Returns `0` if an error occurs during the writing process.
1511 *
1512 * @details
1513 * The function performs the following steps:
1514 * - Validates the dataset structure.
1515 * - Iterates over all arrays defined in the dataset layout.
1516 * - For each array:
1517 * - If the array has no dimensions, it writes zeroes for each defined dimension.
1518 * - If the array has dimensions, it writes the dimension sizes using the appropriate
1519 * compression method.
1520 * - If the array type is `SDDS_STRING`, it writes each string element using the appropriate
1521 * compression method.
1522 * - Otherwise, it writes the array's data using buffered write functions.
1523 *
1524 * The function handles different file formats:
1525 * - For gzip files, it uses `SDDS_GZipWriteBinaryString` and `SDDS_GZipBufferedWrite`.
1526 * - For LZMA files, it uses `SDDS_LZMAWriteBinaryString` and `SDDS_LZMABufferedWrite`.
1527 * - For standard binary files, it uses `SDDS_WriteBinaryString` and `SDDS_BufferedWrite`.
1528 *
1529 * @note
1530 * - The function assumes that the dataset has been properly initialized and that all arrays are correctly allocated.
1531 * - Compression support (`zLib` or LZMA) must be enabled during compilation for handling compressed files.
1532 */
1533int32_t SDDS_WriteBinaryArrays(SDDS_DATASET *SDDS_dataset) {
1534 int32_t i, j, zero = 0;
1535 SDDS_LAYOUT *layout;
1536#if defined(zLib)
1537 gzFile gzfp;
1538#endif
1539 FILE *fp;
1540 struct lzmafile *lzmafp;
1541 SDDS_FILEBUFFER *fBuffer;
1542
1543 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WriteBinaryArrays"))
1544 return (0);
1545 layout = &SDDS_dataset->layout;
1546#if defined(zLib)
1547 if (SDDS_dataset->layout.gzipFile) {
1548 gzfp = layout->gzfp;
1549 fBuffer = &SDDS_dataset->fBuffer;
1550 for (i = 0; i < layout->n_arrays; i++) {
1551 if (!SDDS_dataset->array[i].dimension) {
1552 for (j = 0; j < layout->array_definition[i].dimensions; j++)
1553 if (!SDDS_GZipBufferedWrite(&zero, sizeof(zero), gzfp, fBuffer)) {
1554 SDDS_SetError("Unable to write null array--failure writing dimensions (SDDS_WriteBinaryArrays)");
1555 return 0;
1556 }
1557 continue;
1558 }
1559 if (!SDDS_GZipBufferedWrite(SDDS_dataset->array[i].dimension, sizeof(*(SDDS_dataset->array)[i].dimension) * layout->array_definition[i].dimensions, gzfp, fBuffer)) {
1560 SDDS_SetError("Unable to write arrays--failure writing dimensions (SDDS_WriteBinaryArrays)");
1561 return (0);
1562 }
1563 if (layout->array_definition[i].type == SDDS_STRING) {
1564 for (j = 0; j < SDDS_dataset->array[i].elements; j++) {
1565 if (!SDDS_GZipWriteBinaryString(((char **)SDDS_dataset->array[i].data)[j], gzfp, fBuffer)) {
1566 SDDS_SetError("Unable to write arrays--failure writing string (SDDS_WriteBinaryArrays)");
1567 return (0);
1568 }
1569 }
1570 } else if (!SDDS_GZipBufferedWrite(SDDS_dataset->array[i].data, SDDS_type_size[layout->array_definition[i].type - 1] * SDDS_dataset->array[i].elements, gzfp, fBuffer)) {
1571 SDDS_SetError("Unable to write arrays--failure writing values (SDDS_WriteBinaryArrays)");
1572 return (0);
1573 }
1574 }
1575 } else {
1576#endif
1577 if (SDDS_dataset->layout.gzipFile) {
1578 lzmafp = layout->lzmafp;
1579 fBuffer = &SDDS_dataset->fBuffer;
1580 for (i = 0; i < layout->n_arrays; i++) {
1581 if (!SDDS_dataset->array[i].dimension) {
1582 for (j = 0; j < layout->array_definition[i].dimensions; j++)
1583 if (!SDDS_LZMABufferedWrite(&zero, sizeof(zero), lzmafp, fBuffer)) {
1584 SDDS_SetError("Unable to write null array--failure writing dimensions (SDDS_WriteBinaryArrays)");
1585 return 0;
1586 }
1587 continue;
1588 }
1589 if (!SDDS_LZMABufferedWrite(SDDS_dataset->array[i].dimension, sizeof(*(SDDS_dataset->array)[i].dimension) * layout->array_definition[i].dimensions, lzmafp, fBuffer)) {
1590 SDDS_SetError("Unable to write arrays--failure writing dimensions (SDDS_WriteBinaryArrays)");
1591 return (0);
1592 }
1593 if (layout->array_definition[i].type == SDDS_STRING) {
1594 for (j = 0; j < SDDS_dataset->array[i].elements; j++) {
1595 if (!SDDS_LZMAWriteBinaryString(((char **)SDDS_dataset->array[i].data)[j], lzmafp, fBuffer)) {
1596 SDDS_SetError("Unable to write arrays--failure writing string (SDDS_WriteBinaryArrays)");
1597 return (0);
1598 }
1599 }
1600 } else if (!SDDS_LZMABufferedWrite(SDDS_dataset->array[i].data, SDDS_type_size[layout->array_definition[i].type - 1] * SDDS_dataset->array[i].elements, lzmafp, fBuffer)) {
1601 SDDS_SetError("Unable to write arrays--failure writing values (SDDS_WriteBinaryArrays)");
1602 return (0);
1603 }
1604 }
1605 } else {
1606 fp = layout->fp;
1607 fBuffer = &SDDS_dataset->fBuffer;
1608 for (i = 0; i < layout->n_arrays; i++) {
1609 if (!SDDS_dataset->array[i].dimension) {
1610 for (j = 0; j < layout->array_definition[i].dimensions; j++)
1611 if (!SDDS_BufferedWrite(&zero, sizeof(zero), fp, fBuffer)) {
1612 SDDS_SetError("Unable to write null array--failure writing dimensions (SDDS_WriteBinaryArrays)");
1613 return 0;
1614 }
1615 continue;
1616 }
1617 if (!SDDS_BufferedWrite(SDDS_dataset->array[i].dimension, sizeof(*(SDDS_dataset->array)[i].dimension) * layout->array_definition[i].dimensions, fp, fBuffer)) {
1618 SDDS_SetError("Unable to write arrays--failure writing dimensions (SDDS_WriteBinaryArrays)");
1619 return (0);
1620 }
1621 if (layout->array_definition[i].type == SDDS_STRING) {
1622 for (j = 0; j < SDDS_dataset->array[i].elements; j++) {
1623 if (!SDDS_WriteBinaryString(((char **)SDDS_dataset->array[i].data)[j], fp, fBuffer)) {
1624 SDDS_SetError("Unable to write arrays--failure writing string (SDDS_WriteBinaryArrays)");
1625 return (0);
1626 }
1627 }
1628 } else if (!SDDS_BufferedWrite(SDDS_dataset->array[i].data, SDDS_type_size[layout->array_definition[i].type - 1] * SDDS_dataset->array[i].elements, fp, fBuffer)) {
1629 SDDS_SetError("Unable to write arrays--failure writing values (SDDS_WriteBinaryArrays)");
1630 return (0);
1631 }
1632 }
1633 }
1634#if defined(zLib)
1635 }
1636#endif
1637 return (1);
1638}
1639
1640/**
1641 * @brief Writes the binary columns of an SDDS dataset to the associated file.
1642 *
1643 * This function iterates over each column defined in the SDDS dataset layout and writes its data
1644 * to the binary file. It handles different data types, including strings and numeric types, and
1645 * supports various compression formats such as gzip and LZMA if enabled.
1646 *
1647 * Depending on the dataset's configuration, the function writes directly to a standard binary
1648 * file, a gzip-compressed file, or an LZMA-compressed file. It also handles sparse data by
1649 * only writing rows flagged for inclusion.
1650 *
1651 * @param SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset to write.
1652 *
1653 * @return
1654 * - Returns `1` on successful writing of all columns.
1655 * - Returns `0` if an error occurs during the writing process.
1656 *
1657 * @details
1658 * The function performs the following steps:
1659 * - Validates the dataset structure using `SDDS_CheckDataset`.
1660 * - Determines the file format (standard, gzip, LZMA) and initializes the corresponding file pointer.
1661 * - Iterates through each column in the dataset:
1662 * - For string columns, writes each string entry individually using the appropriate write function.
1663 * - For numeric columns, writes the entire column data in a buffered manner if all rows are flagged;
1664 * otherwise, writes individual row entries.
1665 * - Handles errors by setting appropriate error messages and aborting the write operation.
1666 *
1667 * @note
1668 * - The function assumes that the dataset has been properly initialized and populated with data.
1669 * - Compression support (`zLib` for gzip, LZMA libraries) must be enabled during compilation
1670 * for handling compressed files.
1671 * - The function is not thread-safe and should be called in a synchronized context.
1672 */
1674 int64_t i, row, rows, type, size;
1675 SDDS_LAYOUT *layout;
1676#if defined(zLib)
1677 gzFile gzfp;
1678#endif
1679 FILE *fp;
1680 struct lzmafile *lzmafp;
1681 SDDS_FILEBUFFER *fBuffer;
1682
1683 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WriteBinaryColumns"))
1684 return (0);
1685 layout = &SDDS_dataset->layout;
1686 fBuffer = &SDDS_dataset->fBuffer;
1687 rows = SDDS_CountRowsOfInterest(SDDS_dataset);
1688#if defined(zLib)
1689 if (SDDS_dataset->layout.gzipFile) {
1690 gzfp = layout->gzfp;
1691 for (i = 0; i < layout->n_columns; i++) {
1692 type = layout->column_definition[i].type;
1693 size = SDDS_type_size[type - 1];
1694 if (type == SDDS_STRING) {
1695 for (row = 0; row < SDDS_dataset->n_rows; row++) {
1696 if (SDDS_dataset->row_flag[row] && !SDDS_GZipWriteBinaryString(*((char **)SDDS_dataset->data[i] + row), gzfp, fBuffer)) {
1697 SDDS_SetError("Unable to write arrays--failure writing string (SDDS_WriteBinaryColumns)");
1698 return (0);
1699 }
1700 }
1701 } else {
1702 if (rows == SDDS_dataset->n_rows) {
1703 if (!SDDS_GZipBufferedWrite(SDDS_dataset->data[i], size * rows, gzfp, fBuffer)) {
1704 SDDS_SetError("Unable to write columns--failure writing values (SDDS_WriteBinaryColumns)");
1705 return (0);
1706 }
1707 } else {
1708 for (row = 0; row < SDDS_dataset->n_rows; row++) {
1709 if (SDDS_dataset->row_flag[row] && !SDDS_GZipBufferedWrite((char *)SDDS_dataset->data[i] + row * size, size, gzfp, fBuffer)) {
1710 SDDS_SetError("Unable to write columns--failure writing values (SDDS_WriteBinaryColumns)");
1711 return (0);
1712 }
1713 }
1714 }
1715 }
1716 }
1717 } else {
1718#endif
1719 if (SDDS_dataset->layout.lzmaFile) {
1720 lzmafp = layout->lzmafp;
1721 for (i = 0; i < layout->n_columns; i++) {
1722 type = layout->column_definition[i].type;
1723 size = SDDS_type_size[type - 1];
1724 if (layout->column_definition[i].type == SDDS_STRING) {
1725 for (row = 0; row < SDDS_dataset->n_rows; row++) {
1726 if (SDDS_dataset->row_flag[row] && !SDDS_LZMAWriteBinaryString(*((char **)SDDS_dataset->data[i] + row), lzmafp, fBuffer)) {
1727 SDDS_SetError("Unable to write arrays--failure writing string (SDDS_WriteBinaryColumns)");
1728 return (0);
1729 }
1730 }
1731 } else {
1732 if (rows == SDDS_dataset->n_rows) {
1733 if (!SDDS_LZMABufferedWrite(SDDS_dataset->data[i], size * rows, lzmafp, fBuffer)) {
1734 SDDS_SetError("Unable to write columns--failure writing values (SDDS_WriteBinaryColumns)");
1735 return (0);
1736 }
1737 } else {
1738 for (row = 0; row < SDDS_dataset->n_rows; row++) {
1739 if (SDDS_dataset->row_flag[row] && !SDDS_LZMABufferedWrite((char *)SDDS_dataset->data[i] + row * size, size, lzmafp, fBuffer)) {
1740 SDDS_SetError("Unable to write columns--failure writing values (SDDS_WriteBinaryColumns)");
1741 return (0);
1742 }
1743 }
1744 }
1745 }
1746 }
1747 } else {
1748 fp = layout->fp;
1749 for (i = 0; i < layout->n_columns; i++) {
1750 type = layout->column_definition[i].type;
1751 size = SDDS_type_size[type - 1];
1752 if (layout->column_definition[i].type == SDDS_STRING) {
1753 for (row = 0; row < SDDS_dataset->n_rows; row++) {
1754 if (SDDS_dataset->row_flag[row] && !SDDS_WriteBinaryString(*((char **)SDDS_dataset->data[i] + row), fp, fBuffer)) {
1755 SDDS_SetError("Unable to write arrays--failure writing string (SDDS_WriteBinaryColumns)");
1756 return (0);
1757 }
1758 }
1759 } else {
1760 if (rows == SDDS_dataset->n_rows) {
1761 if (!SDDS_BufferedWrite(SDDS_dataset->data[i], size * rows, fp, fBuffer)) {
1762 SDDS_SetError("Unable to write columns--failure writing values (SDDS_WriteBinaryColumns)");
1763 return (0);
1764 }
1765 } else {
1766 for (row = 0; row < SDDS_dataset->n_rows; row++) {
1767 if (SDDS_dataset->row_flag[row] && !SDDS_BufferedWrite((char *)SDDS_dataset->data[i] + row * size, size, fp, fBuffer)) {
1768 SDDS_SetError("Unable to write columns--failure writing values (SDDS_WriteBinaryColumns)");
1769 return (0);
1770 }
1771 }
1772 }
1773 }
1774 }
1775 }
1776#if defined(zLib)
1777 }
1778#endif
1779 return (1);
1780}
1781
1782/**
1783 * @brief Writes non-native endian binary columns of an SDDS dataset to the associated file.
1784 *
1785 * This function iterates over each column defined in the SDDS dataset layout and writes its data
1786 * to the binary file using a non-native byte order. It handles different data types, including
1787 * strings and numeric types, and supports various compression formats such as gzip and LZMA if
1788 * enabled.
1789 *
1790 * Depending on the dataset's configuration, the function writes directly to a standard binary
1791 * file, a gzip-compressed file, or an LZMA-compressed file. It also handles sparse data by
1792 * only writing rows flagged for inclusion.
1793 *
1794 * @param SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset to write.
1795 *
1796 * @return
1797 * - Returns `1` on successful writing of all columns.
1798 * - Returns `0` if an error occurs during the writing process.
1799 *
1800 * @details
1801 * The function performs the following steps:
1802 * - Validates the dataset structure using `SDDS_CheckDataset`.
1803 * - Determines the file format (standard, gzip, LZMA) and initializes the corresponding file pointer.
1804 * - Iterates through each column in the dataset:
1805 * - For string columns, writes each string entry individually using the appropriate non-native write function.
1806 * - For numeric columns, writes the entire column data in a buffered manner if all rows are flagged;
1807 * otherwise, writes individual row entries.
1808 * - Handles errors by setting appropriate error messages and aborting the write operation.
1809 *
1810 * @note
1811 * - The function assumes that the dataset has been properly initialized and populated with data.
1812 * - Compression support (`zLib` for gzip, LZMA libraries) must be enabled during compilation
1813 * for handling compressed files.
1814 * - The function is not thread-safe and should be called in a synchronized context.
1815 */
1817 int64_t i, row, rows, size, type;
1818 SDDS_LAYOUT *layout;
1819#if defined(zLib)
1820 gzFile gzfp;
1821#endif
1822 FILE *fp;
1823 struct lzmafile *lzmafp;
1824 SDDS_FILEBUFFER *fBuffer;
1825
1826 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WriteNonNativeBinaryColumns"))
1827 return (0);
1828 layout = &SDDS_dataset->layout;
1829 rows = SDDS_CountRowsOfInterest(SDDS_dataset);
1830 fBuffer = &SDDS_dataset->fBuffer;
1831#if defined(zLib)
1832 if (SDDS_dataset->layout.gzipFile) {
1833 gzfp = layout->gzfp;
1834 for (i = 0; i < layout->n_columns; i++) {
1835 type = layout->column_definition[i].type;
1836 size = SDDS_type_size[type - 1];
1837 if (type == SDDS_STRING) {
1838 for (row = 0; row < SDDS_dataset->n_rows; row++) {
1839 if (SDDS_dataset->row_flag[row] && !SDDS_GZipWriteNonNativeBinaryString(*((char **)SDDS_dataset->data[i] + row), gzfp, fBuffer)) {
1840 SDDS_SetError("Unable to write arrays--failure writing string (SDDS_WriteNonNativeBinaryColumns)");
1841 return (0);
1842 }
1843 }
1844 } else {
1845 if (rows == SDDS_dataset->n_rows) {
1846 if (!SDDS_GZipBufferedWrite((char *)SDDS_dataset->data[i], size * rows, gzfp, fBuffer)) {
1847 SDDS_SetError("Unable to write columns--failure writing values (SDDS_WriteNonNativeBinaryColumns)");
1848 return (0);
1849 }
1850 } else {
1851 for (row = 0; row < SDDS_dataset->n_rows; row++) {
1852 if (SDDS_dataset->row_flag[row] && !SDDS_GZipBufferedWrite((char *)SDDS_dataset->data[i] + row * size, size, gzfp, fBuffer)) {
1853 SDDS_SetError("Unable to write columns--failure writing values (SDDS_WriteNonNativeBinaryColumns)");
1854 return (0);
1855 }
1856 }
1857 }
1858 }
1859 }
1860 } else {
1861#endif
1862 if (SDDS_dataset->layout.lzmaFile) {
1863 lzmafp = layout->lzmafp;
1864 for (i = 0; i < layout->n_columns; i++) {
1865 type = layout->column_definition[i].type;
1866 size = SDDS_type_size[type - 1];
1867 if (type == SDDS_STRING) {
1868 for (row = 0; row < SDDS_dataset->n_rows; row++) {
1869 if (SDDS_dataset->row_flag[row] && !SDDS_LZMAWriteNonNativeBinaryString(*((char **)SDDS_dataset->data[i] + row), lzmafp, fBuffer)) {
1870 SDDS_SetError("Unable to write arrays--failure writing string (SDDS_WriteNonNativeBinaryColumns)");
1871 return (0);
1872 }
1873 }
1874 } else {
1875 if (rows == SDDS_dataset->n_rows) {
1876 if (!SDDS_LZMABufferedWrite(SDDS_dataset->data[i], size * rows, lzmafp, fBuffer)) {
1877 SDDS_SetError("Unable to write columns--failure writing values (SDDS_WriteNonNativeBinaryColumns)");
1878 return (0);
1879 }
1880 } else {
1881 for (row = 0; row < SDDS_dataset->n_rows; row++) {
1882 if (SDDS_dataset->row_flag[row] && !SDDS_LZMABufferedWrite((char *)SDDS_dataset->data[i] + row * size, size, lzmafp, fBuffer)) {
1883 SDDS_SetError("Unable to write columns--failure writing values (SDDS_WriteNonNativeBinaryColumns)");
1884 return (0);
1885 }
1886 }
1887 }
1888 }
1889 }
1890 } else {
1891 fp = layout->fp;
1892 for (i = 0; i < layout->n_columns; i++) {
1893 type = layout->column_definition[i].type;
1894 size = SDDS_type_size[type - 1];
1895 if (type == SDDS_STRING) {
1896 for (row = 0; row < SDDS_dataset->n_rows; row++) {
1897 if (SDDS_dataset->row_flag[row] && !SDDS_WriteNonNativeBinaryString(*((char **)SDDS_dataset->data[i] + row), fp, fBuffer)) {
1898 SDDS_SetError("Unable to write arrays--failure writing string (SDDS_WriteNonNativeBinaryColumns)");
1899 return (0);
1900 }
1901 }
1902 } else {
1903 if (rows == SDDS_dataset->n_rows) {
1904 if (!SDDS_BufferedWrite(SDDS_dataset->data[i], size * rows, fp, fBuffer)) {
1905 SDDS_SetError("Unable to write columns--failure writing values (SDDS_WriteNonNativeBinaryColumns)");
1906 return (0);
1907 }
1908 } else {
1909 for (row = 0; row < SDDS_dataset->n_rows; row++) {
1910 if (SDDS_dataset->row_flag[row] && !SDDS_BufferedWrite((char *)SDDS_dataset->data[i] + row * size, size, fp, fBuffer)) {
1911 SDDS_SetError("Unable to write columns--failure writing values (SDDS_WriteNonNativeBinaryColumns)");
1912 return (0);
1913 }
1914 }
1915 }
1916 }
1917 }
1918 }
1919#if defined(zLib)
1920 }
1921#endif
1922 return (1);
1923}
1924
1925/**
1926 * @brief Writes a single binary row of an SDDS dataset to the associated file.
1927 *
1928 * This function writes the data of a specified row within the SDDS dataset to the binary file.
1929 * It handles different data types, including strings and numeric types, and supports various
1930 * compression formats such as gzip and LZMA if enabled.
1931 *
1932 * Depending on the dataset's configuration, the function writes directly to a standard binary
1933 * file, a gzip-compressed file, or an LZMA-compressed file.
1934 *
1935 * @param SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
1936 * @param row The zero-based index of the row to write.
1937 *
1938 * @return
1939 * - Returns `1` on successful writing of the row.
1940 * - Returns `0` if an error occurs during the writing process.
1941 *
1942 * @details
1943 * The function performs the following steps:
1944 * - Validates the dataset structure using `SDDS_CheckDataset`.
1945 * - Determines the file format (standard, gzip, LZMA) and initializes the corresponding file pointer.
1946 * - Iterates through each column in the dataset:
1947 * - For string columns, writes the string entry of the specified row using the appropriate write function.
1948 * - For numeric columns, writes the data of the specified row using buffered write functions.
1949 * - Handles errors by setting appropriate error messages and aborting the write operation.
1950 *
1951 * @note
1952 * - The function assumes that the dataset has been properly initialized and that the specified row exists.
1953 * - Compression support (`zLib` for gzip, LZMA libraries) must be enabled during compilation
1954 * for handling compressed files.
1955 * - The function is not thread-safe and should be called in a synchronized context.
1956 */
1957int32_t SDDS_WriteBinaryRow(SDDS_DATASET *SDDS_dataset, int64_t row) {
1958 int64_t i, type, size;
1959 SDDS_LAYOUT *layout;
1960#if defined(zLib)
1961 gzFile gzfp;
1962#endif
1963 FILE *fp;
1964 struct lzmafile *lzmafp;
1965 SDDS_FILEBUFFER *fBuffer;
1966
1967 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WriteBinaryRow"))
1968 return (0);
1969 layout = &SDDS_dataset->layout;
1970#if defined(zLib)
1971 if (SDDS_dataset->layout.gzipFile) {
1972 gzfp = layout->gzfp;
1973 fBuffer = &SDDS_dataset->fBuffer;
1974 for (i = 0; i < layout->n_columns; i++) {
1975 if ((type = layout->column_definition[i].type) == SDDS_STRING) {
1976 if (!SDDS_GZipWriteBinaryString(*((char **)SDDS_dataset->data[i] + row), gzfp, fBuffer)) {
1977 SDDS_SetError("Unable to write rows--failure writing string (SDDS_WriteBinaryRows)");
1978 return (0);
1979 }
1980 } else {
1981 size = SDDS_type_size[type - 1];
1982 if (!SDDS_GZipBufferedWrite((char *)SDDS_dataset->data[i] + row * size, size, gzfp, fBuffer)) {
1983 SDDS_SetError("Unable to write row--failure writing value (SDDS_WriteBinaryRow)");
1984 return (0);
1985 }
1986 }
1987 }
1988 } else {
1989#endif
1990 if (SDDS_dataset->layout.lzmaFile) {
1991 lzmafp = layout->lzmafp;
1992 fBuffer = &SDDS_dataset->fBuffer;
1993 for (i = 0; i < layout->n_columns; i++) {
1994 if ((type = layout->column_definition[i].type) == SDDS_STRING) {
1995 if (!SDDS_LZMAWriteBinaryString(*((char **)SDDS_dataset->data[i] + row), lzmafp, fBuffer)) {
1996 SDDS_SetError("Unable to write rows--failure writing string (SDDS_WriteBinaryRows)");
1997 return (0);
1998 }
1999 } else {
2000 size = SDDS_type_size[type - 1];
2001 if (!SDDS_LZMABufferedWrite((char *)SDDS_dataset->data[i] + row * size, size, lzmafp, fBuffer)) {
2002 SDDS_SetError("Unable to write row--failure writing value (SDDS_WriteBinaryRow)");
2003 return (0);
2004 }
2005 }
2006 }
2007 } else {
2008 fp = layout->fp;
2009 fBuffer = &SDDS_dataset->fBuffer;
2010 for (i = 0; i < layout->n_columns; i++) {
2011 if ((type = layout->column_definition[i].type) == SDDS_STRING) {
2012 if (!SDDS_WriteBinaryString(*((char **)SDDS_dataset->data[i] + row), fp, fBuffer)) {
2013 SDDS_SetError("Unable to write rows--failure writing string (SDDS_WriteBinaryRows)");
2014 return (0);
2015 }
2016 } else {
2017 size = SDDS_type_size[type - 1];
2018 if (!SDDS_BufferedWrite((char *)SDDS_dataset->data[i] + row * size, size, fp, fBuffer)) {
2019 SDDS_SetError("Unable to write row--failure writing value (SDDS_WriteBinaryRow)");
2020 return (0);
2021 }
2022 }
2023 }
2024 }
2025#if defined(zLib)
2026 }
2027#endif
2028 return (1);
2029}
2030
2031/**
2032 * @brief Checks if any data in an SDDS page was recovered after an error was detected.
2033 *
2034 * This function inspects the SDDS dataset to determine if any data recovery was possible
2035 * following an error during data reading. It resets the recovery flag after checking.
2036 *
2037 * @param SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
2038 *
2039 * @return
2040 * - Returns `1` if recovery was possible.
2041 * - Returns `0` if no recovery was performed or if recovery was not possible.
2042 *
2043 * @details
2044 * The function performs the following steps:
2045 * - Retrieves the current state of the `readRecoveryPossible` flag from the dataset.
2046 * - Resets the `readRecoveryPossible` flag to `0`.
2047 * - Returns the original state of the `readRecoveryPossible` flag.
2048 *
2049 * @note
2050 * - This function is typically used after attempting to recover from a read error to verify
2051 * if any partial data was successfully recovered.
2052 * - The recovery flag is automatically managed by other functions within the SDDS library.
2053 */
2055 int32_t returnValue;
2056
2057 returnValue = SDDS_dataset->readRecoveryPossible;
2058 SDDS_dataset->readRecoveryPossible = 0;
2059 return returnValue;
2060}
2061
2062/**
2063 * @brief Sets the read recovery mode for an SDDS dataset.
2064 *
2065 * This function configures whether read recovery is possible for the specified SDDS dataset.
2066 * Enabling recovery allows the dataset to attempt to recover partial data in case of read errors.
2067 *
2068 * @param SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
2069 * @param mode Integer flag indicating the recovery mode:
2070 * - `0` to disable read recovery.
2071 * - `1` to enable read recovery.
2072 *
2073 * @details
2074 * The function updates the `readRecoveryPossible` flag within the dataset structure based on the
2075 * provided `mode` parameter. This flag is later checked by other functions to determine whether
2076 * to attempt data recovery after encountering read errors.
2077 *
2078 * @note
2079 * - Enabling read recovery does not guarantee that all data can be recovered after an error.
2080 * - It is recommended to enable recovery only if partial data recovery is acceptable in your application.
2081 */
2082void SDDS_SetReadRecoveryMode(SDDS_DATASET *SDDS_dataset, int32_t mode) {
2083 SDDS_dataset->readRecoveryPossible = mode;
2084}
2085
2086/**
2087 * @brief Reads a binary page from an SDDS dataset.
2088 *
2089 * This function reads a binary page from the specified SDDS dataset. It allows for sparse reading
2090 * by specifying the `sparse_interval` and `sparse_offset` parameters, enabling the reading of
2091 * data at specified intervals or starting from a specific offset.
2092 *
2093 * @param SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset to read from.
2094 * @param sparse_interval Interval at which to read rows. A value greater than `1` enables sparse reading.
2095 * @param sparse_offset Number of initial rows to skip before starting to read data.
2096 * @param sparse_statistics Flag indicating whether to compute statistics during sparse reading:
2097 * - `0`: No statistics.
2098 * - `1`: Compute average.
2099 * - `2`: Compute median.
2100 * - `3`: Compute minimum.
2101 * - `4`: Compute maximum.
2102 *
2103 * @return
2104 * - Returns the page number on successful read.
2105 * - Returns `-1` if the end-of-file is reached.
2106 * - Returns `0` on error.
2107 *
2108 * @details
2109 * The function internally calls `SDDS_ReadBinaryPageDetailed` with the provided parameters to perform
2110 * the actual reading. It handles various scenarios, including non-native byte orders and different
2111 * data layouts (row-major or column-major).
2112 *
2113 * @note
2114 * - This function is typically called to read data pages in bulk, allowing for efficient data access
2115 * by skipping unnecessary rows.
2116 * - Sparse statistics can be used to reduce the amount of data by computing aggregated values.
2117 * - The function assumes that the dataset has been properly initialized and that the file pointers
2118 * are correctly set up.
2119 */
2120int32_t SDDS_ReadBinaryPage(SDDS_DATASET *SDDS_dataset, int64_t sparse_interval, int64_t sparse_offset, int32_t sparse_statistics) {
2121 return SDDS_ReadBinaryPageDetailed(SDDS_dataset, sparse_interval, sparse_offset, 0, sparse_statistics);
2122}
2123
2124/**
2125 * @brief Reads the last specified number of rows from a binary page of an SDDS dataset.
2126 *
2127 * This function reads the last `last_rows` rows from the binary page of the specified SDDS dataset.
2128 * It is useful for retrieving recent data entries without processing the entire dataset.
2129 *
2130 * @param SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset to read from.
2131 * @param last_rows The number of rows to read from the end of the dataset.
2132 *
2133 * @return
2134 * - Returns the page number on successful read.
2135 * - Returns `-1` if the end-of-file is reached.
2136 * - Returns `0` on error.
2137 *
2138 * @details
2139 * The function internally calls `SDDS_ReadBinaryPageDetailed` with `sparse_interval` set to `1`,
2140 * `sparse_offset` set to `0`, and `last_rows` as specified. This configuration ensures that only
2141 * the last `last_rows` rows are read from the dataset.
2142 *
2143 * @note
2144 * - This function is particularly useful for applications that need to display or process the most
2145 * recent data entries.
2146 * - Ensure that `last_rows` does not exceed the total number of rows in the dataset to avoid errors.
2147 * - The function assumes that the dataset has been properly initialized and that the file pointers
2148 * are correctly set up.
2149 */
2150int32_t SDDS_ReadBinaryPageLastRows(SDDS_DATASET *SDDS_dataset, int64_t last_rows) {
2151 return SDDS_ReadBinaryPageDetailed(SDDS_dataset, 1, 0, last_rows, 0);
2152}
2153
2154/**
2155 * @brief Reads a binary page from an SDDS dataset with detailed options.
2156 *
2157 * This function reads a binary page from the specified SDDS dataset, providing detailed control
2158 * over the reading process. It supports sparse reading, reading a specific number of rows from
2159 * the end, and computing statistics on the data.
2160 *
2161 * Typically, this function is not called directly. Instead, it is invoked through higher-level
2162 * functions such as `SDDS_ReadBinaryPage` or `SDDS_ReadBinaryPageLastRows`, which provide
2163 * simplified interfaces for common reading scenarios.
2164 *
2165 * @param SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset to read from.
2166 * @param sparse_interval Interval at which to read rows. A value greater than `1` enables sparse reading.
2167 * @param sparse_offset Number of initial rows to skip before starting to read data.
2168 * @param last_rows The number of rows to read from the end of the dataset. If `0`, all rows are read.
2169 * @param sparse_statistics Flag indicating whether to compute statistics during sparse reading:
2170 * - `0`: No statistics.
2171 * - `1`: Compute average.
2172 * - `2`: Compute median.
2173 * - `3`: Compute minimum.
2174 * - `4`: Compute maximum.
2175 *
2176 * @return
2177 * - Returns the page number on successful read.
2178 * - Returns `-1` if the end-of-file is reached.
2179 * - Returns `0` on error.
2180 *
2181 * @details
2182 * The function performs the following steps:
2183 * - Checks if the dataset has been auto-recovered; if so, it returns `-1`.
2184 * - Determines if the dataset uses native or non-native byte order and delegates to `SDDS_ReadNonNativePageDetailed` if necessary.
2185 * - Initializes file pointers based on the compression format (standard, gzip, LZMA).
2186 * - Allocates and initializes the buffer for reading if not already allocated.
2187 * - Reads the number of rows from the binary file, handling both 32-bit and 64-bit row counts.
2188 * - Validates the row count and ensures it does not exceed predefined limits.
2189 * - Adjusts for column-major layouts by calling `SDDS_ReadBinaryColumns` if necessary.
2190 * - Handles sparse reading by skipping rows based on `sparse_interval` and `sparse_offset`.
2191 * - If `sparse_statistics` is enabled, computes the specified statistics (average, median, min, max) on floating-point data.
2192 * - Handles errors by setting appropriate error messages and managing recovery modes.
2193 *
2194 * @note
2195 * - This function provides extensive control over the reading process, allowing for optimized data access.
2196 * - Ensure that all parameters are set correctly to avoid unintended data skips or miscomputations.
2197 * - The function assumes that the dataset has been properly initialized and that the file pointers
2198 * are correctly set up.
2199 * - Compression support (`zLib` for gzip, LZMA libraries) must be enabled during compilation
2200 * for handling compressed files.
2201 */
2202int32_t SDDS_ReadBinaryPageDetailed(SDDS_DATASET *SDDS_dataset, int64_t sparse_interval, int64_t sparse_offset, int64_t last_rows, int32_t sparse_statistics) {
2203 int32_t n_rows32;
2204 int64_t n_rows, i, j, k, alloc_rows, rows_to_store, mod;
2205
2206 /* int32_t page_number, i; */
2207#if defined(zLib)
2208 gzFile gzfp = NULL;
2209#endif
2210 FILE *fp = NULL;
2211 struct lzmafile *lzmafp = NULL;
2212 SDDS_FILEBUFFER *fBuffer;
2213 void **statData=NULL;
2214 double statResult;
2215
2216 if (SDDS_dataset->autoRecovered)
2217 return -1;
2218 if (SDDS_dataset->swapByteOrder) {
2219 return SDDS_ReadNonNativePageDetailed(SDDS_dataset, 0, sparse_interval, sparse_offset, last_rows);
2220 }
2221
2222 /* static char s[SDDS_MAXLINE]; */
2223 n_rows = 0;
2224 SDDS_SetReadRecoveryMode(SDDS_dataset, 0);
2225#if defined(zLib)
2226 if (SDDS_dataset->layout.gzipFile) {
2227 gzfp = SDDS_dataset->layout.gzfp;
2228 } else {
2229#endif
2230 if (SDDS_dataset->layout.lzmaFile) {
2231 lzmafp = SDDS_dataset->layout.lzmafp;
2232 } else {
2233 fp = SDDS_dataset->layout.fp;
2234 }
2235#if defined(zLib)
2236 }
2237#endif
2238 fBuffer = &SDDS_dataset->fBuffer;
2239 if (!fBuffer->buffer) {
2240 if (defaultIOBufferSize == 0 && (SDDS_dataset->layout.popenUsed || !SDDS_dataset->layout.filename) && (sparse_interval > 1 || sparse_offset > 0 || last_rows > 0)) {
2241 SDDS_SetError("The IO buffer size is 0 for data being read from a pipe with sparsing. This is not supported.");
2242 return 0;
2243 }
2244 if (!(fBuffer->buffer = fBuffer->data = SDDS_Malloc(sizeof(char) * (defaultIOBufferSize + 1)))) {
2245 SDDS_SetError("Unable to do buffered read--allocation failure");
2246 return 0;
2247 }
2248 fBuffer->bufferSize = defaultIOBufferSize;
2249 fBuffer->bytesLeft = 0;
2250 }
2251 SDDS_dataset->rowcount_offset = -1;
2252#if defined(zLib)
2253 if (SDDS_dataset->layout.gzipFile) {
2254 if (!SDDS_GZipBufferedRead(&n_rows32, sizeof(n_rows32), gzfp, &SDDS_dataset->fBuffer, SDDS_LONG, SDDS_dataset->layout.byteOrderDeclared)) {
2255 if (gzeof(gzfp))
2256 return (SDDS_dataset->page_number = -1);
2257 SDDS_SetError("Unable to read page--failure reading number of rows (SDDS_ReadBinaryPageDetailed)");
2258 return (0);
2259 }
2260 if (n_rows32 == INT32_MIN) {
2261 if (!SDDS_GZipBufferedRead(&n_rows, sizeof(n_rows), gzfp, &SDDS_dataset->fBuffer, SDDS_LONG64, SDDS_dataset->layout.byteOrderDeclared)) {
2262 if (gzeof(gzfp))
2263 return (SDDS_dataset->page_number = -1);
2264 SDDS_SetError("Unable to read page--failure reading number of rows (SDDS_ReadBinaryPageDetailed)");
2265 return (0);
2266 }
2267 } else {
2268 n_rows = n_rows32;
2269 }
2270 } else {
2271#endif
2272 /* This value will only be valid if read buffering is turned off, which is done for
2273 * certain append operations! Should really modify SDDS_BufferedRead and SDDS_BufferedWrite
2274 * to provide ftell capability.
2275 */
2276 if (SDDS_dataset->layout.lzmaFile) {
2277 if (!SDDS_LZMABufferedRead(&n_rows32, sizeof(n_rows32), lzmafp, &SDDS_dataset->fBuffer, SDDS_LONG, SDDS_dataset->layout.byteOrderDeclared)) {
2278 if (lzma_eof(lzmafp))
2279 return (SDDS_dataset->page_number = -1);
2280 SDDS_SetError("Unable to read page--failure reading number of rows (SDDS_ReadBinaryPageDetailed)");
2281 return (0);
2282 }
2283 if (n_rows32 == INT32_MIN) {
2284 if (!SDDS_LZMABufferedRead(&n_rows, sizeof(n_rows), lzmafp, &SDDS_dataset->fBuffer, SDDS_LONG64, SDDS_dataset->layout.byteOrderDeclared)) {
2285 if (lzma_eof(lzmafp))
2286 return (SDDS_dataset->page_number = -1);
2287 SDDS_SetError("Unable to read page--failure reading number of rows (SDDS_ReadBinaryPageDetailed)");
2288 return (0);
2289 }
2290 } else {
2291 n_rows = n_rows32;
2292 }
2293 } else {
2294 SDDS_dataset->rowcount_offset = ftell(fp);
2295 if (!SDDS_BufferedRead(&n_rows32, sizeof(n_rows32), fp, &SDDS_dataset->fBuffer, SDDS_LONG, SDDS_dataset->layout.byteOrderDeclared)) {
2296 if (feof(fp))
2297 return (SDDS_dataset->page_number = -1);
2298 SDDS_SetError("Unable to read page--failure reading number of rows (SDDS_ReadBinaryPageDetailed)");
2299 return (0);
2300 }
2301 if (n_rows32 == INT32_MIN) {
2302 if (!SDDS_BufferedRead(&n_rows, sizeof(n_rows), fp, &SDDS_dataset->fBuffer, SDDS_LONG64, SDDS_dataset->layout.byteOrderDeclared)) {
2303 if (feof(fp))
2304 return (SDDS_dataset->page_number = -1);
2305 SDDS_SetError("Unable to read page--failure reading number of rows (SDDS_ReadBinaryPageDetailed)");
2306 return (0);
2307 }
2308 } else {
2309 n_rows = n_rows32;
2310 }
2311 }
2312#if defined(zLib)
2313 }
2314#endif
2315
2316#if defined(DEBUG)
2317 fprintf(stderr, "Expect %" PRId64 " rows of data\n", n_rows);
2318#endif
2319 if (n_rows < 0) {
2320 SDDS_SetError("Unable to read page--negative number of rows (SDDS_ReadBinaryPageDetailed)");
2321 return (0);
2322 }
2323 if (SDDS_dataset->layout.byteOrderDeclared == 0) {
2324 if (n_rows > 10000000) {
2325 SDDS_SetError("Unable to read page--endian byte order not declared and suspected to be non-native. (SDDS_ReadBinaryPageDetailed)");
2326 return (0);
2327 }
2328 }
2329 if (n_rows > SDDS_GetRowLimit()) {
2330 /* the number of rows is "unreasonably" large---treat like end-of-file */
2331 return (SDDS_dataset->page_number = -1);
2332 }
2333 if (last_rows < 0)
2334 last_rows = 0;
2335 /* Fix this limitation later */
2336 if (SDDS_dataset->layout.data_mode.column_major) {
2337 if ((sparse_interval != 1) || (sparse_offset != 0) || (last_rows != 0)) {
2338 SDDS_SetError("Sparsing column data not yet supported for column-major layout. Use sddsconvert -majorOrder=row to convert first.\n");
2339 return (0);
2340 }
2341 sparse_interval = 1;
2342 sparse_offset = 0;
2343 last_rows = 0;
2344 }
2345 if (last_rows) {
2346 sparse_interval = 1;
2347 sparse_offset = n_rows - last_rows;
2348 }
2349 if (sparse_interval <= 0)
2350 sparse_interval = 1;
2351 if (sparse_offset < 0)
2352 sparse_offset = 0;
2353
2354 rows_to_store = (n_rows - sparse_offset) / sparse_interval + 2;
2355 alloc_rows = rows_to_store - SDDS_dataset->n_rows_allocated;
2356
2357 if (!SDDS_StartPage(SDDS_dataset, 0) || !SDDS_LengthenTable(SDDS_dataset, alloc_rows)) {
2358 SDDS_SetError("Unable to read page--couldn't start page (SDDS_ReadBinaryPageDetailed)");
2359 return (0);
2360 }
2361
2362 /* read the parameter values */
2363 if (!SDDS_ReadBinaryParameters(SDDS_dataset)) {
2364 SDDS_SetError("Unable to read page--parameter reading error (SDDS_ReadBinaryPageDetailed)");
2365 return (0);
2366 }
2367
2368 /* read the array values */
2369 if (!SDDS_ReadBinaryArrays(SDDS_dataset)) {
2370 SDDS_SetError("Unable to read page--array reading error (SDDS_ReadBinaryPageDetailed)");
2371 return (0);
2372 }
2373 if (SDDS_dataset->layout.data_mode.column_major) {
2374 SDDS_dataset->n_rows = n_rows;
2375 if (!SDDS_ReadBinaryColumns(SDDS_dataset)) {
2376 SDDS_SetError("Unable to read page--column reading error (SDDS_ReadBinaryPageDetailed)");
2377 return (0);
2378 }
2379 return (SDDS_dataset->page_number);
2380 }
2381 if ((sparse_interval <= 1) && (sparse_offset == 0)) {
2382 for (j = 0; j < n_rows; j++) {
2383 if (!SDDS_ReadBinaryRow(SDDS_dataset, j, 0)) {
2384 SDDS_dataset->n_rows = j;
2385 if (SDDS_dataset->autoRecover) {
2386#if defined(DEBUG)
2387 fprintf(stderr, "Doing auto-read recovery\n");
2388#endif
2389 SDDS_dataset->autoRecovered = 1;
2391 return (SDDS_dataset->page_number);
2392 }
2393 SDDS_SetError("Unable to read page--error reading data row (SDDS_ReadBinaryPageDetailed)");
2394 SDDS_SetReadRecoveryMode(SDDS_dataset, 1);
2395 return (0);
2396 }
2397 }
2398 SDDS_dataset->n_rows = j;
2399 return (SDDS_dataset->page_number);
2400 } else {
2401 for (j = 0; j < sparse_offset; j++) {
2402 if (!SDDS_ReadBinaryRow(SDDS_dataset, 0, 1)) {
2403 SDDS_dataset->n_rows = 0;
2404 if (SDDS_dataset->autoRecover) {
2405 SDDS_dataset->autoRecovered = 1;
2407 return (SDDS_dataset->page_number);
2408 }
2409 SDDS_SetError("Unable to read page--error reading data row (SDDS_ReadBinaryPageDetailed)");
2410 SDDS_SetReadRecoveryMode(SDDS_dataset, 1);
2411 return (0);
2412 }
2413 }
2414 n_rows -= sparse_offset;
2415 if (sparse_statistics != 0) {
2416 // Allocate buffer space for statistical sparsing
2417 statData = (void**)malloc(SDDS_dataset->layout.n_columns * sizeof(void*));
2418 for (i = 0; i < SDDS_dataset->layout.n_columns; i++) {
2419 if (SDDS_FLOATING_TYPE(SDDS_dataset->layout.column_definition[i].type)) {
2420 // Not ideal for SDDS_LONGDOUBLE but we may never run across this error
2421 statData[i] = (double*)calloc(sparse_interval, sizeof(double));
2422 }
2423 }
2424 for (j = k = 0; j < n_rows; j++) {
2425 if (!SDDS_ReadBinaryRow(SDDS_dataset, k, 0)) {
2426 SDDS_dataset->n_rows = k;
2427 if (SDDS_dataset->autoRecover) {
2428 SDDS_dataset->autoRecovered = 1;
2430 return (SDDS_dataset->page_number);
2431 }
2432 SDDS_SetError("Unable to read page--error reading data row (SDDS_ReadBinaryPageDetailed)");
2433 SDDS_SetReadRecoveryMode(SDDS_dataset, 1);
2434 return (0);
2435 }
2436 for (i = 0; i < SDDS_dataset->layout.n_columns; i++) {
2437 switch (SDDS_dataset->layout.column_definition[i].type) {
2438 case SDDS_FLOAT:
2439 ((double*)statData[i])[j % sparse_interval] = (double)(((float*)SDDS_dataset->data[i])[k]);
2440 break;
2441 case SDDS_DOUBLE:
2442 ((double*)statData[i])[j % sparse_interval] = ((double*)SDDS_dataset->data[i])[k];
2443 break;
2444 case SDDS_LONGDOUBLE:
2445 ((double*)statData[i])[j % sparse_interval] = (double)(((long double*)SDDS_dataset->data[i])[k]);
2446 break;
2447 }
2448 if (SDDS_FLOATING_TYPE(SDDS_dataset->layout.column_definition[i].type)) {
2449 if (sparse_statistics == 1) {
2450 // Sparse and get average statistics
2451 compute_average(&statResult, (double*)statData[i], (j % sparse_interval) + 1);
2452 } else if (sparse_statistics == 2) {
2453 // Sparse and get median statistics
2454 compute_median(&statResult, (double*)statData[i], (j % sparse_interval) + 1);
2455 } else if (sparse_statistics == 3) {
2456 // Sparse and get minimum statistics
2457 statResult = min_in_array((double*)statData[i], (j % sparse_interval) + 1);
2458 } else if (sparse_statistics == 4) {
2459 // Sparse and get maximum statistics
2460 statResult = max_in_array((double*)statData[i], (j % sparse_interval) + 1);
2461 }
2462 }
2463 switch (SDDS_dataset->layout.column_definition[i].type) {
2464 case SDDS_FLOAT:
2465 ((float*)SDDS_dataset->data[i])[k] = statResult;
2466 break;
2467 case SDDS_DOUBLE:
2468 ((double*)SDDS_dataset->data[i])[k] = statResult;
2469 break;
2470 case SDDS_LONGDOUBLE:
2471 ((long double*)SDDS_dataset->data[i])[k] = statResult;
2472 break;
2473 }
2474 }
2475 if (j % sparse_interval == sparse_interval - 1) {
2476 k++;
2477 }
2478 }
2479 for (i = 0; i < SDDS_dataset->layout.n_columns; i++) {
2480 if (SDDS_FLOATING_TYPE(SDDS_dataset->layout.column_definition[i].type)) {
2481 free(statData[i]);
2482 }
2483 }
2484 free(statData);
2485 } else {
2486 for (j = k = 0; j < n_rows; j++) {
2487 if (!SDDS_ReadBinaryRow(SDDS_dataset, k, mod = j % sparse_interval)) {
2488 SDDS_dataset->n_rows = k;
2489 if (SDDS_dataset->autoRecover) {
2490 SDDS_dataset->autoRecovered = 1;
2492 return (SDDS_dataset->page_number);
2493 }
2494 SDDS_SetError("Unable to read page--error reading data row (SDDS_ReadBinaryPageDetailed)");
2495 SDDS_SetReadRecoveryMode(SDDS_dataset, 1);
2496 return (0);
2497 }
2498 k += mod ? 0 : 1;
2499 }
2500 }
2501 SDDS_dataset->n_rows = k;
2502 return (SDDS_dataset->page_number);
2503 }
2504}
2505
2506/**
2507 * @brief Writes a binary string to a file with buffering.
2508 *
2509 * This function writes a binary string to the specified file by first writing the length of the string
2510 * followed by the string's content to ensure proper binary formatting. If the input string is NULL,
2511 * an empty string is written instead. The writing operation utilizes a buffered approach to enhance performance.
2512 *
2513 * @param[in] string The null-terminated string to be written. If NULL, an empty string is written.
2514 * @param[in] fp The file pointer to write to. Must be an open file in binary write mode.
2515 * @param[in,out] fBuffer Pointer to the file buffer used for buffered writing operations.
2516 *
2517 * @return int32_t Returns 1 on success, 0 on failure.
2518 * @retval 1 Operation was successful.
2519 * @retval 0 An error occurred during writing.
2520 */
2521int32_t SDDS_WriteBinaryString(char *string, FILE *fp, SDDS_FILEBUFFER *fBuffer) {
2522 int32_t length;
2523 static char *dummy_string = "";
2524 if (!string)
2525 string = dummy_string;
2526 length = strlen(string);
2527 if (!SDDS_BufferedWrite(&length, sizeof(length), fp, fBuffer)) {
2528 SDDS_SetError("Unable to write string--error writing length");
2529 return (0);
2530 }
2531 if (length && !SDDS_BufferedWrite(string, sizeof(*string) * length, fp, fBuffer)) {
2532 SDDS_SetError("Unable to write string--error writing contents");
2533 return (0);
2534 }
2535 return (1);
2536}
2537
2538/**
2539 * @brief Writes a binary string to a file with LZMA compression.
2540 *
2541 * This function writes a binary string to the specified LZMA-compressed file by first writing the length
2542 * of the string followed by the string's content. If the input string is NULL, an empty string is written instead.
2543 * The writing operation utilizes LZMA buffered write functions to ensure data is compressed appropriately.
2544 *
2545 * @param[in] string The null-terminated string to be written. If NULL, an empty string is written.
2546 * @param[in] lzmafp The LZMA file pointer to write to. Must be a valid, open LZMA-compressed file in write mode.
2547 * @param[in,out] fBuffer Pointer to the file buffer used for buffered writing operations.
2548 *
2549 * @return int32_t Returns 1 on success, 0 on failure.
2550 * @retval 1 Operation was successful.
2551 * @retval 0 An error occurred during writing.
2552 */
2553int32_t SDDS_LZMAWriteBinaryString(char *string, struct lzmafile *lzmafp, SDDS_FILEBUFFER *fBuffer) {
2554 int32_t length;
2555 static char *dummy_string = "";
2556 if (!string)
2557 string = dummy_string;
2558 length = strlen(string);
2559 if (!SDDS_LZMABufferedWrite(&length, sizeof(length), lzmafp, fBuffer)) {
2560 SDDS_SetError("Unable to write string--error writing length");
2561 return (0);
2562 }
2563 if (length && !SDDS_LZMABufferedWrite(string, sizeof(*string) * length, lzmafp, fBuffer)) {
2564 SDDS_SetError("Unable to write string--error writing contents");
2565 return (0);
2566 }
2567 return (1);
2568}
2569
2570#if defined(zLib)
2571/**
2572 * @brief Writes a binary string to a GZIP-compressed file with buffering.
2573 *
2574 * This function writes a binary string to the specified GZIP-compressed file by first writing the length
2575 * of the string followed by the string's content. If the input string is NULL, an empty string is written instead.
2576 * The writing operation uses GZIP buffered write functions to compress the data.
2577 *
2578 * @param[in] string The null-terminated string to be written. If NULL, an empty string is written.
2579 * @param[in] gzfp The GZIP file pointer to write to. Must be a valid, open GZIP-compressed file in write mode.
2580 * @param[in,out] fBuffer Pointer to the file buffer used for buffered writing operations.
2581 *
2582 * @return int32_t Returns 1 on success, 0 on failure.
2583 * @retval 1 Operation was successful.
2584 * @retval 0 An error occurred during writing.
2585 */
2586int32_t SDDS_GZipWriteBinaryString(char *string, gzFile gzfp, SDDS_FILEBUFFER *fBuffer) {
2587 int32_t length;
2588 static char *dummy_string = "";
2589 if (!string)
2590 string = dummy_string;
2591 length = strlen(string);
2592 if (!SDDS_GZipBufferedWrite(&length, sizeof(length), gzfp, fBuffer)) {
2593 SDDS_SetError("Unable to write string--error writing length");
2594 return (0);
2595 }
2596 if (length && !SDDS_GZipBufferedWrite(string, sizeof(*string) * length, gzfp, fBuffer)) {
2597 SDDS_SetError("Unable to write string--error writing contents");
2598 return (0);
2599 }
2600 return (1);
2601}
2602#endif
2603
2604/**
2605 * @brief Reads a binary string from a file with buffering.
2606 *
2607 * This function reads a binary string from the specified file by first reading the length of the string
2608 * and then reading the string content based on the length. If the 'skip' parameter is set, the string data
2609 * is skipped over instead of being stored. The function allocates memory for the string, which should be
2610 * freed by the caller when no longer needed.
2611 *
2612 * @param[in] fp The file pointer to read from. Must be an open file in binary read mode.
2613 * @param[in,out] fBuffer Pointer to the file buffer used for buffered reading operations.
2614 * @param[in] skip If non-zero, the string data is skipped without being stored.
2615 *
2616 * @return char* Returns a pointer to the read null-terminated string on success, or NULL if an error occurred.
2617 * @retval NULL An error occurred during reading or memory allocation.
2618 * @retval Non-NULL Pointer to the read string.
2619 */
2620char *SDDS_ReadBinaryString(FILE *fp, SDDS_FILEBUFFER *fBuffer, int32_t skip) {
2621 int32_t length;
2622 char *string;
2623
2624 if (!SDDS_BufferedRead(&length, sizeof(length), fp, fBuffer, SDDS_LONG, 0) || length < 0)
2625 return (0);
2626 if (!(string = SDDS_Malloc(sizeof(*string) * (length + 1))))
2627 return (NULL);
2628 if (length && !SDDS_BufferedRead(skip ? NULL : string, sizeof(*string) * length, fp, fBuffer, SDDS_STRING, 0))
2629 return (NULL);
2630 string[length] = 0;
2631 return (string);
2632}
2633
2634/**
2635 * @brief Reads a binary string from an LZMA-compressed file with buffering.
2636 *
2637 * This function reads a binary string from the specified LZMA-compressed file by first reading the length
2638 * of the string and then reading the string content based on the length. If the 'skip' parameter is set,
2639 * the string data is skipped over instead of being stored. The function allocates memory for the string,
2640 * which should be freed by the caller when no longer needed.
2641 *
2642 * @param[in] lzmafp The LZMA file pointer to read from. Must be an open LZMA-compressed file in read mode.
2643 * @param[in,out] fBuffer Pointer to the file buffer used for buffered reading operations.
2644 * @param[in] skip If non-zero, the string data is skipped without being stored.
2645 *
2646 * @return char* Returns a pointer to the read null-terminated string on success, or NULL if an error occurred.
2647 * @retval NULL An error occurred during reading or memory allocation.
2648 * @retval Non-NULL Pointer to the read string.
2649 */
2650char *SDDS_ReadLZMABinaryString(struct lzmafile *lzmafp, SDDS_FILEBUFFER *fBuffer, int32_t skip) {
2651 int32_t length;
2652 char *string;
2653
2654 if (!SDDS_LZMABufferedRead(&length, sizeof(length), lzmafp, fBuffer, SDDS_LONG, 0) || length < 0)
2655 return (0);
2656 if (!(string = SDDS_Malloc(sizeof(*string) * (length + 1))))
2657 return (NULL);
2658 if (length && !SDDS_LZMABufferedRead(skip ? NULL : string, sizeof(*string) * length, lzmafp, fBuffer, SDDS_STRING, 0))
2659 return (NULL);
2660 string[length] = 0;
2661 return (string);
2662}
2663
2664#if defined(zLib)
2665/**
2666 * @brief Reads a binary string from a GZIP-compressed file with buffering.
2667 *
2668 * This function reads a binary string from the specified GZIP-compressed file by first reading the length
2669 * of the string and then reading the string content based on the length. If the 'skip' parameter is set,
2670 * the string data is skipped over instead of being stored. The function allocates memory for the string,
2671 * which should be freed by the caller when no longer needed.
2672 *
2673 * @param[in] gzfp The GZIP file pointer to read from. Must be an open GZIP-compressed file in read mode.
2674 * @param[in,out] fBuffer Pointer to the file buffer used for buffered reading operations.
2675 * @param[in] skip If non-zero, the string data is skipped without being stored.
2676 *
2677 * @return char* Returns a pointer to the read null-terminated string on success, or NULL if an error occurred.
2678 * @retval NULL An error occurred during reading or memory allocation.
2679 * @retval Non-NULL Pointer to the read string.
2680 */
2681char *SDDS_ReadGZipBinaryString(gzFile gzfp, SDDS_FILEBUFFER *fBuffer, int32_t skip) {
2682 int32_t length;
2683 char *string;
2684
2685 if (!SDDS_GZipBufferedRead(&length, sizeof(length), gzfp, fBuffer, SDDS_LONG, 0) || length < 0)
2686 return (0);
2687 if (!(string = SDDS_Malloc(sizeof(*string) * (length + 1))))
2688 return (NULL);
2689 if (length && !SDDS_GZipBufferedRead(skip ? NULL : string, sizeof(*string) * length, gzfp, fBuffer, SDDS_STRING, 0))
2690 return (NULL);
2691 string[length] = 0;
2692 return (string);
2693}
2694#endif
2695
2696/**
2697 * @brief Reads a binary row from the specified SDDS dataset.
2698 *
2699 * This function reads a single row of data from the given SDDS dataset. Depending on the dataset's configuration,
2700 * it handles uncompressed, LZMA-compressed, or GZIP-compressed files. For each column in the dataset, the function
2701 * reads the appropriate data type. If a column is of type string, it reads the string using the corresponding
2702 * string reading function. If the 'skip' parameter is set, the function skips reading the data without storing it.
2703 *
2704 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
2705 * @param[in] row The row number to read. Must be within the allocated range of rows in the dataset.
2706 * @param[in] skip If non-zero, the function skips reading the data for each column without storing it.
2707 *
2708 * @return int32_t Returns 1 on successful reading of the row, or 0 if an error occurred.
2709 * @retval 1 The row was successfully read and stored (or skipped).
2710 * @retval 0 An error occurred during reading, such as I/O errors or memory allocation failures.
2711 *
2712 * @note This function may modify the dataset's data structures by allocating memory for string columns.
2713 * Ensure that the dataset is properly initialized and that memory is managed appropriately.
2714 */
2715int32_t SDDS_ReadBinaryRow(SDDS_DATASET *SDDS_dataset, int64_t row, int32_t skip) {
2716 int64_t i, type, size;
2717 SDDS_LAYOUT *layout;
2718#if defined(zLib)
2719 gzFile gzfp;
2720#endif
2721 FILE *fp;
2722 struct lzmafile *lzmafp;
2723 SDDS_FILEBUFFER *fBuffer;
2724
2725 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReadBinaryRow"))
2726 return (0);
2727 layout = &SDDS_dataset->layout;
2728 fBuffer = &SDDS_dataset->fBuffer;
2729
2730#if defined(zLib)
2731 if (SDDS_dataset->layout.gzipFile) {
2732 gzfp = layout->gzfp;
2733 for (i = 0; i < layout->n_columns; i++) {
2734 if (layout->column_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
2735 continue;
2736 if ((type = layout->column_definition[i].type) == SDDS_STRING) {
2737 if (!skip) {
2738 if (((char ***)SDDS_dataset->data)[i][row])
2739 free((((char ***)SDDS_dataset->data)[i][row]));
2740 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadGZipBinaryString(gzfp, fBuffer, 0))) {
2741 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadBinaryRows)");
2742 return (0);
2743 }
2744 } else {
2745 if (!SDDS_ReadGZipBinaryString(gzfp, fBuffer, 1)) {
2746 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadBinaryRows)");
2747 return 0;
2748 }
2749 }
2750 } else {
2751 size = SDDS_type_size[type - 1];
2752 if (!SDDS_GZipBufferedRead(skip ? NULL : (char *)SDDS_dataset->data[i] + row * size, size, gzfp, fBuffer, type, SDDS_dataset->layout.byteOrderDeclared)) {
2753 SDDS_SetError("Unable to read row--failure reading value (SDDS_ReadBinaryRow)");
2754 return (0);
2755 }
2756 }
2757 }
2758 } else {
2759#endif
2760 if (SDDS_dataset->layout.lzmaFile) {
2761 lzmafp = layout->lzmafp;
2762 for (i = 0; i < layout->n_columns; i++) {
2763 if (layout->column_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
2764 continue;
2765 if ((type = layout->column_definition[i].type) == SDDS_STRING) {
2766 if (!skip) {
2767 if (((char ***)SDDS_dataset->data)[i][row])
2768 free((((char ***)SDDS_dataset->data)[i][row]));
2769 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadLZMABinaryString(lzmafp, fBuffer, 0))) {
2770 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadBinaryRows)");
2771 return (0);
2772 }
2773 } else {
2774 if (!SDDS_ReadLZMABinaryString(lzmafp, fBuffer, 1)) {
2775 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadBinaryRows)");
2776 return 0;
2777 }
2778 }
2779 } else {
2780 size = SDDS_type_size[type - 1];
2781 if (!SDDS_LZMABufferedRead(skip ? NULL : (char *)SDDS_dataset->data[i] + row * size, size, lzmafp, fBuffer, type, SDDS_dataset->layout.byteOrderDeclared)) {
2782 SDDS_SetError("Unable to read row--failure reading value (SDDS_ReadBinaryRow)");
2783 return (0);
2784 }
2785 }
2786 }
2787 } else {
2788 fp = layout->fp;
2789 for (i = 0; i < layout->n_columns; i++) {
2790 if (layout->column_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
2791 continue;
2792 if ((type = layout->column_definition[i].type) == SDDS_STRING) {
2793 if (!skip) {
2794 if (((char ***)SDDS_dataset->data)[i][row])
2795 free((((char ***)SDDS_dataset->data)[i][row]));
2796 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadBinaryString(fp, fBuffer, 0))) {
2797 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadBinaryRows)");
2798 return (0);
2799 }
2800 } else {
2801 if (!SDDS_ReadBinaryString(fp, fBuffer, 1)) {
2802 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadBinaryRows)");
2803 return 0;
2804 }
2805 }
2806 } else {
2807 size = SDDS_type_size[type - 1];
2808 if (!SDDS_BufferedRead(skip ? NULL : (char *)SDDS_dataset->data[i] + row * size, size, fp, fBuffer, type, SDDS_dataset->layout.byteOrderDeclared)) {
2809 SDDS_SetError("Unable to read row--failure reading value (SDDS_ReadBinaryRow)");
2810 return (0);
2811 }
2812 }
2813 }
2814 }
2815#if defined(zLib)
2816 }
2817#endif
2818 return (1);
2819}
2820
2821/**
2822 * @brief Reads new binary rows from the SDDS dataset.
2823 *
2824 * This function updates the SDDS dataset by reading any new rows that have been added to the underlying file
2825 * since the last read operation. It verifies that the dataset is in a compatible binary format and ensures
2826 * that byte order and compression settings are supported. If the number of rows in the file exceeds the
2827 * currently allocated rows in memory, the function expands the dataset's internal storage to accommodate
2828 * the new rows.
2829 *
2830 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
2831 *
2832 * @return int32_t Returns the number of new rows successfully read on success, or -1 if an error occurred.
2833 * @retval >0 The number of new rows read and added to the dataset.
2834 * @retval -1 An error occurred during the read operation, such as unsupported file format,
2835 * I/O errors, or memory allocation failures.
2836 *
2837 * @note This function does not support MPI parallel I/O, ASCII files, column-major order binary files,
2838 * non-native byte orders, or compressed files (gzip or lzma). Attempts to use these features will
2839 * result in an error.
2840 */
2841int32_t SDDS_ReadNewBinaryRows(SDDS_DATASET *SDDS_dataset) {
2842 int64_t row, offset, newRows = 0;
2843 int32_t rowsPresent32;
2844 int64_t rowsPresent;
2845
2846#if SDDS_MPI_IO
2847 if (SDDS_dataset->parallel_io) {
2848 SDDS_SetError("Error: MPI mode not supported yet in SDDS_ReadNewBinaryRows");
2849 return -1;
2850 }
2851#endif
2852 if (SDDS_dataset->original_layout.data_mode.mode == SDDS_ASCII) {
2853 SDDS_SetError("Error: ASCII files not supported in SDDS_ReadNewBinaryRows");
2854 return -1;
2855 }
2856 if (SDDS_dataset->layout.data_mode.column_major) {
2857 SDDS_SetError("Error: column-major order binary files not supported in SDDS_ReadNewBinaryRows");
2858 return -1;
2859 }
2860 if (SDDS_dataset->swapByteOrder) {
2861 SDDS_SetError("Error: Non-native endian not supported yet in SDDS_ReadNewBinaryRows");
2862 return -1;
2863 }
2864#if defined(zLib)
2865 if (SDDS_dataset->layout.gzipFile) {
2866 SDDS_SetError("Error: gzip compressed files not supported yet in SDDS_ReadNewBinaryRows");
2867 return -1;
2868 } else {
2869#endif
2870 if (SDDS_dataset->layout.lzmaFile) {
2871 SDDS_SetError("Error: lzma compressed files not supported yet in SDDS_ReadNewBinaryRows");
2872 return -1;
2873 }
2874#if defined(zLib)
2875 }
2876#endif
2877
2878 // Read how many rows we have now
2879 offset = ftell(SDDS_dataset->layout.fp);
2880 fseek(SDDS_dataset->layout.fp, SDDS_dataset->rowcount_offset, 0);
2881 if (SDDS_dataset->layout.data_mode.mode == SDDS_BINARY) {
2882 fread(&rowsPresent32, sizeof(rowsPresent32), 1, SDDS_dataset->layout.fp);
2883 if (SDDS_dataset->swapByteOrder) {
2884 SDDS_SwapLong(&rowsPresent32);
2885 }
2886 if (rowsPresent32 == INT32_MIN) {
2887 fread(&rowsPresent, sizeof(rowsPresent), 1, SDDS_dataset->layout.fp);
2888 if (SDDS_dataset->swapByteOrder) {
2889 SDDS_SwapLong64(&rowsPresent);
2890 }
2891 } else {
2892 rowsPresent = rowsPresent32;
2893 }
2894 } else {
2895 char buffer[30];
2896 if (!fgets(buffer, 30, SDDS_dataset->layout.fp) || strlen(buffer) != 21 || sscanf(buffer, "%" SCNd64, &rowsPresent) != 1) {
2897 SDDS_SetError("Error: row count not present or not correct length");
2898 return -1;
2899 }
2900 }
2901 fseek(SDDS_dataset->layout.fp, offset, 0);
2902
2903 // If the row count listed in the file is greather than the allocated rows, then lengthen the table in memory
2904 if (rowsPresent > SDDS_dataset->n_rows_allocated) {
2905 if (!SDDS_LengthenTable(SDDS_dataset, rowsPresent + 3)) {
2906 return -1;
2907 }
2908 }
2909
2910 for (row = SDDS_dataset->n_rows; row < rowsPresent; row++) {
2911 if (!SDDS_ReadBinaryRow(SDDS_dataset, row, 0)) {
2912 if (SDDS_dataset->autoRecover) {
2913 row--;
2914 SDDS_dataset->autoRecovered = 1;
2916 break;
2917 }
2918 SDDS_SetError("Unable to read page--error reading data row");
2919 return -1;
2920 }
2921 }
2922 newRows = row + 1 - SDDS_dataset->n_rows;
2923 SDDS_dataset->n_rows = row + 1;
2924 return newRows;
2925}
2926
2927/**
2928 * @brief Reads binary parameters from the specified SDDS dataset.
2929 *
2930 * This function iterates through all the parameters defined in the SDDS dataset layout and reads their values
2931 * from the underlying file. It handles different data types, including strings, and manages memory allocation
2932 * for string parameters. Depending on the dataset's compression settings (uncompressed, LZMA, or GZIP),
2933 * it uses the appropriate reading functions to retrieve the parameter values.
2934 *
2935 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
2936 *
2937 * @return int32_t Returns 1 on successfully reading all binary parameters, or 0 if an error occurred.
2938 * @retval 1 All parameters were successfully read and stored.
2939 * @retval 0 An error occurred during the read operation, such as I/O errors, data type mismatches, or memory allocation failures.
2940 *
2941 * @note Parameters with the 'fixed_value' attribute are handled by scanning the fixed value string
2942 * instead of reading from the file. String parameters are dynamically allocated and should be
2943 * freed by the caller when no longer needed.
2944 */
2946 int32_t i;
2947 SDDS_LAYOUT *layout;
2948 /* char *predefined_format; */
2949 char buffer[SDDS_MAXLINE];
2950#if defined(zLib)
2951 gzFile gzfp = NULL;
2952#endif
2953 FILE *fp = NULL;
2954 struct lzmafile *lzmafp = NULL;
2955 SDDS_FILEBUFFER *fBuffer;
2956
2957 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReadBinaryParameters"))
2958 return (0);
2959 layout = &SDDS_dataset->layout;
2960 if (!layout->n_parameters)
2961 return (1);
2962#if defined(zLib)
2963 if (SDDS_dataset->layout.gzipFile) {
2964 gzfp = layout->gzfp;
2965 } else {
2966#endif
2967 if (SDDS_dataset->layout.lzmaFile) {
2968 lzmafp = layout->lzmafp;
2969 } else {
2970 fp = layout->fp;
2971 }
2972#if defined(zLib)
2973 }
2974#endif
2975 fBuffer = &SDDS_dataset->fBuffer;
2976 for (i = 0; i < layout->n_parameters; i++) {
2977 if (layout->parameter_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
2978 continue;
2979 if (layout->parameter_definition[i].fixed_value) {
2980 strcpy(buffer, layout->parameter_definition[i].fixed_value);
2981 if (!SDDS_ScanData(buffer, layout->parameter_definition[i].type, 0, SDDS_dataset->parameter[i], 0, 1)) {
2982 SDDS_SetError("Unable to read page--parameter scanning error (SDDS_ReadBinaryParameters)");
2983 return (0);
2984 }
2985 } else if (layout->parameter_definition[i].type == SDDS_STRING) {
2986 if (*(char **)SDDS_dataset->parameter[i])
2987 free(*(char **)SDDS_dataset->parameter[i]);
2988#if defined(zLib)
2989 if (SDDS_dataset->layout.gzipFile) {
2990 if (!(*((char **)SDDS_dataset->parameter[i]) = SDDS_ReadGZipBinaryString(gzfp, fBuffer, 0))) {
2991 SDDS_SetError("Unable to read parameters--failure reading string (SDDS_ReadBinaryParameters)");
2992 return (0);
2993 }
2994 } else {
2995#endif
2996 if (SDDS_dataset->layout.lzmaFile) {
2997 if (!(*((char **)SDDS_dataset->parameter[i]) = SDDS_ReadLZMABinaryString(lzmafp, fBuffer, 0))) {
2998 SDDS_SetError("Unable to read parameters--failure reading string (SDDS_ReadBinaryParameters)");
2999 return (0);
3000 }
3001 } else {
3002 if (!(*((char **)SDDS_dataset->parameter[i]) = SDDS_ReadBinaryString(fp, fBuffer, 0))) {
3003 SDDS_SetError("Unable to read parameters--failure reading string (SDDS_ReadBinaryParameters)");
3004 return (0);
3005 }
3006 }
3007#if defined(zLib)
3008 }
3009#endif
3010 } else {
3011#if defined(zLib)
3012 if (SDDS_dataset->layout.gzipFile) {
3013 if (!SDDS_GZipBufferedRead(SDDS_dataset->parameter[i], SDDS_type_size[layout->parameter_definition[i].type - 1], gzfp, fBuffer, layout->parameter_definition[i].type, SDDS_dataset->layout.byteOrderDeclared)) {
3014 SDDS_SetError("Unable to read parameters--failure reading value (SDDS_ReadBinaryParameters)");
3015 return (0);
3016 }
3017 } else {
3018#endif
3019 if (SDDS_dataset->layout.lzmaFile) {
3020 if (!SDDS_LZMABufferedRead(SDDS_dataset->parameter[i], SDDS_type_size[layout->parameter_definition[i].type - 1], lzmafp, fBuffer, layout->parameter_definition[i].type, SDDS_dataset->layout.byteOrderDeclared)) {
3021 SDDS_SetError("Unable to read parameters--failure reading value (SDDS_ReadBinaryParameters)");
3022 return (0);
3023 }
3024 } else {
3025 if (!SDDS_BufferedRead(SDDS_dataset->parameter[i], SDDS_type_size[layout->parameter_definition[i].type - 1], fp, fBuffer, layout->parameter_definition[i].type, SDDS_dataset->layout.byteOrderDeclared)) {
3026 SDDS_SetError("Unable to read parameters--failure reading value (SDDS_ReadBinaryParameters)");
3027 return (0);
3028 }
3029 }
3030#if defined(zLib)
3031 }
3032#endif
3033 }
3034 }
3035 return (1);
3036}
3037
3038/**
3039 * @brief Reads binary arrays from an SDDS dataset.
3040 *
3041 * This function iterates through all array definitions within the specified SDDS dataset and reads their
3042 * binary data from the underlying file. It handles various compression formats, including uncompressed,
3043 * LZMA-compressed, and GZIP-compressed files. For each array, the function reads its definition, dimensions,
3044 * and data elements, allocating and managing memory as necessary. String arrays are handled by reading
3045 * each string individually, while other data types are read in bulk.
3046 *
3047 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
3048 *
3049 * @return int32_t Returns 1 on successful reading of all arrays, or 0 if an error occurred.
3050 * @retval 1 All arrays were successfully read and stored.
3051 * @retval 0 An error occurred during the read operation, such as I/O failures, memory allocation issues,
3052 * or corrupted array definitions.
3053 *
3054 * @note The caller is responsible for ensuring that the SDDS_dataset structure is properly initialized
3055 * and that memory allocations for arrays are managed appropriately to prevent memory leaks.
3056 */
3057int32_t SDDS_ReadBinaryArrays(SDDS_DATASET *SDDS_dataset) {
3058 int32_t i, j;
3059 SDDS_LAYOUT *layout;
3060 /* char *predefined_format; */
3061 /* static char buffer[SDDS_MAXLINE]; */
3062#if defined(zLib)
3063 gzFile gzfp = NULL;
3064#endif
3065 FILE *fp = NULL;
3066 struct lzmafile *lzmafp = NULL;
3067 SDDS_ARRAY *array;
3068 SDDS_FILEBUFFER *fBuffer;
3069
3070 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReadBinaryArrays"))
3071 return (0);
3072 layout = &SDDS_dataset->layout;
3073 if (!layout->n_arrays)
3074 return (1);
3075#if defined(zLib)
3076 if (SDDS_dataset->layout.gzipFile) {
3077 gzfp = layout->gzfp;
3078 } else {
3079#endif
3080 if (SDDS_dataset->layout.lzmaFile) {
3081 lzmafp = layout->lzmafp;
3082 } else {
3083 fp = layout->fp;
3084 }
3085#if defined(zLib)
3086 }
3087#endif
3088 fBuffer = &SDDS_dataset->fBuffer;
3089 if (!SDDS_dataset->array) {
3090 SDDS_SetError("Unable to read array--pointer to structure storage area is NULL (SDDS_ReadBinaryArrays)");
3091 return (0);
3092 }
3093 for (i = 0; i < layout->n_arrays; i++) {
3094 array = SDDS_dataset->array + i;
3095 if (array->definition && !SDDS_FreeArrayDefinition(array->definition)) {
3096 SDDS_SetError("Unable to get array--array definition corrupted (SDDS_ReadBinaryArrays)");
3097 return (0);
3098 }
3099 if (!SDDS_CopyArrayDefinition(&array->definition, layout->array_definition + i)) {
3100 SDDS_SetError("Unable to read array--definition copy failed (SDDS_ReadBinaryArrays)");
3101 return (0);
3102 }
3103 /*if (array->dimension) free(array->dimension); */
3104 if (!(array->dimension = SDDS_Realloc(array->dimension, sizeof(*array->dimension) * array->definition->dimensions))) {
3105 SDDS_SetError("Unable to read array--allocation failure (SDDS_ReadBinaryArrays)");
3106 return (0);
3107 }
3108#if defined(zLib)
3109 if (SDDS_dataset->layout.gzipFile) {
3110 if (!SDDS_GZipBufferedRead(array->dimension, sizeof(*array->dimension) * array->definition->dimensions, gzfp, fBuffer, SDDS_LONG, SDDS_dataset->layout.byteOrderDeclared)) {
3111 SDDS_SetError("Unable to read arrays--failure reading dimensions (SDDS_ReadBinaryArrays)");
3112 return (0);
3113 }
3114 } else {
3115#endif
3116 if (SDDS_dataset->layout.lzmaFile) {
3117 if (!SDDS_LZMABufferedRead(array->dimension, sizeof(*array->dimension) * array->definition->dimensions, lzmafp, fBuffer, SDDS_LONG, SDDS_dataset->layout.byteOrderDeclared)) {
3118 SDDS_SetError("Unable to read arrays--failure reading dimensions (SDDS_ReadBinaryArrays)");
3119 return (0);
3120 }
3121 } else {
3122 if (!SDDS_BufferedRead(array->dimension, sizeof(*array->dimension) * array->definition->dimensions, fp, fBuffer, SDDS_LONG, SDDS_dataset->layout.byteOrderDeclared)) {
3123 SDDS_SetError("Unable to read arrays--failure reading dimensions (SDDS_ReadBinaryArrays)");
3124 return (0);
3125 }
3126 }
3127#if defined(zLib)
3128 }
3129#endif
3130 array->elements = 1;
3131 for (j = 0; j < array->definition->dimensions; j++)
3132 array->elements *= array->dimension[j];
3133 if (array->data)
3134 free(array->data);
3135 array->data = array->pointer = NULL;
3136 if (array->elements == 0)
3137 continue;
3138 if (array->elements < 0) {
3139 SDDS_SetError("Unable to read array--number of elements is negative (SDDS_ReadBinaryArrays)");
3140 return (0);
3141 }
3142 if (!(array->data = SDDS_Realloc(array->data, array->elements * SDDS_type_size[array->definition->type - 1]))) {
3143 SDDS_SetError("Unable to read array--allocation failure (SDDS_ReadBinaryArrays)");
3144 return (0);
3145 }
3146 if (array->definition->type == SDDS_STRING) {
3147#if defined(zLib)
3148 if (SDDS_dataset->layout.gzipFile) {
3149 for (j = 0; j < array->elements; j++) {
3150 if (!(((char **)(array->data))[j] = SDDS_ReadGZipBinaryString(gzfp, fBuffer, 0))) {
3151 SDDS_SetError("Unable to read arrays--failure reading string (SDDS_ReadBinaryArrays)");
3152 return (0);
3153 }
3154 }
3155 } else {
3156#endif
3157 if (SDDS_dataset->layout.lzmaFile) {
3158 for (j = 0; j < array->elements; j++) {
3159 if (!(((char **)(array->data))[j] = SDDS_ReadLZMABinaryString(lzmafp, fBuffer, 0))) {
3160 SDDS_SetError("Unable to read arrays--failure reading string (SDDS_ReadBinaryArrays)");
3161 return (0);
3162 }
3163 }
3164 } else {
3165 for (j = 0; j < array->elements; j++) {
3166 if (!(((char **)(array->data))[j] = SDDS_ReadBinaryString(fp, fBuffer, 0))) {
3167 SDDS_SetError("Unable to read arrays--failure reading string (SDDS_ReadBinaryArrays)");
3168 return (0);
3169 }
3170 }
3171 }
3172#if defined(zLib)
3173 }
3174#endif
3175 } else {
3176#if defined(zLib)
3177 if (SDDS_dataset->layout.gzipFile) {
3178 if (!SDDS_GZipBufferedRead(array->data, SDDS_type_size[array->definition->type - 1] * array->elements, gzfp, fBuffer, array->definition->type, SDDS_dataset->layout.byteOrderDeclared)) {
3179 SDDS_SetError("Unable to read arrays--failure reading values (SDDS_ReadBinaryArrays)");
3180 return (0);
3181 }
3182 } else {
3183#endif
3184 if (SDDS_dataset->layout.lzmaFile) {
3185 if (!SDDS_LZMABufferedRead(array->data, SDDS_type_size[array->definition->type - 1] * array->elements, lzmafp, fBuffer, array->definition->type, SDDS_dataset->layout.byteOrderDeclared)) {
3186 SDDS_SetError("Unable to read arrays--failure reading values (SDDS_ReadBinaryArrays)");
3187 return (0);
3188 }
3189 } else {
3190 if (!SDDS_BufferedRead(array->data, SDDS_type_size[array->definition->type - 1] * array->elements, fp, fBuffer, array->definition->type, SDDS_dataset->layout.byteOrderDeclared)) {
3191 SDDS_SetError("Unable to read arrays--failure reading values (SDDS_ReadBinaryArrays)");
3192 return (0);
3193 }
3194 }
3195#if defined(zLib)
3196 }
3197#endif
3198 }
3199 }
3200 return (1);
3201}
3202
3203/**
3204 * @brief Reads the binary columns from an SDDS dataset.
3205 *
3206 * This function iterates through all column definitions within the specified SDDS dataset and reads their
3207 * binary data from the underlying file. It handles various compression formats, including uncompressed,
3208 * LZMA-compressed, and GZIP-compressed files. For each column, the function reads data for each row,
3209 * managing memory allocation for string columns as necessary. Non-string data types are read in bulk for
3210 * each column.
3211 *
3212 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
3213 *
3214 * @return int32_t Returns 1 on successful reading of all columns, or 0 if an error occurred.
3215 * @retval 1 All columns were successfully read and stored.
3216 * @retval 0 An error occurred during the read operation, such as I/O failures, memory allocation issues,
3217 * or corrupted column definitions.
3218 *
3219 * @note The caller is responsible for ensuring that the SDDS_dataset structure is properly initialized
3220 * and that memory allocations for columns are managed appropriately to prevent memory leaks.
3221 */
3222int32_t SDDS_ReadBinaryColumns(SDDS_DATASET *SDDS_dataset) {
3223 int64_t i, row;
3224 SDDS_LAYOUT *layout;
3225 /* char *predefined_format; */
3226 /* static char buffer[SDDS_MAXLINE]; */
3227#if defined(zLib)
3228 gzFile gzfp = NULL;
3229#endif
3230 FILE *fp = NULL;
3231 struct lzmafile *lzmafp = NULL;
3232 SDDS_FILEBUFFER *fBuffer;
3233
3234 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReadBinaryColumns"))
3235 return (0);
3236 layout = &SDDS_dataset->layout;
3237 if (!layout->n_columns || !SDDS_dataset->n_rows)
3238 return (1);
3239#if defined(zLib)
3240 if (SDDS_dataset->layout.gzipFile) {
3241 gzfp = layout->gzfp;
3242 } else {
3243#endif
3244 if (SDDS_dataset->layout.lzmaFile) {
3245 lzmafp = layout->lzmafp;
3246 } else {
3247 fp = layout->fp;
3248 }
3249#if defined(zLib)
3250 }
3251#endif
3252 fBuffer = &SDDS_dataset->fBuffer;
3253
3254 for (i = 0; i < layout->n_columns; i++) {
3255 if (layout->column_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
3256 continue;
3257 if (layout->column_definition[i].type == SDDS_STRING) {
3258#if defined(zLib)
3259 if (SDDS_dataset->layout.gzipFile) {
3260 for (row = 0; row < SDDS_dataset->n_rows; row++) {
3261 if (((char ***)SDDS_dataset->data)[i][row])
3262 free((((char ***)SDDS_dataset->data)[i][row]));
3263 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadGZipBinaryString(gzfp, fBuffer, 0))) {
3264 SDDS_SetError("Unable to read columns--failure reading string (SDDS_ReadBinaryColumns)");
3265 return (0);
3266 }
3267 }
3268 } else {
3269#endif
3270 if (SDDS_dataset->layout.lzmaFile) {
3271 for (row = 0; row < SDDS_dataset->n_rows; row++) {
3272 if (((char ***)SDDS_dataset->data)[i][row])
3273 free((((char ***)SDDS_dataset->data)[i][row]));
3274 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadLZMABinaryString(lzmafp, fBuffer, 0))) {
3275 SDDS_SetError("Unable to read columns--failure reading string (SDDS_ReadBinaryColumms)");
3276 return (0);
3277 }
3278 }
3279 } else {
3280 for (row = 0; row < SDDS_dataset->n_rows; row++) {
3281 if (((char ***)SDDS_dataset->data)[i][row])
3282 free((((char ***)SDDS_dataset->data)[i][row]));
3283 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadBinaryString(fp, fBuffer, 0))) {
3284 SDDS_SetError("Unable to read columns--failure reading string (SDDS_ReadBinaryColumms)");
3285 return (0);
3286 }
3287 }
3288 }
3289#if defined(zLib)
3290 }
3291#endif
3292 } else {
3293#if defined(zLib)
3294 if (SDDS_dataset->layout.gzipFile) {
3295 if (!SDDS_GZipBufferedRead(SDDS_dataset->data[i], SDDS_type_size[layout->column_definition[i].type - 1] * SDDS_dataset->n_rows, gzfp, fBuffer, layout->column_definition[i].type, SDDS_dataset->layout.byteOrderDeclared)) {
3296 SDDS_SetError("Unable to read columns--failure reading values (SDDS_ReadBinaryColumns)");
3297 return (0);
3298 }
3299 } else {
3300#endif
3301 if (SDDS_dataset->layout.lzmaFile) {
3302 if (!SDDS_LZMABufferedRead(SDDS_dataset->data[i], SDDS_type_size[layout->column_definition[i].type - 1] * SDDS_dataset->n_rows, lzmafp, fBuffer, layout->column_definition[i].type, SDDS_dataset->layout.byteOrderDeclared)) {
3303 SDDS_SetError("Unable to read columns--failure reading values (SDDS_ReadBinaryColumns)");
3304 return (0);
3305 }
3306 } else {
3307 if (!SDDS_BufferedRead(SDDS_dataset->data[i], SDDS_type_size[layout->column_definition[i].type - 1] * SDDS_dataset->n_rows, fp, fBuffer, layout->column_definition[i].type, SDDS_dataset->layout.byteOrderDeclared)) {
3308 SDDS_SetError("Unable to read columns--failure reading values (SDDS_ReadBinaryColumns)");
3309 return (0);
3310 }
3311 }
3312#if defined(zLib)
3313 }
3314#endif
3315 }
3316 }
3317 return (1);
3318}
3319
3320/**
3321 * @brief Reads the non-native endian binary columns from an SDDS dataset.
3322 *
3323 * This function is similar to SDDS_ReadBinaryColumns but specifically handles columns with non-native
3324 * endianness. It iterates through all column definitions within the specified SDDS dataset and reads
3325 * their binary data from the underlying file, ensuring that the byte order is correctly swapped
3326 * to match the system's native endianness. The function supports various compression formats,
3327 * including uncompressed, LZMA-compressed, and GZIP-compressed files.
3328 *
3329 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
3330 *
3331 * @return int32_t Returns 1 on successful reading and byte-swapping of all columns, or 0 if an error occurred.
3332 * @retval 1 All non-native endian columns were successfully read and byte-swapped.
3333 * @retval 0 An error occurred during the read or byte-swapping operation, such as I/O failures,
3334 * memory allocation issues, or corrupted column definitions.
3335 *
3336 * @note This function assumes that the dataset's byte order has been declared and that the
3337 * underlying file's byte order differs from the system's native byte order. Proper
3338 * initialization and configuration of the SDDS_dataset structure are required before
3339 * calling this function.
3340 */
3342 int64_t i, row;
3343 SDDS_LAYOUT *layout;
3344 /* char *predefined_format; */
3345 /* static char buffer[SDDS_MAXLINE]; */
3346#if defined(zLib)
3347 gzFile gzfp = NULL;
3348#endif
3349 FILE *fp = NULL;
3350 struct lzmafile *lzmafp = NULL;
3351 SDDS_FILEBUFFER *fBuffer;
3352
3353 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReadNonNativeBinaryColumns"))
3354 return (0);
3355 layout = &SDDS_dataset->layout;
3356 if (!layout->n_columns || !SDDS_dataset->n_rows)
3357 return (1);
3358#if defined(zLib)
3359 if (SDDS_dataset->layout.gzipFile) {
3360 gzfp = layout->gzfp;
3361 } else {
3362#endif
3363 if (SDDS_dataset->layout.lzmaFile) {
3364 lzmafp = layout->lzmafp;
3365 } else {
3366 fp = layout->fp;
3367 }
3368#if defined(zLib)
3369 }
3370#endif
3371 fBuffer = &SDDS_dataset->fBuffer;
3372
3373 for (i = 0; i < layout->n_columns; i++) {
3374 if (layout->column_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
3375 continue;
3376 if (layout->column_definition[i].type == SDDS_STRING) {
3377#if defined(zLib)
3378 if (SDDS_dataset->layout.gzipFile) {
3379 for (row = 0; row < SDDS_dataset->n_rows; row++) {
3380 if (((char ***)SDDS_dataset->data)[i][row])
3381 free((((char ***)SDDS_dataset->data)[i][row]));
3382 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadNonNativeGZipBinaryString(gzfp, fBuffer, 0))) {
3383 SDDS_SetError("Unable to read columns--failure reading string (SDDS_ReadNonNativeBinaryColumns)");
3384 return (0);
3385 }
3386 }
3387 } else {
3388#endif
3389 if (SDDS_dataset->layout.lzmaFile) {
3390 for (row = 0; row < SDDS_dataset->n_rows; row++) {
3391 if (((char ***)SDDS_dataset->data)[i][row])
3392 free((((char ***)SDDS_dataset->data)[i][row]));
3393 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadNonNativeLZMABinaryString(lzmafp, fBuffer, 0))) {
3394 SDDS_SetError("Unable to read columns--failure reading string (SDDS_ReadNonNativeBinaryColumms)");
3395 return (0);
3396 }
3397 }
3398 } else {
3399 for (row = 0; row < SDDS_dataset->n_rows; row++) {
3400 if (((char ***)SDDS_dataset->data)[i][row])
3401 free((((char ***)SDDS_dataset->data)[i][row]));
3402 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadNonNativeBinaryString(fp, fBuffer, 0))) {
3403 SDDS_SetError("Unable to read columns--failure reading string (SDDS_ReadNonNativeBinaryColumms)");
3404 return (0);
3405 }
3406 }
3407 }
3408#if defined(zLib)
3409 }
3410#endif
3411 } else {
3412#if defined(zLib)
3413 if (SDDS_dataset->layout.gzipFile) {
3414 if (!SDDS_GZipBufferedRead(SDDS_dataset->data[i], SDDS_type_size[layout->column_definition[i].type - 1] * SDDS_dataset->n_rows, gzfp, fBuffer, layout->column_definition[i].type, SDDS_dataset->layout.byteOrderDeclared)) {
3415 SDDS_SetError("Unable to read columns--failure reading values (SDDS_ReadNonNativeBinaryColumns)");
3416 return (0);
3417 }
3418 } else {
3419#endif
3420 if (SDDS_dataset->layout.lzmaFile) {
3421 if (!SDDS_LZMABufferedRead(SDDS_dataset->data[i], SDDS_type_size[layout->column_definition[i].type - 1] * SDDS_dataset->n_rows, lzmafp, fBuffer, layout->column_definition[i].type, SDDS_dataset->layout.byteOrderDeclared)) {
3422 SDDS_SetError("Unable to read columns--failure reading values (SDDS_ReadNonNativeBinaryColumns)");
3423 return (0);
3424 }
3425 } else {
3426 if (!SDDS_BufferedRead(SDDS_dataset->data[i], SDDS_type_size[layout->column_definition[i].type - 1] * SDDS_dataset->n_rows, fp, fBuffer, layout->column_definition[i].type, SDDS_dataset->layout.byteOrderDeclared)) {
3427 SDDS_SetError("Unable to read columns--failure reading values (SDDS_ReadNonNativeBinaryColumns)");
3428 return (0);
3429 }
3430 }
3431#if defined(zLib)
3432 }
3433#endif
3434 }
3435 }
3436 return (1);
3437}
3438
3439/**
3440 * @brief Swaps the endianness of the column data in an SDDS dataset.
3441 *
3442 * This function iterates through all columns in the specified SDDS dataset and swaps the byte order
3443 * of each data element to match the system's native endianness. It supports various data types,
3444 * including short, unsigned short, long, unsigned long, long long, unsigned long long, float,
3445 * double, and long double. The function ensures that binary data is correctly interpreted on systems
3446 * with different byte orders.
3447 *
3448 * @param[in,out] SDDSin Pointer to the SDDS_DATASET structure representing the dataset whose
3449 * column data endianness is to be swapped.
3450 *
3451 * @return int32_t Always returns 1.
3452 * @retval 1 The endianness of all applicable column data elements was successfully swapped.
3453 *
3454 * @note This function modifies the dataset's column data in place. It should be called only when
3455 * the dataset's byte order is known to differ from the system's native byte order.
3456 * String data types are not affected by this function.
3457 */
3459 int32_t i, row;
3460 SDDS_LAYOUT *layout;
3461 short *sData;
3462 unsigned short *suData;
3463 int32_t *lData;
3464 uint32_t *luData;
3465 int64_t *lData64;
3466 uint64_t *luData64;
3467 float *fData;
3468 double *dData;
3469 long double *ldData;
3470
3471 layout = &SDDSin->layout;
3472 for (i = 0; i < layout->n_columns; i++) {
3473 switch (layout->column_definition[i].type) {
3474 case SDDS_SHORT:
3475 sData = SDDSin->data[i];
3476 for (row = 0; row < SDDSin->n_rows; row++)
3477 SDDS_SwapShort(sData + row);
3478 break;
3479 case SDDS_USHORT:
3480 suData = SDDSin->data[i];
3481 for (row = 0; row < SDDSin->n_rows; row++)
3482 SDDS_SwapUShort(suData + row);
3483 break;
3484 case SDDS_LONG:
3485 lData = SDDSin->data[i];
3486 for (row = 0; row < SDDSin->n_rows; row++)
3487 SDDS_SwapLong(lData + row);
3488 break;
3489 case SDDS_ULONG:
3490 luData = SDDSin->data[i];
3491 for (row = 0; row < SDDSin->n_rows; row++)
3492 SDDS_SwapULong(luData + row);
3493 break;
3494 case SDDS_LONG64:
3495 lData64 = SDDSin->data[i];
3496 for (row = 0; row < SDDSin->n_rows; row++)
3497 SDDS_SwapLong64(lData64 + row);
3498 break;
3499 case SDDS_ULONG64:
3500 luData64 = SDDSin->data[i];
3501 for (row = 0; row < SDDSin->n_rows; row++)
3502 SDDS_SwapULong64(luData64 + row);
3503 break;
3504 case SDDS_LONGDOUBLE:
3505 ldData = SDDSin->data[i];
3506 for (row = 0; row < SDDSin->n_rows; row++)
3507 SDDS_SwapLongDouble(ldData + row);
3508 break;
3509 case SDDS_DOUBLE:
3510 dData = SDDSin->data[i];
3511 for (row = 0; row < SDDSin->n_rows; row++)
3512 SDDS_SwapDouble(dData + row);
3513 break;
3514 case SDDS_FLOAT:
3515 fData = SDDSin->data[i];
3516 for (row = 0; row < SDDSin->n_rows; row++)
3517 SDDS_SwapFloat(fData + row);
3518 break;
3519 default:
3520 break;
3521 }
3522 }
3523 return (1);
3524}
3525
3526/**
3527 * @brief Swaps the endianness of the parameter data in an SDDS dataset.
3528 *
3529 * This function iterates through all parameters in the specified SDDS dataset and swaps the byte order
3530 * of each data element to match the system's native endianness. It handles various data types, including
3531 * short, unsigned short, long, unsigned long, long long, unsigned long long, float, double, and
3532 * long double. Parameters with fixed values are skipped as their byte order is already consistent.
3533 *
3534 * @param[in,out] SDDSin Pointer to the SDDS_DATASET structure representing the dataset whose
3535 * parameter data endianness is to be swapped.
3536 *
3537 * @return int32_t Always returns 1.
3538 * @retval 1 The endianness of all applicable parameter data elements was successfully swapped.
3539 *
3540 * @note This function modifies the dataset's parameter data in place. It should be called only when
3541 * the dataset's byte order is known to differ from the system's native byte order.
3542 * String data types and parameters with fixed values are not affected by this function.
3543 */
3545 int32_t i;
3546 SDDS_LAYOUT *layout;
3547 short *sData;
3548 unsigned short *suData;
3549 int32_t *lData;
3550 uint32_t *luData;
3551 int64_t *lData64;
3552 uint64_t *luData64;
3553 float *fData;
3554 double *dData;
3555 long double *ldData;
3556
3557 layout = &SDDSin->layout;
3558 for (i = 0; i < layout->n_parameters; i++) {
3559 if (layout->parameter_definition[i].fixed_value) {
3560 continue;
3561 }
3562 switch (layout->parameter_definition[i].type) {
3563 case SDDS_SHORT:
3564 sData = SDDSin->parameter[i];
3565 SDDS_SwapShort(sData);
3566 break;
3567 case SDDS_USHORT:
3568 suData = SDDSin->parameter[i];
3569 SDDS_SwapUShort(suData);
3570 break;
3571 case SDDS_LONG:
3572 lData = SDDSin->parameter[i];
3573 SDDS_SwapLong(lData);
3574 break;
3575 case SDDS_ULONG:
3576 luData = SDDSin->parameter[i];
3577 SDDS_SwapULong(luData);
3578 break;
3579 case SDDS_LONG64:
3580 lData64 = SDDSin->parameter[i];
3581 SDDS_SwapLong64(lData64);
3582 break;
3583 case SDDS_ULONG64:
3584 luData64 = SDDSin->parameter[i];
3585 SDDS_SwapULong64(luData64);
3586 break;
3587 case SDDS_LONGDOUBLE:
3588 ldData = SDDSin->parameter[i];
3589 SDDS_SwapLongDouble(ldData);
3590 break;
3591 case SDDS_DOUBLE:
3592 dData = SDDSin->parameter[i];
3593 SDDS_SwapDouble(dData);
3594 break;
3595 case SDDS_FLOAT:
3596 fData = SDDSin->parameter[i];
3597 SDDS_SwapFloat(fData);
3598 break;
3599 default:
3600 break;
3601 }
3602 }
3603 return (1);
3604}
3605
3606/**
3607 * @brief Swaps the endianness of the array data in an SDDS dataset.
3608 *
3609 * This function iterates through all arrays defined in the specified SDDS dataset and swaps the byte order
3610 * of each element to match the system's native endianness. It supports various data types including
3611 * short, unsigned short, long, unsigned long, long long, unsigned long long, float, double, and long double.
3612 * The function ensures that binary data is correctly interpreted on systems with different byte orders.
3613 *
3614 * @param[in,out] SDDSin Pointer to the SDDS_DATASET structure representing the dataset whose
3615 * array data endianness is to be swapped.
3616 *
3617 * @return int32_t Always returns 1.
3618 * @retval 1 The endianness of all applicable array data elements was successfully swapped.
3619 *
3620 * @note This function modifies the dataset's array data in place. It should be called only when
3621 * the dataset's byte order is known to differ from the system's native byte order.
3622 */
3624 int32_t i, j;
3625 SDDS_LAYOUT *layout;
3626 short *sData;
3627 unsigned short *suData;
3628 int32_t *lData;
3629 uint32_t *luData;
3630 int64_t *lData64;
3631 uint64_t *luData64;
3632 float *fData;
3633 double *dData;
3634 long double *ldData;
3635
3636 layout = &SDDSin->layout;
3637
3638 for (i = 0; i < layout->n_arrays; i++) {
3639 switch (layout->array_definition[i].type) {
3640 case SDDS_SHORT:
3641 sData = SDDSin->array[i].data;
3642 for (j = 0; j < SDDSin->array[i].elements; j++)
3643 SDDS_SwapShort(sData + j);
3644 break;
3645 case SDDS_USHORT:
3646 suData = SDDSin->array[i].data;
3647 for (j = 0; j < SDDSin->array[i].elements; j++)
3648 SDDS_SwapUShort(suData + j);
3649 break;
3650 case SDDS_LONG:
3651 lData = SDDSin->array[i].data;
3652 for (j = 0; j < SDDSin->array[i].elements; j++)
3653 SDDS_SwapLong(lData + j);
3654 break;
3655 case SDDS_ULONG:
3656 luData = SDDSin->array[i].data;
3657 for (j = 0; j < SDDSin->array[i].elements; j++)
3658 SDDS_SwapULong(luData + j);
3659 break;
3660 case SDDS_LONG64:
3661 lData64 = SDDSin->array[i].data;
3662 for (j = 0; j < SDDSin->array[i].elements; j++)
3663 SDDS_SwapLong64(lData64 + j);
3664 break;
3665 case SDDS_ULONG64:
3666 luData64 = SDDSin->array[i].data;
3667 for (j = 0; j < SDDSin->array[i].elements; j++)
3668 SDDS_SwapULong64(luData64 + j);
3669 break;
3670 case SDDS_LONGDOUBLE:
3671 ldData = SDDSin->array[i].data;
3672 for (j = 0; j < SDDSin->array[i].elements; j++)
3673 SDDS_SwapLongDouble(ldData + j);
3674 break;
3675 case SDDS_DOUBLE:
3676 dData = SDDSin->array[i].data;
3677 for (j = 0; j < SDDSin->array[i].elements; j++)
3678 SDDS_SwapDouble(dData + j);
3679 break;
3680 case SDDS_FLOAT:
3681 fData = SDDSin->array[i].data;
3682 for (j = 0; j < SDDSin->array[i].elements; j++)
3683 SDDS_SwapFloat(fData + j);
3684 break;
3685 default:
3686 break;
3687 }
3688 }
3689 return (1);
3690}
3691
3692/**
3693 * @brief Swaps the endianness of a short integer.
3694 *
3695 * This function swaps the byte order of a 16-bit short integer pointed to by the provided data pointer.
3696 * It effectively converts the data between little-endian and big-endian formats.
3697 *
3698 * @param[in,out] data Pointer to the short integer whose byte order is to be swapped.
3699 *
3700 * @note The function modifies the data in place. Ensure that the pointer is valid and points to a
3701 * properly aligned 16-bit short integer.
3702 */
3703void SDDS_SwapShort(short *data) {
3704 unsigned char c1;
3705 c1 = *((char *)data);
3706 *((char *)data) = *(((char *)data) + 1);
3707 *(((char *)data) + 1) = c1;
3708}
3709
3710/**
3711 * @brief Swaps the endianness of an unsigned short integer.
3712 *
3713 * This function swaps the byte order of a 16-bit unsigned short integer pointed to by the provided data pointer.
3714 * It effectively converts the data between little-endian and big-endian formats.
3715 *
3716 * @param[in,out] data Pointer to the unsigned short integer whose byte order is to be swapped.
3717 *
3718 * @note The function modifies the data in place. Ensure that the pointer is valid and points to a
3719 * properly aligned 16-bit unsigned short integer.
3720 */
3721void SDDS_SwapUShort(unsigned short *data) {
3722 unsigned char c1;
3723 c1 = *((char *)data);
3724 *((char *)data) = *(((char *)data) + 1);
3725 *(((char *)data) + 1) = c1;
3726}
3727
3728/**
3729 * @brief Swaps the endianness of a 32-bit integer.
3730 *
3731 * This function swaps the byte order of a 32-bit integer pointed to by the provided data pointer.
3732 * It effectively converts the data between little-endian and big-endian formats.
3733 *
3734 * @param[in,out] data Pointer to the 32-bit integer whose byte order is to be swapped.
3735 *
3736 * @note The function modifies the data in place. Ensure that the pointer is valid and points to a
3737 * properly aligned 32-bit integer.
3738 */
3739void SDDS_SwapLong(int32_t *data) {
3740 int32_t copy;
3741 short i, j;
3742 copy = *data;
3743 for (i = 0, j = 3; i < 4; i++, j--)
3744 *(((char *)data) + i) = *(((char *)&copy) + j);
3745}
3746
3747/**
3748 * @brief Swaps the endianness of a 32-bit unsigned integer.
3749 *
3750 * This function swaps the byte order of a 32-bit unsigned integer pointed to by the provided data pointer.
3751 * It effectively converts the data between little-endian and big-endian formats.
3752 *
3753 * @param[in,out] data Pointer to the 32-bit unsigned integer whose byte order is to be swapped.
3754 *
3755 * @note The function modifies the data in place. Ensure that the pointer is valid and points to a
3756 * properly aligned 32-bit unsigned integer.
3757 */
3758void SDDS_SwapULong(uint32_t *data) {
3759 uint32_t copy;
3760 short i, j;
3761 copy = *data;
3762 for (i = 0, j = 3; i < 4; i++, j--)
3763 *(((char *)data) + i) = *(((char *)&copy) + j);
3764}
3765
3766/**
3767 * @brief Swaps the endianness of a 64-bit integer.
3768 *
3769 * This function swaps the byte order of a 64-bit integer pointed to by the provided data pointer.
3770 * It effectively converts the data between little-endian and big-endian formats.
3771 *
3772 * @param[in,out] data Pointer to the 64-bit integer whose byte order is to be swapped.
3773 *
3774 * @note The function modifies the data in place. Ensure that the pointer is valid and points to a
3775 * properly aligned 64-bit integer.
3776 */
3777void SDDS_SwapLong64(int64_t *data) {
3778 int64_t copy;
3779 short i, j;
3780 copy = *data;
3781 for (i = 0, j = 7; i < 8; i++, j--)
3782 *(((char *)data) + i) = *(((char *)&copy) + j);
3783}
3784
3785/**
3786 * @brief Swaps the endianness of a 64-bit unsigned integer.
3787 *
3788 * This function swaps the byte order of a 64-bit unsigned integer pointed to by the provided data pointer.
3789 * It effectively converts the data between little-endian and big-endian formats.
3790 *
3791 * @param[in,out] data Pointer to the 64-bit unsigned integer whose byte order is to be swapped.
3792 *
3793 * @note The function modifies the data in place. Ensure that the pointer is valid and points to a
3794 * properly aligned 64-bit unsigned integer.
3795 */
3796void SDDS_SwapULong64(uint64_t *data) {
3797 uint64_t copy;
3798 short i, j;
3799 copy = *data;
3800 for (i = 0, j = 7; i < 8; i++, j--)
3801 *(((char *)data) + i) = *(((char *)&copy) + j);
3802}
3803
3804/**
3805 * @brief Swaps the endianness of a float.
3806 *
3807 * This function swaps the byte order of a 32-bit floating-point number pointed to by the provided data pointer.
3808 * It effectively converts the data between little-endian and big-endian formats.
3809 *
3810 * @param[in,out] data Pointer to the float whose byte order is to be swapped.
3811 *
3812 * @note The function modifies the data in place. Ensure that the pointer is valid and points to a
3813 * properly aligned float.
3814 */
3815void SDDS_SwapFloat(float *data) {
3816 float copy;
3817 short i, j;
3818 copy = *data;
3819 for (i = 0, j = 3; i < 4; i++, j--)
3820 *(((char *)data) + i) = *(((char *)&copy) + j);
3821}
3822
3823/**
3824 * @brief Swaps the endianness of a double.
3825 *
3826 * This function swaps the byte order of a 64-bit double-precision floating-point number pointed to by the
3827 * provided data pointer. It effectively converts the data between little-endian and big-endian formats.
3828 *
3829 * @param[in,out] data Pointer to the double whose byte order is to be swapped.
3830 *
3831 * @note The function modifies the data in place. Ensure that the pointer is valid and points to a
3832 * properly aligned double.
3833 */
3834void SDDS_SwapDouble(double *data) {
3835 double copy;
3836 short i, j;
3837 copy = *data;
3838 for (i = 0, j = 7; i < 8; i++, j--)
3839 *(((char *)data) + i) = *(((char *)&copy) + j);
3840}
3841
3842/**
3843 * @brief Swaps the endianness of a long double.
3844 *
3845 * This function swaps the byte order of a long double floating-point number pointed to by the provided data pointer.
3846 * It effectively converts the data between little-endian and big-endian formats. The function accounts for
3847 * different sizes of long double based on the system's architecture.
3848 *
3849 * @param[in,out] data Pointer to the long double whose byte order is to be swapped.
3850 *
3851 * @note The function modifies the data in place. Ensure that the pointer is valid and points to a
3852 * properly aligned long double. The size of long double may vary between different systems.
3853 */
3854void SDDS_SwapLongDouble(long double *data) {
3855 long double copy;
3856 short i, j;
3857 copy = *data;
3858 if (LDBL_DIG == 18) {
3859 for (i = 0, j = 11; i < 12; i++, j--)
3860 *(((char *)data) + i) = *(((char *)&copy) + j);
3861 } else {
3862 for (i = 0, j = 7; i < 8; i++, j--)
3863 *(((char *)data) + i) = *(((char *)&copy) + j);
3864 }
3865}
3866
3867/**
3868 * @brief Reads a non-native endian page from an SDDS dataset.
3869 *
3870 * This function reads a page of data from the specified SDDS dataset, handling data with non-native
3871 * endianness. It supports both ASCII and binary data modes, performing necessary byte order
3872 * conversions to ensure correct data interpretation on the host system.
3873 *
3874 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
3875 *
3876 * @return int32_t Returns the number of rows read on success, or 0 on failure.
3877 * @retval >0 Number of rows successfully read.
3878 * @retval 0 An error occurred during the read operation, such as I/O failures, data corruption,
3879 * or unsupported data modes.
3880 *
3881 * @note This function is a wrapper for SDDS_ReadNonNativePageDetailed with default parameters.
3882 * It should be used when no specific mode, sparse interval, or offset is required.
3883 */
3884int32_t SDDS_ReadNonNativePage(SDDS_DATASET *SDDS_dataset) {
3885 return SDDS_ReadNonNativePageDetailed(SDDS_dataset, 0, 1, 0, 0);
3886}
3887/**
3888 * @brief Reads a sparse non-native endian page from an SDDS dataset.
3889 *
3890 * This function reads a sparse page of data from the specified SDDS dataset, handling data with non-native
3891 * endianness. Sparse reading allows for selective row retrieval based on the provided interval and offset.
3892 *
3893 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
3894 * @param[in] mode Mode flag to support future expansion.
3895 * @param[in] sparse_interval Interval between rows to be read for sparsity.
3896 * @param[in] sparse_offset Offset to start reading rows for sparsity.
3897 *
3898 * @return int32_t Returns the number of rows read on success, or 0 on failure.
3899 * @retval >0 Number of rows successfully read.
3900 * @retval 0 An error occurred during the read operation, such as I/O failures, data corruption,
3901 * or unsupported data modes.
3902 *
3903 * @note This function is a wrapper for SDDS_ReadNonNativePageDetailed with specific parameters
3904 * to enable sparse reading. It should be used when selective row retrieval is desired.
3905 */
3906int32_t SDDS_ReadNonNativePageSparse(SDDS_DATASET *SDDS_dataset, uint32_t mode, int64_t sparse_interval, int64_t sparse_offset) {
3907 return SDDS_ReadNonNativePageDetailed(SDDS_dataset, mode, sparse_interval, sparse_offset, 0);
3908}
3909
3910/**
3911 * @brief Reads a detailed non-native endian page from an SDDS dataset.
3912 *
3913 * This function reads a page of data from the specified SDDS dataset, handling data with non-native
3914 * endianness. It supports both ASCII and binary data modes, performing necessary byte order
3915 * conversions to ensure correct data interpretation on the host system. Additionally, it allows
3916 * for sparse reading and reading of the last few rows based on the provided parameters.
3917 *
3918 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
3919 * @param[in] mode Mode flag to support future expansion.
3920 * @param[in] sparse_interval Interval between rows to be read for sparsity.
3921 * @param[in] sparse_offset Offset to start reading rows for sparsity.
3922 * @param[in] last_rows Number of last rows to read from the dataset.
3923 *
3924 * @return int32_t Returns the number of rows read on success, or 0 on failure.
3925 * @retval >0 Number of rows successfully read.
3926 * @retval 0 An error occurred during the read operation, such as I/O failures, data corruption,
3927 * or unsupported data modes.
3928 *
3929 * @note This function handles various compression formats, including uncompressed, LZMA-compressed,
3930 * and GZIP-compressed files. It manages memory allocation for parameters, arrays, and columns,
3931 * ensuring that data is correctly stored and byte-swapped as necessary.
3932 */
3933int32_t SDDS_ReadNonNativePageDetailed(SDDS_DATASET *SDDS_dataset, uint32_t mode, int64_t sparse_interval, int64_t sparse_offset, int64_t last_rows)
3934/* the mode argument is to support future expansion */
3935{
3936 int32_t retval;
3937 /* SDDS_LAYOUT layout_copy; */
3938
3939 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReadNonNativePageDetailed"))
3940 return (0);
3941 if (SDDS_dataset->layout.disconnected) {
3942 SDDS_SetError("Can't read page--file is disconnected (SDDS_ReadNonNativePageDetailed)");
3943 return 0;
3944 }
3945#if defined(zLib)
3946 if (SDDS_dataset->layout.gzipFile) {
3947 if (!SDDS_dataset->layout.gzfp) {
3948 SDDS_SetError("Unable to read page--NULL file pointer (SDDS_ReadNonNativePageDetailed)");
3949 return (0);
3950 }
3951 } else {
3952#endif
3953 if (SDDS_dataset->layout.lzmaFile) {
3954 if (!SDDS_dataset->layout.lzmafp) {
3955 SDDS_SetError("Unable to read page--NULL file pointer (SDDS_ReadNonNativePageDetailed)");
3956 return (0);
3957 }
3958 } else {
3959 if (!SDDS_dataset->layout.fp) {
3960 SDDS_SetError("Unable to read page--NULL file pointer (SDDS_ReadNonNativePageDetailed)");
3961 return (0);
3962 }
3963 }
3964#if defined(zLib)
3965 }
3966#endif
3967 if (SDDS_dataset->original_layout.data_mode.mode == SDDS_ASCII) {
3968 if ((retval = SDDS_ReadAsciiPage(SDDS_dataset, sparse_interval, sparse_offset, 0)) < 1) {
3969 return (retval);
3970 }
3971 } else if (SDDS_dataset->original_layout.data_mode.mode == SDDS_BINARY) {
3972 if ((retval = SDDS_ReadNonNativeBinaryPage(SDDS_dataset, sparse_interval, sparse_offset)) < 1) {
3973 return (retval);
3974 }
3975 } else {
3976 SDDS_SetError("Unable to read page--unrecognized data mode (SDDS_ReadNonNativePageDetailed)");
3977 return (0);
3978 }
3979 return (retval);
3980}
3981
3982/**
3983 * @brief Reads the last few rows from a non-native endian page in an SDDS dataset.
3984 *
3985 * This function reads the specified number of last rows from the non-native endian page of the
3986 * given SDDS dataset. It handles data with non-native endianness, performing necessary byte order
3987 * conversions to ensure correct data interpretation on the host system.
3988 *
3989 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
3990 * @param[in] last_rows Number of last rows to read from the dataset.
3991 *
3992 * @return int32_t Returns the number of rows read on success, or 0 on failure.
3993 * @retval >0 Number of rows successfully read.
3994 * @retval 0 An error occurred during the read operation, such as I/O failures, data corruption,
3995 * or unsupported data modes.
3996 *
3997 * @note This function is a wrapper for SDDS_ReadNonNativePageDetailed with specific parameters
3998 * to read the last few rows. It should be used when only the most recent rows are needed.
3999 */
4000int32_t SDDS_ReadNonNativePageLastRows(SDDS_DATASET *SDDS_dataset, int64_t last_rows) {
4001 int32_t retval;
4002 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReadNonNativePageLastRows"))
4003 return (0);
4004 if (SDDS_dataset->layout.disconnected) {
4005 SDDS_SetError("Can't read page--file is disconnected (SDDS_ReadNonNativePageLastRows)");
4006 return 0;
4007 }
4008#if defined(zLib)
4009 if (SDDS_dataset->layout.gzipFile) {
4010 if (!SDDS_dataset->layout.gzfp) {
4011 SDDS_SetError("Unable to read page--NULL file pointer (SDDS_ReadNonNativePageLastRows)");
4012 return (0);
4013 }
4014 } else {
4015#endif
4016 if (SDDS_dataset->layout.lzmaFile) {
4017 if (!SDDS_dataset->layout.lzmafp) {
4018 SDDS_SetError("Unable to read page--NULL file pointer (SDDS_ReadNonNativePageLastRows)");
4019 return (0);
4020 }
4021 } else {
4022 if (!SDDS_dataset->layout.fp) {
4023 SDDS_SetError("Unable to read page--NULL file pointer (SDDS_ReadNonNativePageLastRows)");
4024 return (0);
4025 }
4026 }
4027#if defined(zLib)
4028 }
4029#endif
4030 if (SDDS_dataset->original_layout.data_mode.mode == SDDS_ASCII) {
4031 if ((retval = SDDS_ReadAsciiPageLastRows(SDDS_dataset, last_rows)) < 1) {
4032 return (retval);
4033 }
4034 } else if (SDDS_dataset->original_layout.data_mode.mode == SDDS_BINARY) {
4035 if ((retval = SDDS_ReadNonNativeBinaryPageLastRows(SDDS_dataset, last_rows)) < 1) {
4036 return (retval);
4037 }
4038 } else {
4039 SDDS_SetError("Unable to read page--unrecognized data mode (SDDS_ReadNonNativePageLastRows)");
4040 return (0);
4041 }
4042 return (retval);
4043}
4044
4045/**
4046 * @brief Reads a non-native endian binary page from an SDDS dataset.
4047 *
4048 * This function reads a binary page from the specified SDDS dataset, handling data with non-native
4049 * endianness. It performs necessary byte order conversions to ensure correct data interpretation on
4050 * the host system. The function supports sparse reading based on the provided interval and offset.
4051 *
4052 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
4053 * @param[in] sparse_interval Interval between rows to be read for sparsity.
4054 * @param[in] sparse_offset Offset to start reading rows for sparsity.
4055 *
4056 * @return int32_t Returns the number of rows read on success, or 0 on failure.
4057 * @retval >0 Number of rows successfully read.
4058 * @retval 0 An error occurred during the read operation, such as I/O failures, data corruption,
4059 * or unsupported data modes.
4060 *
4061 * @note This function is a wrapper for SDDS_ReadNonNativeBinaryPageDetailed with specific parameters.
4062 */
4063int32_t SDDS_ReadNonNativeBinaryPage(SDDS_DATASET *SDDS_dataset, int64_t sparse_interval, int64_t sparse_offset) {
4064 return SDDS_ReadNonNativeBinaryPageDetailed(SDDS_dataset, sparse_interval, sparse_offset, 0);
4065}
4066
4067/**
4068 * @brief Reads the last few rows from a non-native endian binary page in an SDDS dataset.
4069 *
4070 * This function reads the specified number of last rows from a binary page in the given SDDS dataset,
4071 * handling data with non-native endianness. It performs necessary byte order conversions to ensure
4072 * correct data interpretation on the host system.
4073 *
4074 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
4075 * @param[in] last_rows Number of last rows to read from the dataset.
4076 *
4077 * @return int32_t Returns the number of rows read on success, or 0 on failure.
4078 * @retval >0 Number of rows successfully read.
4079 * @retval 0 An error occurred during the read operation, such as I/O failures, data corruption,
4080 * or unsupported data modes.
4081 *
4082 * @note This function is a wrapper for SDDS_ReadNonNativeBinaryPageDetailed with specific parameters
4083 * to read the last few rows. It should be used when only the most recent rows are needed.
4084 */
4085int32_t SDDS_ReadNonNativeBinaryPageLastRows(SDDS_DATASET *SDDS_dataset, int64_t last_rows) {
4086 return SDDS_ReadNonNativeBinaryPageDetailed(SDDS_dataset, 1, 0, last_rows);
4087}
4088
4089/**
4090 * @brief Reads a detailed non-native endian binary page from an SDDS dataset.
4091 *
4092 * This function reads a binary page from the specified SDDS dataset, handling data with non-native
4093 * endianness. It supports both sparse reading and reading of the last few rows based on the provided
4094 * parameters. The function performs necessary byte order conversions to ensure correct data interpretation
4095 * on the host system.
4096 *
4097 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
4098 * @param[in] sparse_interval Interval between rows to be read for sparsity.
4099 * @param[in] sparse_offset Offset to start reading rows for sparsity.
4100 * @param[in] last_rows Number of last rows to read from the dataset.
4101 *
4102 * @return int32_t Returns the page number on success, or 0 on failure.
4103 * @retval >0 Page number successfully read.
4104 * @retval 0 An error occurred during the read operation, such as I/O failures, data corruption,
4105 * or unsupported data modes.
4106 *
4107 * @note This function handles various compression formats, including uncompressed, LZMA-compressed,
4108 * and GZIP-compressed files. It manages memory allocation for parameters, arrays, and columns,
4109 * ensuring that data is correctly stored and byte-swapped as necessary.
4110 * The function also updates the dataset's row count and handles auto-recovery in case of errors.
4111 */
4112int32_t SDDS_ReadNonNativeBinaryPageDetailed(SDDS_DATASET *SDDS_dataset, int64_t sparse_interval, int64_t sparse_offset, int64_t last_rows) {
4113 int32_t n_rows32 = 0;
4114 int64_t n_rows, j, k, alloc_rows, rows_to_store, mod;
4115 /* int32_t page_number, i; */
4116#if defined(zLib)
4117 gzFile gzfp = NULL;
4118#endif
4119 FILE *fp = NULL;
4120 struct lzmafile *lzmafp = NULL;
4121 SDDS_FILEBUFFER *fBuffer;
4122
4123 /* static char s[SDDS_MAXLINE]; */
4124 n_rows = 0;
4125 SDDS_SetReadRecoveryMode(SDDS_dataset, 0);
4126#if defined(zLib)
4127 if (SDDS_dataset->layout.gzipFile) {
4128 gzfp = SDDS_dataset->layout.gzfp;
4129 } else {
4130#endif
4131 if (SDDS_dataset->layout.lzmaFile) {
4132 lzmafp = SDDS_dataset->layout.lzmafp;
4133 } else {
4134 fp = SDDS_dataset->layout.fp;
4135 }
4136#if defined(zLib)
4137 }
4138#endif
4139 fBuffer = &SDDS_dataset->fBuffer;
4140 if (!fBuffer->buffer) {
4141 if (!(fBuffer->buffer = fBuffer->data = SDDS_Malloc(sizeof(char) * defaultIOBufferSize))) {
4142 SDDS_SetError("Unable to do buffered read--allocation failure");
4143 return 0;
4144 }
4145 fBuffer->bufferSize = defaultIOBufferSize;
4146 fBuffer->bytesLeft = 0;
4147 }
4148 SDDS_dataset->rowcount_offset = -1;
4149#if defined(zLib)
4150 if (SDDS_dataset->layout.gzipFile) {
4151 if (!SDDS_GZipBufferedRead(&n_rows32, sizeof(n_rows32), gzfp, &SDDS_dataset->fBuffer, SDDS_LONG, SDDS_dataset->layout.byteOrderDeclared)) {
4152 if (gzeof(gzfp))
4153 return (SDDS_dataset->page_number = -1);
4154 SDDS_SetError("Unable to read page--failure reading number of rows (SDDS_ReadNonNativeBinaryPage)");
4155 return (0);
4156 }
4157 SDDS_SwapLong(&n_rows32);
4158 if (n_rows32 == INT32_MIN) {
4159 if (!SDDS_GZipBufferedRead(&n_rows, sizeof(n_rows), gzfp, &SDDS_dataset->fBuffer, SDDS_LONG64, SDDS_dataset->layout.byteOrderDeclared)) {
4160 if (gzeof(gzfp))
4161 return (SDDS_dataset->page_number = -1);
4162 SDDS_SetError("Unable to read page--failure reading number of rows (SDDS_ReadNonNativeBinaryPage)");
4163 return (0);
4164 }
4165 SDDS_SwapLong64(&n_rows);
4166 } else {
4167 n_rows = n_rows32;
4168 }
4169 } else {
4170#endif
4171 /* This value will only be valid if read buffering is turned off, which is done for
4172 * certain append operations! Should really modify SDDS_BufferedRead and SDDS_BufferedWrite
4173 * to provide ftell capability.
4174 */
4175 if (SDDS_dataset->layout.lzmaFile) {
4176 if (!SDDS_LZMABufferedRead(&n_rows32, sizeof(n_rows32), lzmafp, &SDDS_dataset->fBuffer, SDDS_LONG, SDDS_dataset->layout.byteOrderDeclared)) {
4177 if (lzma_eof(lzmafp))
4178 return (SDDS_dataset->page_number = -1);
4179 SDDS_SetError("Unable to read page--failure reading number of rows (SDDS_ReadNonNativeBinaryPage)");
4180 return (0);
4181 }
4182 SDDS_SwapLong(&n_rows32);
4183 if (n_rows32 == INT32_MIN) {
4184 if (!SDDS_LZMABufferedRead(&n_rows, sizeof(n_rows), lzmafp, &SDDS_dataset->fBuffer, SDDS_LONG64, SDDS_dataset->layout.byteOrderDeclared)) {
4185 if (lzma_eof(lzmafp))
4186 return (SDDS_dataset->page_number = -1);
4187 SDDS_SetError("Unable to read page--failure reading number of rows (SDDS_ReadNonNativeBinaryPage)");
4188 return (0);
4189 }
4190 SDDS_SwapLong64(&n_rows);
4191 } else {
4192 n_rows = n_rows32;
4193 }
4194 } else {
4195 SDDS_dataset->rowcount_offset = ftell(fp);
4196 if (!SDDS_BufferedRead(&n_rows32, sizeof(n_rows32), fp, &SDDS_dataset->fBuffer, SDDS_LONG, SDDS_dataset->layout.byteOrderDeclared)) {
4197 if (feof(fp))
4198 return (SDDS_dataset->page_number = -1);
4199 SDDS_SetError("Unable to read page--failure reading number of rows (SDDS_ReadNonNativeBinaryPage)");
4200 return (0);
4201 }
4202 SDDS_SwapLong(&n_rows32);
4203 if (n_rows32 == INT32_MIN) {
4204 if (!SDDS_BufferedRead(&n_rows, sizeof(n_rows), fp, &SDDS_dataset->fBuffer, SDDS_LONG64, SDDS_dataset->layout.byteOrderDeclared)) {
4205 if (feof(fp))
4206 return (SDDS_dataset->page_number = -1);
4207 SDDS_SetError("Unable to read page--failure reading number of rows (SDDS_ReadNonNativeBinaryPage)");
4208 return (0);
4209 }
4210 SDDS_SwapLong64(&n_rows);
4211 } else {
4212 n_rows = n_rows32;
4213 }
4214 }
4215#if defined(zLib)
4216 }
4217#endif
4218 if (n_rows < 0) {
4219 SDDS_SetError("Unable to read page--negative number of rows (SDDS_ReadNonNativeBinaryPage)");
4220 return (0);
4221 }
4222 if (last_rows < 0)
4223 last_rows = 0;
4224 /* Fix this limitation later */
4225 if (SDDS_dataset->layout.data_mode.column_major) {
4226 sparse_interval = 1;
4227 sparse_offset = 0;
4228 last_rows = 0;
4229 }
4230 if (last_rows) {
4231 sparse_interval = 1;
4232 sparse_offset = n_rows - last_rows;
4233 rows_to_store = last_rows + 2;
4234 alloc_rows = rows_to_store - SDDS_dataset->n_rows_allocated;
4235 }
4236 if (sparse_interval <= 0)
4237 sparse_interval = 1;
4238 if (sparse_offset < 0)
4239 sparse_offset = 0;
4240
4241 rows_to_store = (n_rows - sparse_offset) / sparse_interval + 2;
4242 alloc_rows = rows_to_store - SDDS_dataset->n_rows_allocated;
4243 if (!SDDS_StartPage(SDDS_dataset, 0) || !SDDS_LengthenTable(SDDS_dataset, alloc_rows)) {
4244 SDDS_SetError("Unable to read page--couldn't start page (SDDS_ReadNonNativeBinaryPage)");
4245 return (0);
4246 }
4247
4248 /* read the parameter values */
4249 if (!SDDS_ReadNonNativeBinaryParameters(SDDS_dataset)) {
4250 SDDS_SetError("Unable to read page--parameter reading error (SDDS_ReadNonNativeBinaryPage)");
4251 return (0);
4252 }
4253
4254 /* read the array values */
4255 if (!SDDS_ReadNonNativeBinaryArrays(SDDS_dataset)) {
4256 SDDS_SetError("Unable to read page--array reading error (SDDS_ReadNonNativeBinaryPage)");
4257 return (0);
4258 }
4259 if (SDDS_dataset->layout.data_mode.column_major) {
4260 SDDS_dataset->n_rows = n_rows;
4261 if (!SDDS_ReadNonNativeBinaryColumns(SDDS_dataset)) {
4262 SDDS_SetError("Unable to read page--column reading error (SDDS_ReadNonNativeBinaryPage)");
4263 return (0);
4264 }
4265 SDDS_SwapEndsColumnData(SDDS_dataset);
4266 return (SDDS_dataset->page_number);
4267 }
4268 if ((sparse_interval <= 1) && (sparse_offset == 0)) {
4269 for (j = 0; j < n_rows; j++) {
4270 if (!SDDS_ReadNonNativeBinaryRow(SDDS_dataset, j, 0)) {
4271 SDDS_dataset->n_rows = j - 1;
4272 if (SDDS_dataset->autoRecover) {
4274 SDDS_SwapEndsColumnData(SDDS_dataset);
4275 return (SDDS_dataset->page_number);
4276 }
4277 SDDS_SetError("Unable to read page--error reading data row (SDDS_ReadNonNativeBinaryPage)");
4278 SDDS_SetReadRecoveryMode(SDDS_dataset, 1);
4279 return (0);
4280 }
4281 }
4282 SDDS_dataset->n_rows = j;
4283 SDDS_SwapEndsColumnData(SDDS_dataset);
4284 return (SDDS_dataset->page_number);
4285 } else {
4286 for (j = 0; j < sparse_offset; j++) {
4287 if (!SDDS_ReadNonNativeBinaryRow(SDDS_dataset, 0, 1)) {
4288 SDDS_dataset->n_rows = 0;
4289 if (SDDS_dataset->autoRecover) {
4291 SDDS_SwapEndsColumnData(SDDS_dataset);
4292 return (SDDS_dataset->page_number);
4293 }
4294 SDDS_SetError("Unable to read page--error reading data row (SDDS_ReadNonNativeBinaryPage)");
4295 SDDS_SetReadRecoveryMode(SDDS_dataset, 1);
4296 return (0);
4297 }
4298 }
4299 n_rows -= sparse_offset;
4300 for (j = k = 0; j < n_rows; j++) {
4301 if (!SDDS_ReadNonNativeBinaryRow(SDDS_dataset, k, mod = j % sparse_interval)) {
4302 SDDS_dataset->n_rows = k - 1;
4303 if (SDDS_dataset->autoRecover) {
4305 SDDS_SwapEndsColumnData(SDDS_dataset);
4306 return (SDDS_dataset->page_number);
4307 }
4308 SDDS_SetError("Unable to read page--error reading data row (SDDS_ReadNonNativeBinaryPage)");
4309 SDDS_SetReadRecoveryMode(SDDS_dataset, 1);
4310 return (0);
4311 }
4312 k += mod ? 0 : 1;
4313 }
4314 SDDS_dataset->n_rows = k;
4315 SDDS_SwapEndsColumnData(SDDS_dataset);
4316 return (SDDS_dataset->page_number);
4317 }
4318}
4319
4320/**
4321 * @brief Reads non-native endian binary parameters from an SDDS dataset.
4322 *
4323 * This function iterates through all parameter definitions in the specified SDDS dataset and reads their
4324 * binary data from the underlying file. It handles various data types, including short, unsigned short,
4325 * long, unsigned long, long long, unsigned long long, float, double, and long double. For string
4326 * parameters, it reads each string individually, ensuring proper memory allocation and byte order
4327 * conversion. Parameters with fixed values are processed by scanning the fixed value strings into
4328 * the appropriate data types. The function supports different compression formats, including uncompressed,
4329 * LZMA-compressed, and GZIP-compressed files.
4330 *
4331 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
4332 *
4333 * @return int32_t Returns 1 on successful reading and byte-swapping of all parameters, or 0 if an error occurred.
4334 * @retval 1 All non-native endian parameters were successfully read and byte-swapped.
4335 * @retval 0 An error occurred during the read or byte-swapping process, such as I/O failures, memory allocation issues,
4336 * or corrupted parameter definitions.
4337 *
4338 * @note This function modifies the dataset's parameter data in place. It should be called after successfully opening
4339 * and preparing the dataset for reading. Ensure that the dataset structure is properly initialized to prevent
4340 * undefined behavior.
4341 */
4343 int32_t i;
4344 SDDS_LAYOUT *layout;
4345 /* char *predefined_format; */
4346 char buffer[SDDS_MAXLINE];
4347#if defined(zLib)
4348 gzFile gzfp = NULL;
4349#endif
4350 FILE *fp = NULL;
4351 struct lzmafile *lzmafp = NULL;
4352 SDDS_FILEBUFFER *fBuffer;
4353
4354 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReadNonNativeBinaryParameters"))
4355 return (0);
4356 layout = &SDDS_dataset->layout;
4357 if (!layout->n_parameters)
4358 return (1);
4359#if defined(zLib)
4360 if (SDDS_dataset->layout.gzipFile) {
4361 gzfp = layout->gzfp;
4362 } else {
4363#endif
4364 if (SDDS_dataset->layout.lzmaFile) {
4365 lzmafp = layout->lzmafp;
4366 } else {
4367 fp = layout->fp;
4368 }
4369#if defined(zLib)
4370 }
4371#endif
4372 fBuffer = &SDDS_dataset->fBuffer;
4373 for (i = 0; i < layout->n_parameters; i++) {
4374 if (layout->parameter_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
4375 continue;
4376 if (layout->parameter_definition[i].fixed_value) {
4377 strcpy(buffer, layout->parameter_definition[i].fixed_value);
4378 if (!SDDS_ScanData(buffer, layout->parameter_definition[i].type, 0, SDDS_dataset->parameter[i], 0, 1)) {
4379 SDDS_SetError("Unable to read page--parameter scanning error (SDDS_ReadNonNativeBinaryParameters)");
4380 return (0);
4381 }
4382 } else if (layout->parameter_definition[i].type == SDDS_STRING) {
4383 if (*(char **)SDDS_dataset->parameter[i])
4384 free(*(char **)SDDS_dataset->parameter[i]);
4385#if defined(zLib)
4386 if (SDDS_dataset->layout.gzipFile) {
4387 if (!(*((char **)SDDS_dataset->parameter[i]) = SDDS_ReadNonNativeGZipBinaryString(gzfp, fBuffer, 0))) {
4388 SDDS_SetError("Unable to read parameters--failure reading string (SDDS_ReadNonNativeBinaryParameters)");
4389 return (0);
4390 }
4391 } else {
4392#endif
4393 if (SDDS_dataset->layout.lzmaFile) {
4394 if (!(*((char **)SDDS_dataset->parameter[i]) = SDDS_ReadNonNativeLZMABinaryString(lzmafp, fBuffer, 0))) {
4395 SDDS_SetError("Unable to read parameters--failure reading string (SDDS_ReadNonNativeBinaryParameters)");
4396 return (0);
4397 }
4398 } else {
4399 if (!(*((char **)SDDS_dataset->parameter[i]) = SDDS_ReadNonNativeBinaryString(fp, fBuffer, 0))) {
4400 SDDS_SetError("Unable to read parameters--failure reading string (SDDS_ReadNonNativeBinaryParameters)");
4401 return (0);
4402 }
4403 }
4404#if defined(zLib)
4405 }
4406#endif
4407 } else {
4408#if defined(zLib)
4409 if (SDDS_dataset->layout.gzipFile) {
4410 if (!SDDS_GZipBufferedRead(SDDS_dataset->parameter[i], SDDS_type_size[layout->parameter_definition[i].type - 1], gzfp, fBuffer, layout->parameter_definition[i].type, SDDS_dataset->layout.byteOrderDeclared)) {
4411 SDDS_SetError("Unable to read parameters--failure reading value (SDDS_ReadNonNativeBinaryParameters)");
4412 return (0);
4413 }
4414 } else {
4415#endif
4416 if (SDDS_dataset->layout.lzmaFile) {
4417 if (!SDDS_LZMABufferedRead(SDDS_dataset->parameter[i], SDDS_type_size[layout->parameter_definition[i].type - 1], lzmafp, fBuffer, layout->parameter_definition[i].type, SDDS_dataset->layout.byteOrderDeclared)) {
4418 SDDS_SetError("Unable to read parameters--failure reading value (SDDS_ReadNonNativeBinaryParameters)");
4419 return (0);
4420 }
4421 } else {
4422 if (!SDDS_BufferedRead(SDDS_dataset->parameter[i], SDDS_type_size[layout->parameter_definition[i].type - 1], fp, fBuffer, layout->parameter_definition[i].type, SDDS_dataset->layout.byteOrderDeclared)) {
4423 SDDS_SetError("Unable to read parameters--failure reading value (SDDS_ReadNonNativeBinaryParameters)");
4424 return (0);
4425 }
4426 }
4427#if defined(zLib)
4428 }
4429#endif
4430 }
4431 }
4432 SDDS_SwapEndsParameterData(SDDS_dataset);
4433 return (1);
4434}
4435
4436/**
4437 * @brief Reads non-native endian binary arrays from an SDDS dataset.
4438 *
4439 * This function iterates through all array definitions in the specified SDDS dataset and reads their
4440 * binary data from the underlying file. It handles various data types, including short, unsigned short,
4441 * long, unsigned long, long long, unsigned long long, float, double, and long double. For string
4442 * arrays, it reads each string individually, ensuring proper memory allocation and byte order conversion.
4443 * The function supports different compression formats, including uncompressed, LZMA-compressed, and
4444 * GZIP-compressed files. After reading, it swaps the endianness of the array data to match the system's
4445 * native byte order.
4446 *
4447 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
4448 *
4449 * @return int32_t Returns 1 on successful reading and byte-swapping of all arrays, or 0 if an error occurred.
4450 * @retval 1 All non-native endian arrays were successfully read and byte-swapped.
4451 * @retval 0 An error occurred during the read or byte-swapping process, such as I/O failures, memory allocation issues,
4452 * or corrupted array definitions.
4453 *
4454 * @note This function modifies the dataset's array data in place. It should be called after successfully opening
4455 * and preparing the dataset for reading. Ensure that the dataset structure is properly initialized to prevent
4456 * undefined behavior.
4457 */
4459 int32_t i, j;
4460 SDDS_LAYOUT *layout;
4461 /* char *predefined_format; */
4462 /* static char buffer[SDDS_MAXLINE]; */
4463#if defined(zLib)
4464 gzFile gzfp = NULL;
4465#endif
4466 FILE *fp = NULL;
4467 struct lzmafile *lzmafp = NULL;
4468 SDDS_ARRAY *array;
4469 SDDS_FILEBUFFER *fBuffer;
4470
4471 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReadNonNativeBinaryArrays"))
4472 return (0);
4473 layout = &SDDS_dataset->layout;
4474 if (!layout->n_arrays)
4475 return (1);
4476#if defined(zLib)
4477 if (SDDS_dataset->layout.gzipFile) {
4478 gzfp = layout->gzfp;
4479 } else {
4480#endif
4481 if (SDDS_dataset->layout.lzmaFile) {
4482 lzmafp = layout->lzmafp;
4483 } else {
4484 fp = layout->fp;
4485 }
4486#if defined(zLib)
4487 }
4488#endif
4489 fBuffer = &SDDS_dataset->fBuffer;
4490 if (!SDDS_dataset->array) {
4491 SDDS_SetError("Unable to read array--pointer to structure storage area is NULL (SDDS_ReadNonNativeBinaryArrays)");
4492 return (0);
4493 }
4494 for (i = 0; i < layout->n_arrays; i++) {
4495 array = SDDS_dataset->array + i;
4496 if (array->definition && !SDDS_FreeArrayDefinition(array->definition)) {
4497 SDDS_SetError("Unable to get array--array definition corrupted (SDDS_ReadNonNativeBinaryArrays)");
4498 return (0);
4499 }
4500 if (!SDDS_CopyArrayDefinition(&array->definition, layout->array_definition + i)) {
4501 SDDS_SetError("Unable to read array--definition copy failed (SDDS_ReadNonNativeBinaryArrays)");
4502 return (0);
4503 }
4504 /*if (array->dimension) free(array->dimension); */
4505 if (!(array->dimension = SDDS_Realloc(array->dimension, sizeof(*array->dimension) * array->definition->dimensions))) {
4506 SDDS_SetError("Unable to read array--allocation failure (SDDS_ReadNonNativeBinaryArrays)");
4507 return (0);
4508 }
4509#if defined(zLib)
4510 if (SDDS_dataset->layout.gzipFile) {
4511 if (!SDDS_GZipBufferedRead(array->dimension, sizeof(*array->dimension) * array->definition->dimensions, gzfp, fBuffer, SDDS_LONG, SDDS_dataset->layout.byteOrderDeclared)) {
4512 SDDS_SetError("Unable to read arrays--failure reading dimensions (SDDS_ReadNonNativeBinaryArrays)");
4513 return (0);
4514 }
4515 } else {
4516#endif
4517 if (SDDS_dataset->layout.lzmaFile) {
4518 if (!SDDS_LZMABufferedRead(array->dimension, sizeof(*array->dimension) * array->definition->dimensions, lzmafp, fBuffer, SDDS_LONG, SDDS_dataset->layout.byteOrderDeclared)) {
4519 SDDS_SetError("Unable to read arrays--failure reading dimensions (SDDS_ReadNonNativeBinaryArrays)");
4520 return (0);
4521 }
4522 } else {
4523 if (!SDDS_BufferedRead(array->dimension, sizeof(*array->dimension) * array->definition->dimensions, fp, fBuffer, SDDS_LONG, SDDS_dataset->layout.byteOrderDeclared)) {
4524 SDDS_SetError("Unable to read arrays--failure reading dimensions (SDDS_ReadNonNativeBinaryArrays)");
4525 return (0);
4526 }
4527 }
4528#if defined(zLib)
4529 }
4530#endif
4531 array->elements = 1;
4532 for (j = 0; j < array->definition->dimensions; j++) {
4533 SDDS_SwapLong(&(array->dimension[j]));
4534 array->elements *= array->dimension[j];
4535 }
4536 if (array->data)
4537 free(array->data);
4538 array->data = array->pointer = NULL;
4539 if (array->elements == 0)
4540 continue;
4541 if (array->elements < 0) {
4542 SDDS_SetError("Unable to read array--number of elements is negative (SDDS_ReadNonNativeBinaryArrays)");
4543 return (0);
4544 }
4545 if (!(array->data = SDDS_Realloc(array->data, array->elements * SDDS_type_size[array->definition->type - 1]))) {
4546 SDDS_SetError("Unable to read array--allocation failure (SDDS_ReadNonNativeBinaryArrays)");
4547 return (0);
4548 }
4549 if (array->definition->type == SDDS_STRING) {
4550#if defined(zLib)
4551 if (SDDS_dataset->layout.gzipFile) {
4552 for (j = 0; j < array->elements; j++) {
4553 if (!(((char **)(array->data))[j] = SDDS_ReadNonNativeGZipBinaryString(gzfp, fBuffer, 0))) {
4554 SDDS_SetError("Unable to read arrays--failure reading string (SDDS_ReadNonNativeBinaryArrays)");
4555 return (0);
4556 }
4557 }
4558 } else {
4559#endif
4560 if (SDDS_dataset->layout.lzmaFile) {
4561 for (j = 0; j < array->elements; j++) {
4562 if (!(((char **)(array->data))[j] = SDDS_ReadNonNativeLZMABinaryString(lzmafp, fBuffer, 0))) {
4563 SDDS_SetError("Unable to read arrays--failure reading string (SDDS_ReadNonNativeBinaryArrays)");
4564 return (0);
4565 }
4566 }
4567 } else {
4568 for (j = 0; j < array->elements; j++) {
4569 if (!(((char **)(array->data))[j] = SDDS_ReadNonNativeBinaryString(fp, fBuffer, 0))) {
4570 SDDS_SetError("Unable to read arrays--failure reading string (SDDS_ReadNonNativeBinaryArrays)");
4571 return (0);
4572 }
4573 }
4574 }
4575#if defined(zLib)
4576 }
4577#endif
4578 } else {
4579#if defined(zLib)
4580 if (SDDS_dataset->layout.gzipFile) {
4581 if (!SDDS_GZipBufferedRead(array->data, SDDS_type_size[array->definition->type - 1] * array->elements, gzfp, fBuffer, array->definition->type, SDDS_dataset->layout.byteOrderDeclared)) {
4582 SDDS_SetError("Unable to read arrays--failure reading values (SDDS_ReadNonNativeBinaryArrays)");
4583 return (0);
4584 }
4585 } else {
4586#endif
4587 if (SDDS_dataset->layout.lzmaFile) {
4588 if (!SDDS_LZMABufferedRead(array->data, SDDS_type_size[array->definition->type - 1] * array->elements, lzmafp, fBuffer, array->definition->type, SDDS_dataset->layout.byteOrderDeclared)) {
4589 SDDS_SetError("Unable to read arrays--failure reading values (SDDS_ReadNonNativeBinaryArrays)");
4590 return (0);
4591 }
4592 } else {
4593 if (!SDDS_BufferedRead(array->data, SDDS_type_size[array->definition->type - 1] * array->elements, fp, fBuffer, array->definition->type, SDDS_dataset->layout.byteOrderDeclared)) {
4594 SDDS_SetError("Unable to read arrays--failure reading values (SDDS_ReadNonNativeBinaryArrays)");
4595 return (0);
4596 }
4597 }
4598#if defined(zLib)
4599 }
4600#endif
4601 }
4602 }
4603 SDDS_SwapEndsArrayData(SDDS_dataset);
4604 return (1);
4605}
4606
4607/**
4608 * @brief Reads a non-native endian binary row from an SDDS dataset.
4609 *
4610 * This function reads a single row of data from the specified SDDS dataset, handling data with
4611 * non-native endianness. It iterates through all column definitions and reads each column's data
4612 * for the given row. For string columns, it ensures proper memory allocation and byte order conversion.
4613 * For other data types, it reads the binary data and performs necessary byte swapping. The function
4614 * supports different compression formats, including uncompressed, LZMA-compressed, and GZIP-compressed files.
4615 *
4616 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
4617 * @param[in] row The index of the row to read.
4618 * @param[in] skip If non-zero, the function will skip reading the row data, useful for sparse reading.
4619 *
4620 * @return int32_t Returns 1 on successful reading of the row, or 0 if an error occurred.
4621 * @retval 1 The row was successfully read and byte-swapped.
4622 * @retval 0 An error occurred during the read or byte-swapping process, such as I/O failures or corrupted data.
4623 *
4624 * @note This function modifies the dataset's data in place. It should be called after successfully
4625 * opening and preparing the dataset for reading. Ensure that the dataset structure is properly initialized
4626 * to prevent undefined behavior.
4627 */
4628int32_t SDDS_ReadNonNativeBinaryRow(SDDS_DATASET *SDDS_dataset, int64_t row, int32_t skip) {
4629 int64_t i, type, size;
4630 SDDS_LAYOUT *layout;
4631#if defined(zLib)
4632 gzFile gzfp;
4633#endif
4634 FILE *fp;
4635 struct lzmafile *lzmafp;
4636 SDDS_FILEBUFFER *fBuffer;
4637
4638 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReadNonNativeBinaryRow"))
4639 return (0);
4640 layout = &SDDS_dataset->layout;
4641 fBuffer = &SDDS_dataset->fBuffer;
4642
4643#if defined(zLib)
4644 if (SDDS_dataset->layout.gzipFile) {
4645 gzfp = layout->gzfp;
4646 for (i = 0; i < layout->n_columns; i++) {
4647 if (layout->column_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
4648 continue;
4649 if ((type = layout->column_definition[i].type) == SDDS_STRING) {
4650 if (!skip) {
4651 if (((char ***)SDDS_dataset->data)[i][row])
4652 free((((char ***)SDDS_dataset->data)[i][row]));
4653 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadNonNativeGZipBinaryString(gzfp, fBuffer, 0))) {
4654 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadNonNativeBinaryRow)");
4655 return (0);
4656 }
4657 } else {
4658 if (!SDDS_ReadNonNativeGZipBinaryString(gzfp, fBuffer, 1)) {
4659 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadNonNativeBinaryRow)");
4660 return 0;
4661 }
4662 }
4663 } else {
4664 size = SDDS_type_size[type - 1];
4665 if (!SDDS_GZipBufferedRead(skip ? NULL : (char *)SDDS_dataset->data[i] + row * size, size, gzfp, fBuffer, type, SDDS_dataset->layout.byteOrderDeclared)) {
4666 SDDS_SetError("Unable to read row--failure reading value (SDDS_ReadNonNativeBinaryRow)");
4667 return (0);
4668 }
4669 }
4670 }
4671 } else {
4672#endif
4673 if (SDDS_dataset->layout.lzmaFile) {
4674 lzmafp = layout->lzmafp;
4675 for (i = 0; i < layout->n_columns; i++) {
4676 if (layout->column_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
4677 continue;
4678 if ((type = layout->column_definition[i].type) == SDDS_STRING) {
4679 if (!skip) {
4680 if (((char ***)SDDS_dataset->data)[i][row])
4681 free((((char ***)SDDS_dataset->data)[i][row]));
4682 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadNonNativeLZMABinaryString(lzmafp, fBuffer, 0))) {
4683 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadNonNativeBinaryRow)");
4684 return (0);
4685 }
4686 } else {
4687 if (!SDDS_ReadNonNativeLZMABinaryString(lzmafp, fBuffer, 1)) {
4688 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadNonNativeBinaryRow)");
4689 return 0;
4690 }
4691 }
4692 } else {
4693 size = SDDS_type_size[type - 1];
4694 if (!SDDS_LZMABufferedRead(skip ? NULL : (char *)SDDS_dataset->data[i] + row * size, size, lzmafp, fBuffer, type, SDDS_dataset->layout.byteOrderDeclared)) {
4695 SDDS_SetError("Unable to read row--failure reading value (SDDS_ReadNonNativeBinaryRow)");
4696 return (0);
4697 }
4698 }
4699 }
4700 } else {
4701 fp = layout->fp;
4702 for (i = 0; i < layout->n_columns; i++) {
4703 if (layout->column_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
4704 continue;
4705 if ((type = layout->column_definition[i].type) == SDDS_STRING) {
4706 if (!skip) {
4707 if (((char ***)SDDS_dataset->data)[i][row])
4708 free((((char ***)SDDS_dataset->data)[i][row]));
4709 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadNonNativeBinaryString(fp, fBuffer, 0))) {
4710 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadNonNativeBinaryRow)");
4711 return (0);
4712 }
4713 } else {
4714 if (!SDDS_ReadNonNativeBinaryString(fp, fBuffer, 1)) {
4715 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadNonNativeBinaryRow)");
4716 return 0;
4717 }
4718 }
4719 } else {
4720 size = SDDS_type_size[type - 1];
4721 if (!SDDS_BufferedRead(skip ? NULL : (char *)SDDS_dataset->data[i] + row * size, size, fp, fBuffer, type, SDDS_dataset->layout.byteOrderDeclared)) {
4722 SDDS_SetError("Unable to read row--failure reading value (SDDS_ReadNonNativeBinaryRow)");
4723 return (0);
4724 }
4725 }
4726 }
4727 }
4728#if defined(zLib)
4729 }
4730#endif
4731 return (1);
4732}
4733
4734/**
4735 * @brief Reads a non-native endian binary string from a file.
4736 *
4737 * This function reads a binary string from the specified file pointer, handling non-native endianness.
4738 * It first reads the length of the string, swaps its byte order if necessary, allocates memory for the
4739 * string, reads the string data, and null-terminates it.
4740 *
4741 * @param[in] fp Pointer to the FILE from which to read the string.
4742 * @param[in,out] fBuffer Pointer to the SDDS_FILEBUFFER structure used for buffered reading.
4743 * @param[in] skip If non-zero, the function will skip reading the string data, useful for sparse reading.
4744 *
4745 * @return char* Returns a pointer to the read string on success, or NULL if an error occurred.
4746 * @retval Non-NULL Pointer to the newly allocated string.
4747 * @retval NULL An error occurred during reading or memory allocation.
4748 *
4749 * @note The caller is responsible for freeing the returned string to prevent memory leaks.
4750 */
4751char *SDDS_ReadNonNativeBinaryString(FILE *fp, SDDS_FILEBUFFER *fBuffer, int32_t skip) {
4752 int32_t length;
4753 char *string;
4754
4755 if (!SDDS_BufferedRead(&length, sizeof(length), fp, fBuffer, SDDS_LONG, 0))
4756 return (0);
4757 SDDS_SwapLong(&length);
4758 if (length < 0)
4759 return (0);
4760 if (!(string = SDDS_Malloc(sizeof(*string) * (length + 1))))
4761 return (NULL);
4762 if (length && !SDDS_BufferedRead(skip ? NULL : string, sizeof(*string) * length, fp, fBuffer, SDDS_STRING, 0))
4763 return (NULL);
4764 string[length] = 0;
4765 return (string);
4766}
4767
4768/**
4769 * @brief Reads a non-native endian binary string from an LZMA-compressed file.
4770 *
4771 * This function reads a binary string from the specified LZMA-compressed file pointer, handling
4772 * non-native endianness. It first reads the length of the string, swaps its byte order if necessary,
4773 * allocates memory for the string, reads the string data, and null-terminates it.
4774 *
4775 * @param[in] lzmafp Pointer to the LZMAFILE from which to read the string.
4776 * @param[in,out] fBuffer Pointer to the SDDS_FILEBUFFER structure used for buffered reading.
4777 * @param[in] skip If non-zero, the function will skip reading the string data, useful for sparse reading.
4778 *
4779 * @return char* Returns a pointer to the read string on success, or NULL if an error occurred.
4780 * @retval Non-NULL Pointer to the newly allocated string.
4781 * @retval NULL An error occurred during reading or memory allocation.
4782 *
4783 * @note The caller is responsible for freeing the returned string to prevent memory leaks.
4784 */
4785char *SDDS_ReadNonNativeLZMABinaryString(struct lzmafile *lzmafp, SDDS_FILEBUFFER *fBuffer, int32_t skip) {
4786 int32_t length;
4787 char *string;
4788
4789 if (!SDDS_LZMABufferedRead(&length, sizeof(length), lzmafp, fBuffer, SDDS_LONG, 0))
4790 return (0);
4791 SDDS_SwapLong(&length);
4792 if (length < 0)
4793 return (0);
4794 if (!(string = SDDS_Malloc(sizeof(*string) * (length + 1))))
4795 return (NULL);
4796 if (length && !SDDS_LZMABufferedRead(skip ? NULL : string, sizeof(*string) * length, lzmafp, fBuffer, SDDS_STRING, 0))
4797 return (NULL);
4798 string[length] = 0;
4799 return (string);
4800}
4801
4802#if defined(zLib)
4803/**
4804 * @brief Reads a non-native endian binary string from a GZIP-compressed file.
4805 *
4806 * This function reads a binary string from the specified GZIP-compressed file pointer, handling
4807 * non-native endianness. It first reads the length of the string, swaps its byte order if necessary,
4808 * allocates memory for the string, reads the string data, and null-terminates it.
4809 *
4810 * @param[in] gzfp Pointer to the gzFile from which to read the string.
4811 * @param[in,out] fBuffer Pointer to the SDDS_FILEBUFFER structure used for buffered reading.
4812 * @param[in] skip If non-zero, the function will skip reading the string data, useful for sparse reading.
4813 *
4814 * @return char* Returns a pointer to the read string on success, or NULL if an error occurred.
4815 * @retval Non-NULL Pointer to the newly allocated string.
4816 * @retval NULL An error occurred during reading or memory allocation.
4817 *
4818 * @note The caller is responsible for freeing the returned string to prevent memory leaks.
4819 */
4820char *SDDS_ReadNonNativeGZipBinaryString(gzFile gzfp, SDDS_FILEBUFFER *fBuffer, int32_t skip) {
4821 int32_t length;
4822 char *string;
4823
4824 if (!SDDS_GZipBufferedRead(&length, sizeof(length), gzfp, fBuffer, SDDS_LONG, 0))
4825 return (0);
4826 SDDS_SwapLong(&length);
4827 if (length < 0)
4828 return (0);
4829 if (!(string = SDDS_Malloc(sizeof(*string) * (length + 1))))
4830 return (NULL);
4831 if (length && !SDDS_GZipBufferedRead(skip ? NULL : string, sizeof(*string) * length, gzfp, fBuffer, SDDS_STRING, 0))
4832 return (NULL);
4833 string[length] = 0;
4834 return (string);
4835}
4836#endif
4837
4838/**
4839 * @brief Writes a non-native endian binary page to an SDDS dataset.
4840 *
4841 * This function writes a binary page to the specified SDDS dataset, handling byte order reversal
4842 * to convert between little-endian and big-endian formats. It manages various compression formats,
4843 * including uncompressed, GZIP-compressed, and LZMA-compressed files. The function performs the
4844 * following operations:
4845 * - Counts the number of rows to write.
4846 * - Writes the row count with appropriate byte order handling.
4847 * - Writes non-native endian parameters and arrays.
4848 * - Writes column data in either column-major or row-major format based on the dataset's configuration.
4849 * - Flushes the buffer to ensure all data is written to the file.
4850 *
4851 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to write to.
4852 *
4853 * @return int32_t Returns 1 on successful writing of the binary page, or 0 if an error occurred.
4854 * @retval 1 The binary page was successfully written and byte-swapped.
4855 * @retval 0 An error occurred during the write operation, such as I/O failures, memory allocation issues,
4856 * or corrupted dataset definitions.
4857 *
4858 * @note This function modifies the dataset's internal structures during the write process. Ensure that
4859 * the dataset is properly initialized and opened for writing before invoking this function. After
4860 * writing, the dataset's state is updated to reflect the newly written page.
4861 */
4863/* Write binary page with byte order reversed. Used for little-to-big
4864 * and big-to-little endian conversion
4865 */
4866{
4867 FILE *fp;
4868 struct lzmafile *lzmafp = NULL;
4869 int64_t i, rows, fixed_rows;
4870 int32_t min32 = INT32_MIN, rows32;
4871 SDDS_FILEBUFFER *fBuffer;
4872#if defined(zLib)
4873 gzFile gzfp = NULL;
4874#endif
4875
4876 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WriteNonNativeBinaryPage"))
4877 return (0);
4878 if (!(fp = SDDS_dataset->layout.fp)) {
4879 SDDS_SetError("Unable to write page--file pointer is NULL (SDDS_WriteNonNativeBinaryPage)");
4880 return (0);
4881 }
4882 fBuffer = &SDDS_dataset->fBuffer;
4883
4884 if (!fBuffer->buffer) {
4885 if (!(fBuffer->buffer = fBuffer->data = SDDS_Malloc(sizeof(char) * defaultIOBufferSize))) {
4886 SDDS_SetError("Unable to do buffered read--allocation failure (SDDS_WriteNonNativeBinaryPage)");
4887 return 0;
4888 }
4889 fBuffer->bufferSize = defaultIOBufferSize;
4890 fBuffer->bytesLeft = defaultIOBufferSize;
4891 }
4892 SDDS_SwapLong(&min32);
4893
4894 rows = SDDS_CountRowsOfInterest(SDDS_dataset);
4895#if defined(zLib)
4896 if (SDDS_dataset->layout.gzipFile) {
4897 if (!(gzfp = SDDS_dataset->layout.gzfp)) {
4898 SDDS_SetError("Unable to write page--file pointer is NULL (SDDS_WriteNonNativeBinaryPage)");
4899 return (0);
4900 }
4901 SDDS_dataset->rowcount_offset = gztell(gzfp);
4902 if (SDDS_dataset->layout.data_mode.fixed_row_count) {
4903 fixed_rows = ((rows / SDDS_dataset->layout.data_mode.fixed_row_increment) + 2) * SDDS_dataset->layout.data_mode.fixed_row_increment;
4904 if (fixed_rows > INT32_MAX) {
4905 if (!SDDS_GZipBufferedWrite(&min32, sizeof(min32), gzfp, fBuffer)) {
4906 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
4907 return (0);
4908 }
4909 SDDS_SwapLong64(&fixed_rows);
4910 if (!SDDS_GZipBufferedWrite(&fixed_rows, sizeof(fixed_rows), gzfp, fBuffer)) {
4911 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
4912 return (0);
4913 }
4914 SDDS_SwapLong64(&fixed_rows);
4915 } else {
4916 rows32 = (int32_t)fixed_rows;
4917 SDDS_SwapLong(&rows32);
4918 if (!SDDS_GZipBufferedWrite(&rows32, sizeof(rows32), gzfp, fBuffer)) {
4919 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
4920 return (0);
4921 }
4922 }
4923 } else {
4924 if (rows > INT32_MAX) {
4925 if (!SDDS_GZipBufferedWrite(&min32, sizeof(min32), gzfp, fBuffer)) {
4926 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
4927 return (0);
4928 }
4929 SDDS_SwapLong64(&rows);
4930 if (!SDDS_GZipBufferedWrite(&rows, sizeof(rows), gzfp, fBuffer)) {
4931 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
4932 return (0);
4933 }
4934 SDDS_SwapLong64(&rows);
4935 } else {
4936 rows32 = (int32_t)rows;
4937 SDDS_SwapLong(&rows32);
4938 if (!SDDS_GZipBufferedWrite(&rows32, sizeof(rows32), gzfp, fBuffer)) {
4939 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
4940 return (0);
4941 }
4942 }
4943 }
4944 } else {
4945#endif
4946 if (SDDS_dataset->layout.lzmaFile) {
4947 if (!(lzmafp = SDDS_dataset->layout.lzmafp)) {
4948 SDDS_SetError("Unable to write page--file pointer is NULL (SDDS_WriteNonNativeBinaryPage)");
4949 return (0);
4950 }
4951 SDDS_dataset->rowcount_offset = lzma_tell(lzmafp);
4952 if (SDDS_dataset->layout.data_mode.fixed_row_count) {
4953 fixed_rows = ((rows / SDDS_dataset->layout.data_mode.fixed_row_increment) + 2) * SDDS_dataset->layout.data_mode.fixed_row_increment;
4954 if (fixed_rows > INT32_MAX) {
4955 if (!SDDS_LZMABufferedWrite(&min32, sizeof(min32), lzmafp, fBuffer)) {
4956 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
4957 return (0);
4958 }
4959 SDDS_SwapLong64(&fixed_rows);
4960 if (!SDDS_LZMABufferedWrite(&fixed_rows, sizeof(fixed_rows), lzmafp, fBuffer)) {
4961 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
4962 return (0);
4963 }
4964 SDDS_SwapLong64(&fixed_rows);
4965 } else {
4966 rows32 = (int32_t)fixed_rows;
4967 SDDS_SwapLong(&rows32);
4968 if (!SDDS_LZMABufferedWrite(&rows32, sizeof(rows32), lzmafp, fBuffer)) {
4969 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
4970 return (0);
4971 }
4972 }
4973 } else {
4974 if (rows > INT32_MAX) {
4975 if (!SDDS_LZMABufferedWrite(&min32, sizeof(min32), lzmafp, fBuffer)) {
4976 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
4977 return (0);
4978 }
4979 SDDS_SwapLong64(&rows);
4980 if (!SDDS_LZMABufferedWrite(&rows, sizeof(rows), lzmafp, fBuffer)) {
4981 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
4982 return (0);
4983 }
4984 SDDS_SwapLong64(&rows);
4985 } else {
4986 rows32 = (int32_t)rows;
4987 SDDS_SwapLong(&rows32);
4988 if (!SDDS_LZMABufferedWrite(&rows32, sizeof(rows32), lzmafp, fBuffer)) {
4989 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
4990 return (0);
4991 }
4992 }
4993 }
4994 } else {
4995 SDDS_dataset->rowcount_offset = ftell(fp);
4996 if (SDDS_dataset->layout.data_mode.fixed_row_count) {
4997 fixed_rows = ((rows / SDDS_dataset->layout.data_mode.fixed_row_increment) + 2) * SDDS_dataset->layout.data_mode.fixed_row_increment;
4998 if (fixed_rows > INT32_MAX) {
4999 if (!SDDS_BufferedWrite(&min32, sizeof(min32), fp, fBuffer)) {
5000 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5001 return (0);
5002 }
5003 SDDS_SwapLong64(&fixed_rows);
5004 if (!SDDS_BufferedWrite(&fixed_rows, sizeof(fixed_rows), fp, fBuffer)) {
5005 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5006 return (0);
5007 }
5008 SDDS_SwapLong64(&fixed_rows);
5009 } else {
5010 rows32 = (int32_t)fixed_rows;
5011 SDDS_SwapLong(&rows32);
5012 if (!SDDS_BufferedWrite(&rows32, sizeof(rows32), fp, fBuffer)) {
5013 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5014 return (0);
5015 }
5016 }
5017 } else {
5018 if (rows > INT32_MAX) {
5019 if (!SDDS_BufferedWrite(&min32, sizeof(min32), fp, fBuffer)) {
5020 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5021 return (0);
5022 }
5023 SDDS_SwapLong64(&rows);
5024 if (!SDDS_BufferedWrite(&rows, sizeof(rows), fp, fBuffer)) {
5025 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5026 return (0);
5027 }
5028 SDDS_SwapLong64(&rows);
5029 } else {
5030 rows32 = (int32_t)rows;
5031 SDDS_SwapLong(&rows32);
5032 if (!SDDS_BufferedWrite(&rows32, sizeof(rows32), fp, fBuffer)) {
5033 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5034 return (0);
5035 }
5036 }
5037 }
5038 }
5039#if defined(zLib)
5040 }
5041#endif
5042 if (!SDDS_WriteNonNativeBinaryParameters(SDDS_dataset)) {
5043 SDDS_SetError("Unable to write page--parameter writing problem (SDDS_WriteNonNativeBinaryPage)");
5044 return 0;
5045 }
5046 if (!SDDS_WriteNonNativeBinaryArrays(SDDS_dataset)) {
5047 SDDS_SetError("Unable to write page--array writing problem (SDDS_WriteNonNativeBinaryPage)");
5048 return 0;
5049 }
5050 SDDS_SwapEndsColumnData(SDDS_dataset);
5051 if (SDDS_dataset->layout.n_columns) {
5052 if (SDDS_dataset->layout.data_mode.column_major) {
5053 if (!SDDS_WriteNonNativeBinaryColumns(SDDS_dataset)) {
5054 SDDS_SetError("Unable to write page--column writing problem (SDDS_WriteNonNativeBinaryPage)");
5055 return 0;
5056 }
5057 } else {
5058 for (i = 0; i < SDDS_dataset->n_rows; i++) {
5059 if (SDDS_dataset->row_flag[i]) {
5060 if (!SDDS_WriteNonNativeBinaryRow(SDDS_dataset, i)) {
5061 SDDS_SetError("Unable to write page--row writing problem (SDDS_WriteNonNativeBinaryPage)");
5062 return 0;
5063 }
5064 }
5065 }
5066 }
5067 }
5068 SDDS_SwapEndsColumnData(SDDS_dataset);
5069#if defined(zLib)
5070 if (SDDS_dataset->layout.gzipFile) {
5071 if (!SDDS_GZipFlushBuffer(gzfp, fBuffer)) {
5072 SDDS_SetError("Unable to write page--buffer flushing problem (SDDS_WriteNonNativeBinaryPage)");
5073 return 0;
5074 }
5075 } else {
5076#endif
5077 if (SDDS_dataset->layout.lzmaFile) {
5078 if (!SDDS_LZMAFlushBuffer(lzmafp, fBuffer)) {
5079 SDDS_SetError("Unable to write page--buffer flushing problem (SDDS_WriteNonNativeBinaryPage)");
5080 return 0;
5081 }
5082 } else {
5083 if (!SDDS_FlushBuffer(fp, fBuffer)) {
5084 SDDS_SetError("Unable to write page--buffer flushing problem (SDDS_WriteNonNativeBinaryPage)");
5085 return 0;
5086 }
5087 }
5088#if defined(zLib)
5089 }
5090#endif
5091 SDDS_dataset->last_row_written = SDDS_dataset->n_rows - 1;
5092 SDDS_dataset->n_rows_written = rows;
5093 SDDS_dataset->writing_page = 1;
5094 return (1);
5095}
5096
5097/**
5098 * @brief Writes non-native endian binary parameters to an SDDS dataset.
5099 *
5100 * This function iterates through all parameter definitions in the specified SDDS dataset and writes their
5101 * binary data to the underlying file. It handles various data types, including short, unsigned short,
5102 * long, unsigned long, long long, unsigned long long, float, double, and long double. For string
5103 * parameters, it writes each string individually, ensuring proper memory management and byte order
5104 * conversion. Parameters with fixed values are skipped during the write process. The function supports
5105 * different compression formats, including uncompressed, LZMA-compressed, and GZIP-compressed files.
5106 *
5107 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to write to.
5108 *
5109 * @return int32_t Returns 1 on successful writing of all parameters, or 0 if an error occurred.
5110 * @retval 1 All non-native endian parameters were successfully written and byte-swapped.
5111 * @retval 0 An error occurred during the write operation, such as I/O failures, memory allocation issues,
5112 * or corrupted parameter definitions.
5113 *
5114 * @note This function modifies the dataset's parameter data during the write process. Ensure that the
5115 * dataset is properly initialized and opened for writing before invoking this function. After
5116 * writing, the dataset's state is updated to reflect the written parameters.
5117 */
5119 int32_t i;
5120 SDDS_LAYOUT *layout;
5121 FILE *fp;
5122 struct lzmafile *lzmafp;
5123 SDDS_FILEBUFFER *fBuffer;
5124#if defined(zLib)
5125 gzFile gzfp;
5126#endif
5127
5128 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WriteNonNativeBinaryParameters"))
5129 return (0);
5130
5131 SDDS_SwapEndsParameterData(SDDS_dataset);
5132
5133 layout = &SDDS_dataset->layout;
5134 fBuffer = &SDDS_dataset->fBuffer;
5135#if defined(zLib)
5136 if (SDDS_dataset->layout.gzipFile) {
5137 if (!(gzfp = layout->gzfp)) {
5138 SDDS_SetError("Unable to write parameters--file pointer is NULL (SDDS_WriteNonNativeBinaryParameters)");
5139 return (0);
5140 }
5141 for (i = 0; i < layout->n_parameters; i++) {
5142 if (layout->parameter_definition[i].fixed_value)
5143 continue;
5144 if (layout->parameter_definition[i].type == SDDS_STRING) {
5145 if (!SDDS_GZipWriteNonNativeBinaryString(*((char **)SDDS_dataset->parameter[i]), gzfp, fBuffer)) {
5146 SDDS_SetError("Unable to write parameters--failure writing string (SDDS_WriteNonNativeBinaryParameters)");
5147 SDDS_SwapEndsParameterData(SDDS_dataset);
5148 return (0);
5149 }
5150 } else if (!SDDS_GZipBufferedWrite(SDDS_dataset->parameter[i], SDDS_type_size[layout->parameter_definition[i].type - 1], gzfp, fBuffer)) {
5151 SDDS_SetError("Unable to write parameters--failure writing value (SDDS_WriteBinaryParameters)");
5152 SDDS_SwapEndsParameterData(SDDS_dataset);
5153 return (0);
5154 }
5155 }
5156 } else {
5157#endif
5158 if (SDDS_dataset->layout.lzmaFile) {
5159 if (!(lzmafp = layout->lzmafp)) {
5160 SDDS_SetError("Unable to write parameters--file pointer is NULL (SDDS_WriteNonNativeBinaryParameters)");
5161 return (0);
5162 }
5163 for (i = 0; i < layout->n_parameters; i++) {
5164 if (layout->parameter_definition[i].fixed_value)
5165 continue;
5166 if (layout->parameter_definition[i].type == SDDS_STRING) {
5167 if (!SDDS_LZMAWriteNonNativeBinaryString(*((char **)SDDS_dataset->parameter[i]), lzmafp, fBuffer)) {
5168 SDDS_SetError("Unable to write parameters--failure writing string (SDDS_WriteNonNativeBinaryParameters)");
5169 SDDS_SwapEndsParameterData(SDDS_dataset);
5170 return (0);
5171 }
5172 } else if (!SDDS_LZMABufferedWrite(SDDS_dataset->parameter[i], SDDS_type_size[layout->parameter_definition[i].type - 1], lzmafp, fBuffer)) {
5173 SDDS_SetError("Unable to write parameters--failure writing value (SDDS_WriteBinaryParameters)");
5174 SDDS_SwapEndsParameterData(SDDS_dataset);
5175 return (0);
5176 }
5177 }
5178 } else {
5179 fp = layout->fp;
5180 for (i = 0; i < layout->n_parameters; i++) {
5181 if (layout->parameter_definition[i].fixed_value)
5182 continue;
5183 if (layout->parameter_definition[i].type == SDDS_STRING) {
5184 if (!SDDS_WriteNonNativeBinaryString(*((char **)SDDS_dataset->parameter[i]), fp, fBuffer)) {
5185 SDDS_SetError("Unable to write parameters--failure writing string (SDDS_WriteNonNativeBinaryParameters)");
5186 SDDS_SwapEndsParameterData(SDDS_dataset);
5187 return (0);
5188 }
5189 } else if (!SDDS_BufferedWrite(SDDS_dataset->parameter[i], SDDS_type_size[layout->parameter_definition[i].type - 1], fp, fBuffer)) {
5190 SDDS_SetError("Unable to write parameters--failure writing value (SDDS_WriteBinaryParameters)");
5191 SDDS_SwapEndsParameterData(SDDS_dataset);
5192 return (0);
5193 }
5194 }
5195 }
5196#if defined(zLib)
5197 }
5198#endif
5199
5200 SDDS_SwapEndsParameterData(SDDS_dataset);
5201 return (1);
5202}
5203
5204/**
5205 * @brief Writes non-native endian binary arrays to an SDDS dataset.
5206 *
5207 * This function iterates through all array definitions in the specified SDDS dataset and writes their
5208 * binary data to the underlying file. It handles various data types, including short, unsigned short,
5209 * long, unsigned long, long long, unsigned long long, float, double, and long double. For string
5210 * arrays, it writes each string individually, ensuring proper memory management and byte order
5211 * conversion. The function supports different compression formats, including uncompressed, LZMA-compressed,
5212 * and GZIP-compressed files. After writing, it swaps the endianness of the array data to match the system's
5213 * native byte order.
5214 *
5215 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to write to.
5216 *
5217 * @return int32_t Returns 1 on successful writing of all arrays, or 0 if an error occurred.
5218 * @retval 1 All non-native endian arrays were successfully written and byte-swapped.
5219 * @retval 0 An error occurred during the write operation, such as I/O failures, memory allocation issues,
5220 * or corrupted array definitions.
5221 *
5222 * @note This function modifies the dataset's array data during the write process. Ensure that the
5223 * dataset is properly initialized and opened for writing before invoking this function. After
5224 * writing, the dataset's state is updated to reflect the written arrays.
5225 */
5227 int32_t i, j, dimension, zero = 0;
5228 SDDS_LAYOUT *layout;
5229 FILE *fp;
5230 struct lzmafile *lzmafp;
5231 SDDS_FILEBUFFER *fBuffer;
5232#if defined(zLib)
5233 gzFile gzfp;
5234#endif
5235 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WriteNonNativeBinaryArrays"))
5236 return (0);
5237 SDDS_SwapEndsArrayData(SDDS_dataset);
5238
5239 layout = &SDDS_dataset->layout;
5240 fBuffer = &SDDS_dataset->fBuffer;
5241#if defined(zLib)
5242 if (SDDS_dataset->layout.gzipFile) {
5243 gzfp = layout->gzfp;
5244 for (i = 0; i < layout->n_arrays; i++) {
5245 if (!SDDS_dataset->array[i].dimension) {
5246 for (j = 0; j < layout->array_definition[i].dimensions; j++)
5247 if (!SDDS_GZipBufferedWrite(&zero, sizeof(zero), gzfp, fBuffer)) {
5248 SDDS_SetError("Unable to write null array--failure writing dimensions (SDDS_WriteNonNativeBinaryArrays)");
5249 SDDS_SwapEndsArrayData(SDDS_dataset);
5250 return 0;
5251 }
5252 continue;
5253 }
5254
5255 for (j = 0; j < layout->array_definition[i].dimensions; j++) {
5256 dimension = SDDS_dataset->array[i].dimension[j];
5257 SDDS_SwapLong(&dimension);
5258 if (!SDDS_GZipBufferedWrite(&dimension, sizeof(dimension), gzfp, fBuffer)) {
5259 SDDS_SetError("Unable to write arrays--failure writing dimensions (SDDS_WriteNonNativeBinaryArrays)");
5260 SDDS_SwapEndsArrayData(SDDS_dataset);
5261 return (0);
5262 }
5263 }
5264 if (layout->array_definition[i].type == SDDS_STRING) {
5265 for (j = 0; j < SDDS_dataset->array[i].elements; j++) {
5266 if (!SDDS_GZipWriteNonNativeBinaryString(((char **)SDDS_dataset->array[i].data)[j], gzfp, fBuffer)) {
5267 SDDS_SetError("Unable to write arrays--failure writing string (SDDS_WriteNonNativeBinaryArrays)");
5268 SDDS_SwapEndsArrayData(SDDS_dataset);
5269 return (0);
5270 }
5271 }
5272 } else if (!SDDS_GZipBufferedWrite(SDDS_dataset->array[i].data, SDDS_type_size[layout->array_definition[i].type - 1] * SDDS_dataset->array[i].elements, gzfp, fBuffer)) {
5273 SDDS_SetError("Unable to write arrays--failure writing values (SDDS_WriteNonNativeBinaryArrays)");
5274 SDDS_SwapEndsArrayData(SDDS_dataset);
5275 return (0);
5276 }
5277 }
5278 } else {
5279#endif
5280 if (SDDS_dataset->layout.lzmaFile) {
5281 lzmafp = layout->lzmafp;
5282 for (i = 0; i < layout->n_arrays; i++) {
5283 if (!SDDS_dataset->array[i].dimension) {
5284 for (j = 0; j < layout->array_definition[i].dimensions; j++)
5285 if (!SDDS_LZMABufferedWrite(&zero, sizeof(zero), lzmafp, fBuffer)) {
5286 SDDS_SetError("Unable to write null array--failure writing dimensions (SDDS_WriteNonNativeBinaryArrays)");
5287 SDDS_SwapEndsArrayData(SDDS_dataset);
5288 return 0;
5289 }
5290 continue;
5291 }
5292
5293 for (j = 0; j < layout->array_definition[i].dimensions; j++) {
5294 dimension = SDDS_dataset->array[i].dimension[j];
5295 SDDS_SwapLong(&dimension);
5296 if (!SDDS_LZMABufferedWrite(&dimension, sizeof(dimension), lzmafp, fBuffer)) {
5297 SDDS_SetError("Unable to write arrays--failure writing dimensions (SDDS_WriteNonNativeBinaryArrays)");
5298 SDDS_SwapEndsArrayData(SDDS_dataset);
5299 return (0);
5300 }
5301 }
5302 if (layout->array_definition[i].type == SDDS_STRING) {
5303 for (j = 0; j < SDDS_dataset->array[i].elements; j++) {
5304 if (!SDDS_LZMAWriteNonNativeBinaryString(((char **)SDDS_dataset->array[i].data)[j], lzmafp, fBuffer)) {
5305 SDDS_SetError("Unable to write arrays--failure writing string (SDDS_WriteNonNativeBinaryArrays)");
5306 SDDS_SwapEndsArrayData(SDDS_dataset);
5307 return (0);
5308 }
5309 }
5310 } else if (!SDDS_LZMABufferedWrite(SDDS_dataset->array[i].data, SDDS_type_size[layout->array_definition[i].type - 1] * SDDS_dataset->array[i].elements, lzmafp, fBuffer)) {
5311 SDDS_SetError("Unable to write arrays--failure writing values (SDDS_WriteNonNativeBinaryArrays)");
5312 SDDS_SwapEndsArrayData(SDDS_dataset);
5313 return (0);
5314 }
5315 }
5316 } else {
5317 fp = layout->fp;
5318 for (i = 0; i < layout->n_arrays; i++) {
5319 if (!SDDS_dataset->array[i].dimension) {
5320 for (j = 0; j < layout->array_definition[i].dimensions; j++)
5321 if (!SDDS_BufferedWrite(&zero, sizeof(zero), fp, fBuffer)) {
5322 SDDS_SetError("Unable to write null array--failure writing dimensions (SDDS_WriteNonNativeBinaryArrays)");
5323 SDDS_SwapEndsArrayData(SDDS_dataset);
5324 return 0;
5325 }
5326 continue;
5327 }
5328
5329 for (j = 0; j < layout->array_definition[i].dimensions; j++) {
5330 dimension = SDDS_dataset->array[i].dimension[j];
5331 SDDS_SwapLong(&dimension);
5332 if (!SDDS_BufferedWrite(&dimension, sizeof(dimension), fp, fBuffer)) {
5333 SDDS_SetError("Unable to write arrays--failure writing dimensions (SDDS_WriteNonNativeBinaryArrays)");
5334 SDDS_SwapEndsArrayData(SDDS_dataset);
5335 return (0);
5336 }
5337 }
5338 if (layout->array_definition[i].type == SDDS_STRING) {
5339 for (j = 0; j < SDDS_dataset->array[i].elements; j++) {
5340 if (!SDDS_WriteNonNativeBinaryString(((char **)SDDS_dataset->array[i].data)[j], fp, fBuffer)) {
5341 SDDS_SetError("Unable to write arrays--failure writing string (SDDS_WriteNonNativeBinaryArrays)");
5342 SDDS_SwapEndsArrayData(SDDS_dataset);
5343 return (0);
5344 }
5345 }
5346 } else if (!SDDS_BufferedWrite(SDDS_dataset->array[i].data, SDDS_type_size[layout->array_definition[i].type - 1] * SDDS_dataset->array[i].elements, fp, fBuffer)) {
5347 SDDS_SetError("Unable to write arrays--failure writing values (SDDS_WriteNonNativeBinaryArrays)");
5348 SDDS_SwapEndsArrayData(SDDS_dataset);
5349 return (0);
5350 }
5351 }
5352 }
5353#if defined(zLib)
5354 }
5355#endif
5356 SDDS_SwapEndsArrayData(SDDS_dataset);
5357 return (1);
5358}
5359
5360/**
5361 * @brief Writes a non-native endian binary row to an SDDS dataset.
5362 *
5363 * This function writes a single row of data to the specified SDDS dataset, handling byte order reversal
5364 * to convert between little-endian and big-endian formats. It supports various compression formats,
5365 * including uncompressed, GZIP-compressed, and LZMA-compressed files. The function iterates through all
5366 * column definitions, writing each column's data appropriately based on its type. For string columns,
5367 * it ensures proper memory management and byte order conversion by utilizing specialized string writing
5368 * functions. For non-string data types, it writes the binary data directly with the correct byte ordering.
5369 *
5370 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to write to.
5371 * @param[in] row The index of the row to write to the dataset.
5372 *
5373 * @return int32_t Returns 1 on successful writing of the binary row, or 0 if an error occurred.
5374 * @retval 1 The binary row was successfully written and byte-swapped.
5375 * @retval 0 An error occurred during the write operation, such as I/O failures or corrupted data.
5376 *
5377 * @note This function modifies the dataset's internal data structures during the write process. Ensure that
5378 * the dataset is properly initialized and opened for writing before invoking this function.
5379 * After writing, the dataset's state is updated to reflect the newly written row.
5380 */
5381int32_t SDDS_WriteNonNativeBinaryRow(SDDS_DATASET *SDDS_dataset, int64_t row) {
5382 int64_t i, type, size;
5383 SDDS_LAYOUT *layout;
5384 FILE *fp;
5385 struct lzmafile *lzmafp;
5386 SDDS_FILEBUFFER *fBuffer;
5387#if defined(zLib)
5388 gzFile gzfp;
5389#endif
5390
5391 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WriteNonNativeBinaryRow"))
5392 return (0);
5393 layout = &SDDS_dataset->layout;
5394 fBuffer = &SDDS_dataset->fBuffer;
5395#if defined(zLib)
5396 if (SDDS_dataset->layout.gzipFile) {
5397 gzfp = layout->gzfp;
5398 for (i = 0; i < layout->n_columns; i++) {
5399 if ((type = layout->column_definition[i].type) == SDDS_STRING) {
5400 if (!SDDS_GZipWriteNonNativeBinaryString(*((char **)SDDS_dataset->data[i] + row), gzfp, fBuffer)) {
5401 SDDS_SetError("Unable to write rows--failure writing string (SDDS_WriteNonNativeBinaryRows)");
5402 return (0);
5403 }
5404 } else {
5405 size = SDDS_type_size[type - 1];
5406 if (!SDDS_GZipBufferedWrite((char *)SDDS_dataset->data[i] + row * size, size, gzfp, fBuffer)) {
5407 SDDS_SetError("Unable to write row--failure writing value (SDDS_WriteNonNativeBinaryRow)");
5408 return (0);
5409 }
5410 }
5411 }
5412 } else {
5413#endif
5414 if (SDDS_dataset->layout.lzmaFile) {
5415 lzmafp = layout->lzmafp;
5416 for (i = 0; i < layout->n_columns; i++) {
5417 if ((type = layout->column_definition[i].type) == SDDS_STRING) {
5418 if (!SDDS_LZMAWriteNonNativeBinaryString(*((char **)SDDS_dataset->data[i] + row), lzmafp, fBuffer)) {
5419 SDDS_SetError("Unable to write rows--failure writing string (SDDS_WriteNonNativeBinaryRows)");
5420 return (0);
5421 }
5422 } else {
5423 size = SDDS_type_size[type - 1];
5424 if (!SDDS_LZMABufferedWrite((char *)SDDS_dataset->data[i] + row * size, size, lzmafp, fBuffer)) {
5425 SDDS_SetError("Unable to write row--failure writing value (SDDS_WriteNonNativeBinaryRow)");
5426 return (0);
5427 }
5428 }
5429 }
5430 } else {
5431 fp = layout->fp;
5432 for (i = 0; i < layout->n_columns; i++) {
5433 if ((type = layout->column_definition[i].type) == SDDS_STRING) {
5434 if (!SDDS_WriteNonNativeBinaryString(*((char **)SDDS_dataset->data[i] + row), fp, fBuffer)) {
5435 SDDS_SetError("Unable to write rows--failure writing string (SDDS_WriteNonNativeBinaryRows)");
5436 return (0);
5437 }
5438 } else {
5439 size = SDDS_type_size[type - 1];
5440 if (!SDDS_BufferedWrite((char *)SDDS_dataset->data[i] + row * size, size, fp, fBuffer)) {
5441 SDDS_SetError("Unable to write row--failure writing value (SDDS_WriteNonNativeBinaryRow)");
5442 return (0);
5443 }
5444 }
5445 }
5446 }
5447#if defined(zLib)
5448 }
5449#endif
5450 return (1);
5451}
5452
5453/**
5454 * @brief Writes a non-native endian binary string to a file.
5455 *
5456 * This function writes a binary string to the specified file pointer, handling non-native endianness.
5457 * It first writes the length of the string as a 32-bit integer with byte order swapped. If the string
5458 * is not to be skipped, it then writes the string data itself followed by a null terminator. If the
5459 * input string is NULL, an empty string is written instead.
5460 *
5461 * @param[in] string The string to write. If NULL, an empty string is written.
5462 * @param[in] fp Pointer to the FILE where the string will be written.
5463 * @param[in] fBuffer Pointer to the SDDS_FILEBUFFER structure used for buffered writing.
5464 *
5465 * @return int32_t Returns 1 on successful writing of the string, or 0 if an error occurred.
5466 * @retval 1 The string was successfully written and byte-swapped.
5467 * @retval 0 An error occurred during the write operation, such as I/O failures or memory allocation issues.
5468 *
5469 * @note The caller is responsible for ensuring that the file pointer `fp` is valid and open for writing.
5470 * This function does not perform memory allocation for the string; it assumes that the string
5471 * is already allocated and managed appropriately.
5472 */
5473int32_t SDDS_WriteNonNativeBinaryString(char *string, FILE *fp, SDDS_FILEBUFFER *fBuffer) {
5474 int32_t length;
5475 static char *dummy_string = "";
5476 if (!string)
5477 string = dummy_string;
5478 length = strlen(string);
5479 SDDS_SwapLong(&length);
5480 if (!SDDS_BufferedWrite(&length, sizeof(length), fp, fBuffer)) {
5481 SDDS_SetError("Unable to write string--error writing length");
5482 return (0);
5483 }
5484 SDDS_SwapLong(&length);
5485 if (length && !SDDS_BufferedWrite(string, sizeof(*string) * length, fp, fBuffer)) {
5486 SDDS_SetError("Unable to write string--error writing contents");
5487 return (0);
5488 }
5489 return (1);
5490}
5491
5492/**
5493 * @brief Writes a non-native endian binary string to an LZMA-compressed file.
5494 *
5495 * This function writes a binary string to the specified LZMA-compressed file pointer, handling
5496 * non-native endianness. It first writes the length of the string as a 32-bit integer with byte
5497 * order swapped. If the string is not to be skipped, it then writes the string data itself
5498 * followed by a null terminator. If the input string is NULL, an empty string is written instead.
5499 *
5500 * @param[in] string The string to write. If NULL, an empty string is written.
5501 * @param[in] lzmafp Pointer to the LZMAFILE where the string will be written.
5502 * @param[in] fBuffer Pointer to the SDDS_FILEBUFFER structure used for buffered writing.
5503 *
5504 * @return int32_t Returns 1 on successful writing of the string, or 0 if an error occurred.
5505 * @retval 1 The string was successfully written and byte-swapped.
5506 * @retval 0 An error occurred during the write operation, such as I/O failures or memory allocation issues.
5507 *
5508 * @note The caller is responsible for ensuring that the LZMAFILE pointer `lzmafp` is valid and open for writing.
5509 * This function does not perform memory allocation for the string; it assumes that the string
5510 * is already allocated and managed appropriately.
5511 */
5512int32_t SDDS_LZMAWriteNonNativeBinaryString(char *string, struct lzmafile *lzmafp, SDDS_FILEBUFFER *fBuffer) {
5513 int32_t length;
5514 static char *dummy_string = "";
5515 if (!string)
5516 string = dummy_string;
5517 length = strlen(string);
5518 SDDS_SwapLong(&length);
5519 if (!SDDS_LZMABufferedWrite(&length, sizeof(length), lzmafp, fBuffer)) {
5520 SDDS_SetError("Unable to write string--error writing length");
5521 return (0);
5522 }
5523 SDDS_SwapLong(&length);
5524 if (length && !SDDS_LZMABufferedWrite(string, sizeof(*string) * length, lzmafp, fBuffer)) {
5525 SDDS_SetError("Unable to write string--error writing contents");
5526 return (0);
5527 }
5528 return (1);
5529}
5530
5531#if defined(zLib)
5532/**
5533 * @brief Writes a non-native endian binary string to a GZIP-compressed file.
5534 *
5535 * This function writes a binary string to the specified GZIP-compressed file pointer, handling
5536 * non-native endianness. It first writes the length of the string as a 32-bit integer with byte
5537 * order swapped. If the string is not to be skipped, it then writes the string data itself
5538 * followed by a null terminator. If the input string is NULL, an empty string is written instead.
5539 *
5540 * @param[in] string The string to write. If NULL, an empty string is written.
5541 * @param[in] gzfp Pointer to the gzFile where the string will be written.
5542 * @param[in] fBuffer Pointer to the SDDS_FILEBUFFER structure used for buffered writing.
5543 *
5544 * @return int32_t Returns 1 on successful writing of the string, or 0 if an error occurred.
5545 * @retval 1 The string was successfully written and byte-swapped.
5546 * @retval 0 An error occurred during the write operation, such as I/O failures or memory allocation issues.
5547 *
5548 * @note The caller is responsible for ensuring that the gzFile pointer `gzfp` is valid and open for writing.
5549 * This function does not perform memory allocation for the string; it assumes that the string
5550 * is already allocated and managed appropriately.
5551 */
5552int32_t SDDS_GZipWriteNonNativeBinaryString(char *string, gzFile gzfp, SDDS_FILEBUFFER *fBuffer) {
5553 int32_t length;
5554 static char *dummy_string = "";
5555 if (!string)
5556 string = dummy_string;
5557 length = strlen(string);
5558 SDDS_SwapLong(&length);
5559 if (!SDDS_GZipBufferedWrite(&length, sizeof(length), gzfp, fBuffer)) {
5560 SDDS_SetError("Unable to write string--error writing length");
5561 return (0);
5562 }
5563 SDDS_SwapLong(&length);
5564 if (length && !SDDS_GZipBufferedWrite(string, sizeof(*string) * length, gzfp, fBuffer)) {
5565 SDDS_SetError("Unable to write string--error writing contents");
5566 return (0);
5567 }
5568 return (1);
5569}
5570#endif
5571
5572/**
5573 * @brief Updates a non-native endian binary page in an SDDS dataset.
5574 *
5575 * This function updates an existing binary page in the specified SDDS dataset, handling byte order
5576 * reversal to convert between little-endian and big-endian formats. It supports updating rows
5577 * based on the provided mode flags, such as flushing the table. The function ensures that the buffer
5578 * is flushed before performing the update and writes any new rows that have been flagged for writing.
5579 * It also handles fixed row counts and manages byte order conversions as necessary.
5580 *
5581 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to update.
5582 * @param[in] mode Bitmask indicating the update mode (e.g., FLUSH_TABLE).
5583 *
5584 * @return int32_t Returns 1 on successful update of the binary page, or 0 if an error occurred.
5585 * @retval 1 The binary page was successfully updated and byte-swapped.
5586 * @retval 0 An error occurred during the update operation, such as I/O failures, invalid row counts,
5587 * or corrupted dataset definitions.
5588 *
5589 * @note This function modifies the dataset's internal structures during the update process. Ensure that
5590 * the dataset is properly initialized and opened for writing before invoking this function.
5591 * After updating, the dataset's state is updated to reflect the changes made to the page.
5592 */
5593int32_t SDDS_UpdateNonNativeBinaryPage(SDDS_DATASET *SDDS_dataset, uint32_t mode) {
5594 FILE *fp;
5595 int32_t code, min32 = INT32_MIN, rows32;
5596 int64_t i, rows, offset, fixed_rows;
5597 SDDS_FILEBUFFER *fBuffer;
5598
5599 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_UpdateNonNativeBinaryPage"))
5600 return (0);
5601#if defined(zLib)
5602 if (SDDS_dataset->layout.gzipFile) {
5603 SDDS_SetError("Unable to perform page updates on a gzip file (SDDS_UpdateNonNativeBinaryPage)");
5604 return 0;
5605 }
5606#endif
5607 if (SDDS_dataset->layout.lzmaFile) {
5608 SDDS_SetError("Unable to perform page updates on .lzma or .xz files (SDDS_UpdateNonNativeBinaryPage)");
5609 return 0;
5610 }
5611 if (SDDS_dataset->layout.data_mode.column_major) {
5612 SDDS_SetError("Unable to perform page updates on a column major order file (SDDS_UpdateNonNativeBinaryPage)");
5613 return 0;
5614 }
5615 if (!SDDS_dataset->writing_page) {
5616#ifdef DEBUG
5617 fprintf(stderr, "Page not being written---calling SDDS_UpdateNonNativeBinaryPage\n");
5618#endif
5619 if (!(code = SDDS_WriteNonNativeBinaryPage(SDDS_dataset))) {
5620 return 0;
5621 }
5622 if (mode & FLUSH_TABLE) {
5623 SDDS_FreeTableStrings(SDDS_dataset);
5624 SDDS_dataset->first_row_in_mem = SDDS_CountRowsOfInterest(SDDS_dataset);
5625 SDDS_dataset->last_row_written = -1;
5626 SDDS_dataset->n_rows = 0;
5627 }
5628 return code;
5629 }
5630
5631 if (!(fp = SDDS_dataset->layout.fp)) {
5632 SDDS_SetError("Unable to update page--file pointer is NULL (SDDS_UpdateNonNativeBinaryPage)");
5633 return (0);
5634 }
5635 fBuffer = &SDDS_dataset->fBuffer;
5636 if (!SDDS_FlushBuffer(fp, fBuffer)) {
5637 SDDS_SetError("Unable to write page--buffer flushing problem (SDDS_UpdateNonNativeBinaryPage)");
5638 return 0;
5639 }
5640 offset = ftell(fp);
5641
5642 rows = SDDS_CountRowsOfInterest(SDDS_dataset) + SDDS_dataset->first_row_in_mem;
5643#ifdef DEBUG
5644 fprintf(stderr, "%" PRId64 " rows stored in table, %" PRId32 " already written\n", rows, SDDS_dataset->n_rows_written);
5645#endif
5646 if (rows == SDDS_dataset->n_rows_written) {
5647 return (1);
5648 }
5649 if (rows < SDDS_dataset->n_rows_written) {
5650 SDDS_SetError("Unable to update page--new number of rows less than previous number (SDDS_UpdateNonNativeBinaryPage)");
5651 return (0);
5652 }
5653 SDDS_SwapLong(&min32);
5654 if ((!SDDS_dataset->layout.data_mode.fixed_row_count) || (((rows + rows - SDDS_dataset->n_rows_written / SDDS_dataset->layout.data_mode.fixed_row_increment)) != (rows / SDDS_dataset->layout.data_mode.fixed_row_increment))) {
5655 if (SDDS_fseek(fp, SDDS_dataset->rowcount_offset, 0) == -1) {
5656 SDDS_SetError("Unable to update page--failure doing fseek (SDDS_UpdateNonNativeBinaryPage)");
5657 return (0);
5658 }
5659 if (SDDS_dataset->layout.data_mode.fixed_row_count) {
5660 if ((rows - SDDS_dataset->n_rows_written) + 1 > SDDS_dataset->layout.data_mode.fixed_row_increment) {
5661 SDDS_dataset->layout.data_mode.fixed_row_increment = (rows - SDDS_dataset->n_rows_written) + 1;
5662 }
5663 fixed_rows = ((rows / SDDS_dataset->layout.data_mode.fixed_row_increment) + 2) * SDDS_dataset->layout.data_mode.fixed_row_increment;
5664#if defined(DEBUG)
5665 fprintf(stderr, "Setting %" PRId64 " fixed rows\n", fixed_rows);
5666#endif
5667 if ((fixed_rows > INT32_MAX) && (SDDS_dataset->n_rows_written <= INT32_MAX)) {
5668 SDDS_SetError("Unable to update page--crossed the INT32_MAX row boundary (SDDS_UpdateNonNativeBinaryPage)");
5669 return (0);
5670 }
5671 if (fixed_rows > INT32_MAX) {
5672 if (fwrite(&min32, sizeof(min32), 1, fp) != 1) {
5673 SDDS_SetError("Unable to update page--failure writing number of rows (SDDS_UpdateBinaryPage)");
5674 return (0);
5675 }
5676 SDDS_SwapLong64(&fixed_rows);
5677 if (fwrite(&fixed_rows, sizeof(fixed_rows), 1, fp) != 1) {
5678 SDDS_SetError("Unable to update page--failure writing number of rows (SDDS_UpdateNonNativeBinaryPage)");
5679 return (0);
5680 }
5681 SDDS_SwapLong64(&fixed_rows);
5682 } else {
5683 rows32 = (int32_t)fixed_rows;
5684 SDDS_SwapLong(&rows32);
5685 if (fwrite(&rows32, sizeof(rows32), 1, fp) != 1) {
5686 SDDS_SetError("Unable to update page--failure writing number of rows (SDDS_UpdateNonNativeBinaryPage)");
5687 return (0);
5688 }
5689 }
5690 } else {
5691#if defined(DEBUG)
5692 fprintf(stderr, "Setting %" PRId64 " rows\n", rows);
5693#endif
5694 if ((rows > INT32_MAX) && (SDDS_dataset->n_rows_written <= INT32_MAX)) {
5695 SDDS_SetError("Unable to update page--crossed the INT32_MAX row boundary (SDDS_UpdateNonNativeBinaryPage)");
5696 return (0);
5697 }
5698 if (rows > INT32_MAX) {
5699 if (fwrite(&min32, sizeof(min32), 1, fp) != 1) {
5700 SDDS_SetError("Unable to update page--failure writing number of rows (SDDS_UpdateBinaryPage)");
5701 return (0);
5702 }
5703 SDDS_SwapLong64(&rows);
5704 if (fwrite(&rows, sizeof(rows), 1, fp) != 1) {
5705 SDDS_SetError("Unable to update page--failure writing number of rows (SDDS_UpdateNonNativeBinaryPage)");
5706 return (0);
5707 }
5708 SDDS_SwapLong64(&rows);
5709 } else {
5710 rows32 = (int32_t)rows;
5711 SDDS_SwapLong(&rows32);
5712 if (fwrite(&rows32, sizeof(rows32), 1, fp) != 1) {
5713 SDDS_SetError("Unable to update page--failure writing number of rows (SDDS_UpdateNonNativeBinaryPage)");
5714 return (0);
5715 }
5716 }
5717 }
5718 if (SDDS_fseek(fp, offset, 0) == -1) {
5719 SDDS_SetError("Unable to update page--failure doing fseek to end of page (SDDS_UpdateNonNativeBinaryPage)");
5720 return (0);
5721 }
5722 }
5723 SDDS_SwapEndsColumnData(SDDS_dataset);
5724 for (i = SDDS_dataset->last_row_written + 1; i < SDDS_dataset->n_rows; i++) {
5725 if (SDDS_dataset->row_flag[i] && !SDDS_WriteNonNativeBinaryRow(SDDS_dataset, i)) {
5726 SDDS_SetError("Unable to update page--failure writing row (SDDS_UpdateNonNativeBinaryPage)");
5727 return (0);
5728 }
5729 }
5730 SDDS_SwapEndsColumnData(SDDS_dataset);
5731#ifdef DEBUG
5732 fprintf(stderr, "Flushing buffer\n");
5733#endif
5734 if (!SDDS_FlushBuffer(fp, fBuffer)) {
5735 SDDS_SetError("Unable to write page--buffer flushing problem (SDDS_UpdateNonNativeBinaryPage)");
5736 return 0;
5737 }
5738 SDDS_dataset->last_row_written = SDDS_dataset->n_rows - 1;
5739 SDDS_dataset->n_rows_written = rows;
5740 if (mode & FLUSH_TABLE) {
5741 SDDS_FreeTableStrings(SDDS_dataset);
5742 SDDS_dataset->first_row_in_mem = rows;
5743 SDDS_dataset->last_row_written = -1;
5744 SDDS_dataset->n_rows = 0;
5745 }
5746 return (1);
5747}
5748
5749/**
5750 * @brief Converts a 16-byte array representing a float80 value to a double.
5751 *
5752 * This function converts a 16-byte array, which represents an 80-bit floating-point (float80) value,
5753 * to a standard double-precision (64-bit) floating-point value. The conversion handles different
5754 * byte orders, supporting both big-endian and little-endian formats. On systems where `long double`
5755 * is implemented as 64-bit (such as Windows and Mac), this function allows reading SDDS_LONGDOUBLE
5756 * SDDS files with a loss of precision by translating float80 values to double.
5757 *
5758 * @param[in] x The 16-byte array representing the float80 value.
5759 * @param[in] byteOrder The byte order of the array, either `SDDS_BIGENDIAN_SEEN` or `SDDS_LITTLEENDIAN_SEEN`.
5760 *
5761 * @return double The converted double-precision floating-point value.
5762 *
5763 * @note This function assumes that the input array `x` is correctly formatted as an 80-bit floating-point
5764 * value. On systems where `long double` is 80 bits, the conversion preserves as much precision as
5765 * possible within the limitations of the double-precision format. On systems with 64-bit `long double`,
5766 * the function translates the value with inherent precision loss.
5767 */
5768double makeFloat64FromFloat80(unsigned char x[16], int32_t byteOrder) {
5769 int exponent;
5770 uint64_t mantissa;
5771 unsigned char d[8] = {0};
5772 double result;
5773
5774 if (byteOrder == SDDS_BIGENDIAN_SEEN) {
5775 /* conversion is done in little endian */
5776 char xx;
5777 int i;
5778 for (i = 0; i < 6; i++) {
5779 xx = x[0 + i];
5780 x[0 + i] = x[11 - i];
5781 x[11 - i] = xx;
5782 }
5783 }
5784
5785 exponent = (((x[9] << 8) | x[8]) & 0x7FFF);
5786 mantissa =
5787 ((uint64_t)x[7] << 56) | ((uint64_t)x[6] << 48) | ((uint64_t)x[5] << 40) | ((uint64_t)x[4] << 32) |
5788 ((uint64_t)x[3] << 24) | ((uint64_t)x[2] << 16) | ((uint64_t)x[1] << 8) | (uint64_t)x[0];
5789
5790 d[7] = x[9] & 0x80; /* Set sign. */
5791
5792 if ((exponent == 0x7FFF) || (exponent == 0)) {
5793 /* Infinite, NaN or denormal */
5794 if (exponent == 0x7FFF) {
5795 /* Infinite or NaN */
5796 d[7] |= 0x7F;
5797 d[6] = 0xF0;
5798 } else {
5799 /* Otherwise it's denormal. It cannot be represented as double. Translate as singed zero. */
5800 memcpy(&result, d, 8);
5801 return result;
5802 }
5803 } else {
5804 /* Normal number. */
5805 exponent = exponent - 0x3FFF + 0x03FF; /*< exponent for double precision. */
5806
5807 if (exponent <= -52) /*< Too small to represent. Translate as (signed) zero. */
5808 {
5809 memcpy(&result, d, 8);
5810 return result;
5811 } else if (exponent < 0) {
5812 /* Denormal, exponent bits are already zero here. */
5813 } else if (exponent >= 0x7FF) /*< Too large to represent. Translate as infinite. */
5814 {
5815 d[7] |= 0x7F;
5816 d[6] = 0xF0;
5817 memset(d, 0x00, 6);
5818 memcpy(&result, d, 8);
5819 return result;
5820 } else {
5821 /* Representable number */
5822 d[7] |= (exponent & 0x7F0) >> 4;
5823 d[6] |= (exponent & 0xF) << 4;
5824 }
5825 }
5826 /* Translate mantissa. */
5827
5828 mantissa >>= 11;
5829
5830 if (exponent < 0) {
5831 /* Denormal, further shifting is required here. */
5832 mantissa >>= (-exponent + 1);
5833 }
5834
5835 d[0] = mantissa & 0xFF;
5836 d[1] = (mantissa >> 8) & 0xFF;
5837 d[2] = (mantissa >> 16) & 0xFF;
5838 d[3] = (mantissa >> 24) & 0xFF;
5839 d[4] = (mantissa >> 32) & 0xFF;
5840 d[5] = (mantissa >> 40) & 0xFF;
5841 d[6] |= (mantissa >> 48) & 0x0F;
5842
5843 memcpy(&result, d, 8);
5844
5845 if (byteOrder == SDDS_BIGENDIAN_SEEN) {
5846 /* convert back to big endian */
5847 SDDS_SwapDouble(&result);
5848 }
5849
5850 return result;
5851}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_ReadAsciiPageLastRows(SDDS_DATASET *SDDS_dataset, int64_t last_rows)
Reads the last specified number of rows from an ASCII page of an SDDS dataset.
int32_t SDDS_ScanData(char *string, int32_t type, int32_t field_length, void *data, int64_t index, int32_t is_parameter)
Scans a string and saves the parsed value into a data pointer according to the specified data type.
int32_t SDDS_ReadAsciiPage(SDDS_DATASET *SDDS_dataset, int64_t sparse_interval, int64_t sparse_offset, int32_t sparse_statistics)
Reads the next SDDS ASCII page into memory with optional data sparsity and statistics.
void SDDS_SwapLongDouble(long double *data)
Swaps the endianness of a long double.
int32_t SDDS_SwapEndsColumnData(SDDS_DATASET *SDDSin)
Swaps the endianness of the column data in an SDDS dataset.
int32_t SDDS_ReadNewBinaryRows(SDDS_DATASET *SDDS_dataset)
Reads new binary rows from the SDDS dataset.
int32_t SDDS_ReadNonNativeBinaryPage(SDDS_DATASET *SDDS_dataset, int64_t sparse_interval, int64_t sparse_offset)
Reads a non-native endian binary page from an SDDS dataset.
char * SDDS_ReadNonNativeLZMABinaryString(struct lzmafile *lzmafp, SDDS_FILEBUFFER *fBuffer, int32_t skip)
Reads a non-native endian binary string from an LZMA-compressed file.
int32_t SDDS_SetDefaultIOBufferSize(int32_t newValue)
Definition SDDS_binary.c:66
int32_t SDDS_WriteNonNativeBinaryPage(SDDS_DATASET *SDDS_dataset)
Writes a non-native endian binary page to an SDDS dataset.
int32_t SDDS_WriteNonNativeBinaryRow(SDDS_DATASET *SDDS_dataset, int64_t row)
Writes a non-native endian binary row to an SDDS dataset.
int32_t SDDS_ReadNonNativeBinaryPageDetailed(SDDS_DATASET *SDDS_dataset, int64_t sparse_interval, int64_t sparse_offset, int64_t last_rows)
Reads a detailed non-native endian binary page from an SDDS dataset.
void SDDS_SwapLong64(int64_t *data)
Swaps the endianness of a 64-bit integer.
int32_t SDDS_ReadNonNativePage(SDDS_DATASET *SDDS_dataset)
Reads a non-native endian page from an SDDS dataset.
int32_t SDDS_UpdateNonNativeBinaryPage(SDDS_DATASET *SDDS_dataset, uint32_t mode)
Updates a non-native endian binary page in an SDDS dataset.
int32_t SDDS_WriteBinaryColumns(SDDS_DATASET *SDDS_dataset)
Writes the binary columns of an SDDS dataset to the associated file.
int32_t SDDS_LZMABufferedRead(void *target, int64_t targetSize, struct lzmafile *lzmafp, SDDS_FILEBUFFER *fBuffer, int32_t type, int32_t byteOrder)
int32_t SDDS_WriteBinaryRow(SDDS_DATASET *SDDS_dataset, int64_t row)
Writes a single binary row of an SDDS dataset to the associated file.
int32_t SDDS_WriteBinaryArrays(SDDS_DATASET *SDDS_dataset)
Writes the binary arrays of the SDDS dataset to a file.
int32_t SDDS_ReadBinaryRow(SDDS_DATASET *SDDS_dataset, int64_t row, int32_t skip)
Reads a binary row from the specified SDDS dataset.
int32_t SDDS_WriteNonNativeBinaryString(char *string, FILE *fp, SDDS_FILEBUFFER *fBuffer)
Writes a non-native endian binary string to a file.
int32_t SDDS_WriteNonNativeBinaryArrays(SDDS_DATASET *SDDS_dataset)
Writes non-native endian binary arrays to an SDDS dataset.
void SDDS_SwapULong64(uint64_t *data)
Swaps the endianness of a 64-bit unsigned integer.
int32_t SDDS_ReadNonNativeBinaryPageLastRows(SDDS_DATASET *SDDS_dataset, int64_t last_rows)
Reads the last few rows from a non-native endian binary page in an SDDS dataset.
char * SDDS_ReadBinaryString(FILE *fp, SDDS_FILEBUFFER *fBuffer, int32_t skip)
Reads a binary string from a file with buffering.
int32_t SDDS_BufferedWrite(void *target, int64_t targetSize, FILE *fp, SDDS_FILEBUFFER *fBuffer)
void SDDS_SwapULong(uint32_t *data)
Swaps the endianness of a 32-bit unsigned integer.
int32_t SDDS_LZMAWriteBinaryString(char *string, struct lzmafile *lzmafp, SDDS_FILEBUFFER *fBuffer)
Writes a binary string to a file with LZMA compression.
int32_t SDDS_WriteBinaryString(char *string, FILE *fp, SDDS_FILEBUFFER *fBuffer)
Writes a binary string to a file with buffering.
void SDDS_SwapUShort(unsigned short *data)
Swaps the endianness of an unsigned short integer.
int32_t SDDS_ReadNonNativePageSparse(SDDS_DATASET *SDDS_dataset, uint32_t mode, int64_t sparse_interval, int64_t sparse_offset)
Reads a sparse non-native endian page from an SDDS dataset.
int32_t SDDS_ReadBinaryPageDetailed(SDDS_DATASET *SDDS_dataset, int64_t sparse_interval, int64_t sparse_offset, int64_t last_rows, int32_t sparse_statistics)
Reads a binary page from an SDDS dataset with detailed options.
int32_t SDDS_BufferedRead(void *target, int64_t targetSize, FILE *fp, SDDS_FILEBUFFER *fBuffer, int32_t type, int32_t byteOrder)
Definition SDDS_binary.c:96
int32_t SDDS_UpdateBinaryPage(SDDS_DATASET *SDDS_dataset, uint32_t mode)
Updates the binary page of an SDDS dataset.
int32_t SDDS_ReadNonNativeBinaryColumns(SDDS_DATASET *SDDS_dataset)
Reads the non-native endian binary columns from an SDDS dataset.
void SDDS_SetReadRecoveryMode(SDDS_DATASET *SDDS_dataset, int32_t mode)
Sets the read recovery mode for an SDDS dataset.
int32_t SDDS_ReadRecoveryPossible(SDDS_DATASET *SDDS_dataset)
Checks if any data in an SDDS page was recovered after an error was detected.
double makeFloat64FromFloat80(unsigned char x[16], int32_t byteOrder)
Converts a 16-byte array representing a float80 value to a double.
int32_t SDDS_FlushBuffer(FILE *fp, SDDS_FILEBUFFER *fBuffer)
int32_t SDDS_ReadNonNativeBinaryRow(SDDS_DATASET *SDDS_dataset, int64_t row, int32_t skip)
Reads a non-native endian binary row from an SDDS dataset.
int32_t SDDS_WriteBinaryParameters(SDDS_DATASET *SDDS_dataset)
Writes the binary parameters of the SDDS dataset.
int32_t SDDS_SwapEndsArrayData(SDDS_DATASET *SDDSin)
Swaps the endianness of the array data in an SDDS dataset.
int32_t SDDS_ReadNonNativePageLastRows(SDDS_DATASET *SDDS_dataset, int64_t last_rows)
Reads the last few rows from a non-native endian page in an SDDS dataset.
int32_t SDDS_ReadBinaryPage(SDDS_DATASET *SDDS_dataset, int64_t sparse_interval, int64_t sparse_offset, int32_t sparse_statistics)
Reads a binary page from an SDDS dataset.
int32_t SDDS_SwapEndsParameterData(SDDS_DATASET *SDDSin)
Swaps the endianness of the parameter data in an SDDS dataset.
int32_t SDDS_ReadNonNativeBinaryParameters(SDDS_DATASET *SDDS_dataset)
Reads non-native endian binary parameters from an SDDS dataset.
int32_t SDDS_ReadBinaryColumns(SDDS_DATASET *SDDS_dataset)
Reads the binary columns from an SDDS dataset.
void SDDS_SwapLong(int32_t *data)
Swaps the endianness of a 32-bit integer.
int32_t SDDS_ReadNonNativeBinaryArrays(SDDS_DATASET *SDDS_dataset)
Reads non-native endian binary arrays from an SDDS dataset.
void SDDS_SwapDouble(double *data)
Swaps the endianness of a double.
int32_t SDDS_WriteBinaryPage(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_fseek(FILE *fp, int64_t offset, int32_t dir)
Sets the file position indicator for a given file stream with retry logic.
int32_t SDDS_WriteNonNativeBinaryColumns(SDDS_DATASET *SDDS_dataset)
Writes non-native endian binary columns of an SDDS dataset to the associated file.
int32_t SDDS_WriteNonNativeBinaryParameters(SDDS_DATASET *SDDS_dataset)
Writes non-native endian binary parameters to an SDDS dataset.
void SDDS_SwapShort(short *data)
Swaps the endianness of a short integer.
int32_t SDDS_lzmaseek(struct lzmafile *lzmafp, int64_t offset, int32_t dir)
Sets the file position indicator for a given LZMA file stream with retry logic.
char * SDDS_ReadNonNativeBinaryString(FILE *fp, SDDS_FILEBUFFER *fBuffer, int32_t skip)
Reads a non-native endian binary string from a file.
int32_t SDDS_ReadNonNativePageDetailed(SDDS_DATASET *SDDS_dataset, uint32_t mode, int64_t sparse_interval, int64_t sparse_offset, int64_t last_rows)
Reads a detailed non-native endian page from an SDDS dataset.
int32_t SDDS_LZMAFlushBuffer(struct lzmafile *lzmafp, SDDS_FILEBUFFER *fBuffer)
void SDDS_SwapFloat(float *data)
Swaps the endianness of a float.
int32_t SDDS_ReadBinaryArrays(SDDS_DATASET *SDDS_dataset)
Reads binary arrays from an SDDS dataset.
int32_t SDDS_LZMABufferedWrite(void *target, int64_t targetSize, struct lzmafile *lzmafp, SDDS_FILEBUFFER *fBuffer)
int32_t SDDS_LZMAWriteNonNativeBinaryString(char *string, struct lzmafile *lzmafp, SDDS_FILEBUFFER *fBuffer)
Writes a non-native endian binary string to an LZMA-compressed file.
int32_t SDDS_ReadBinaryPageLastRows(SDDS_DATASET *SDDS_dataset, int64_t last_rows)
Reads the last specified number of rows from a binary page of an SDDS dataset.
char * SDDS_ReadLZMABinaryString(struct lzmafile *lzmafp, SDDS_FILEBUFFER *fBuffer, int32_t skip)
Reads a binary string from an LZMA-compressed file with buffering.
int32_t SDDS_ReadBinaryParameters(SDDS_DATASET *SDDS_dataset)
Reads binary parameters from the specified SDDS dataset.
int32_t SDDS_type_size[SDDS_NUM_TYPES]
Array of sizes for each supported data type.
Definition SDDS_data.c:62
int32_t SDDS_LengthenTable(SDDS_DATASET *SDDS_dataset, int64_t n_additional_rows)
int32_t SDDS_StartPage(SDDS_DATASET *SDDS_dataset, int64_t expected_n_rows)
int64_t SDDS_CountRowsOfInterest(SDDS_DATASET *SDDS_dataset)
Counts the number of rows marked as "of interest" in the current data table.
int64_t SDDS_GetRowLimit()
void SDDS_FreeTableStrings(SDDS_DATASET *SDDS_dataset)
Internal definitions and function declarations for SDDS with LZMA support.
void SDDS_SetError(char *error_text)
Records an error message in the SDDS error stack.
Definition SDDS_utils.c:379
int32_t SDDS_FreeArrayDefinition(ARRAY_DEFINITION *source)
Frees memory allocated for an array definition.
int32_t SDDS_CheckDataset(SDDS_DATASET *SDDS_dataset, const char *caller)
Validates the SDDS dataset pointer.
Definition SDDS_utils.c:552
void * SDDS_Malloc(size_t size)
Allocates memory of a specified size.
Definition SDDS_utils.c:639
void SDDS_ClearErrors()
Clears all recorded error messages from the SDDS error stack.
Definition SDDS_utils.c:318
ARRAY_DEFINITION * SDDS_CopyArrayDefinition(ARRAY_DEFINITION **target, ARRAY_DEFINITION *source)
Creates a copy of an array definition.
int32_t SDDS_IsBigEndianMachine()
Determines whether the current machine uses big-endian byte ordering.
void * SDDS_Realloc(void *old_ptr, size_t new_size)
Reallocates memory to a new size.
Definition SDDS_utils.c:677
#define SDDS_ULONG
Identifier for the unsigned 32-bit integer data type.
Definition SDDStypes.h:67
#define SDDS_FLOAT
Identifier for the float data type.
Definition SDDStypes.h:43
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
#define SDDS_ULONG64
Identifier for the unsigned 64-bit integer data type.
Definition SDDStypes.h:55
#define SDDS_FLOATING_TYPE(type)
Checks if the given type identifier corresponds to a floating-point type.
Definition SDDStypes.h:124
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
Definition SDDStypes.h:61
#define SDDS_SHORT
Identifier for the signed short integer data type.
Definition SDDStypes.h:73
#define SDDS_USHORT
Identifier for the unsigned short integer data type.
Definition SDDStypes.h:79
#define SDDS_DOUBLE
Identifier for the double data type.
Definition SDDStypes.h:37
#define SDDS_LONGDOUBLE
Identifier for the long double data type.
Definition SDDStypes.h:31
#define SDDS_LONG64
Identifier for the signed 64-bit integer data type.
Definition SDDStypes.h:49