SDDS ToolKit Programs and Libraries for C and Python
All Classes Files Functions Variables Macros Pages
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 && sparse_statistics != 0) {
2337 SDDS_SetError("sparse_statistics is not yet supported for column-major layout. Use sddsconvert -majorOrder=row to convert first.\n");
2338 return (0);
2339 }
2340
2341 if (last_rows) {
2342 sparse_interval = 1;
2343 sparse_offset = n_rows - last_rows;
2344 }
2345 if (sparse_interval <= 0)
2346 sparse_interval = 1;
2347 if (sparse_offset < 0)
2348 sparse_offset = 0;
2349
2350 rows_to_store = (n_rows - sparse_offset) / sparse_interval + 2;
2351 alloc_rows = rows_to_store - SDDS_dataset->n_rows_allocated;
2352
2353 if (!SDDS_StartPage(SDDS_dataset, 0) || !SDDS_LengthenTable(SDDS_dataset, alloc_rows)) {
2354 SDDS_SetError("Unable to read page--couldn't start page (SDDS_ReadBinaryPageDetailed)");
2355 return (0);
2356 }
2357
2358 /* read the parameter values */
2359 if (!SDDS_ReadBinaryParameters(SDDS_dataset)) {
2360 SDDS_SetError("Unable to read page--parameter reading error (SDDS_ReadBinaryPageDetailed)");
2361 return (0);
2362 }
2363
2364 /* read the array values */
2365 if (!SDDS_ReadBinaryArrays(SDDS_dataset)) {
2366 SDDS_SetError("Unable to read page--array reading error (SDDS_ReadBinaryPageDetailed)");
2367 return (0);
2368 }
2369 if (SDDS_dataset->layout.data_mode.column_major) {
2370 SDDS_dataset->n_rows = n_rows;
2371 if (!SDDS_ReadBinaryColumns(SDDS_dataset, sparse_interval, sparse_offset)) {
2372 SDDS_SetError("Unable to read page--column reading error (SDDS_ReadBinaryPageDetailed)");
2373 return (0);
2374 }
2375 return (SDDS_dataset->page_number);
2376 }
2377 if ((sparse_interval <= 1) && (sparse_offset == 0)) {
2378 for (j = 0; j < n_rows; j++) {
2379 if (!SDDS_ReadBinaryRow(SDDS_dataset, j, 0)) {
2380 SDDS_dataset->n_rows = j;
2381 if (SDDS_dataset->autoRecover) {
2382#if defined(DEBUG)
2383 fprintf(stderr, "Doing auto-read recovery\n");
2384#endif
2385 SDDS_dataset->autoRecovered = 1;
2387 return (SDDS_dataset->page_number);
2388 }
2389 SDDS_SetError("Unable to read page--error reading data row (SDDS_ReadBinaryPageDetailed)");
2390 SDDS_SetReadRecoveryMode(SDDS_dataset, 1);
2391 return (0);
2392 }
2393 }
2394 SDDS_dataset->n_rows = j;
2395 return (SDDS_dataset->page_number);
2396 } else {
2397 for (j = 0; j < sparse_offset; j++) {
2398 if (!SDDS_ReadBinaryRow(SDDS_dataset, 0, 1)) {
2399 SDDS_dataset->n_rows = 0;
2400 if (SDDS_dataset->autoRecover) {
2401 SDDS_dataset->autoRecovered = 1;
2403 return (SDDS_dataset->page_number);
2404 }
2405 SDDS_SetError("Unable to read page--error reading data row (SDDS_ReadBinaryPageDetailed)");
2406 SDDS_SetReadRecoveryMode(SDDS_dataset, 1);
2407 return (0);
2408 }
2409 }
2410 n_rows -= sparse_offset;
2411 if (sparse_statistics != 0) {
2412 // Allocate buffer space for statistical sparsing
2413 statData = (void**)malloc(SDDS_dataset->layout.n_columns * sizeof(void*));
2414 for (i = 0; i < SDDS_dataset->layout.n_columns; i++) {
2415 if (SDDS_FLOATING_TYPE(SDDS_dataset->layout.column_definition[i].type)) {
2416 // Not ideal for SDDS_LONGDOUBLE but we may never run across this error
2417 statData[i] = (double*)calloc(sparse_interval, sizeof(double));
2418 }
2419 }
2420 for (j = k = 0; j < n_rows; j++) {
2421 if (!SDDS_ReadBinaryRow(SDDS_dataset, k, 0)) {
2422 SDDS_dataset->n_rows = k;
2423 if (SDDS_dataset->autoRecover) {
2424 SDDS_dataset->autoRecovered = 1;
2426 return (SDDS_dataset->page_number);
2427 }
2428 SDDS_SetError("Unable to read page--error reading data row (SDDS_ReadBinaryPageDetailed)");
2429 SDDS_SetReadRecoveryMode(SDDS_dataset, 1);
2430 return (0);
2431 }
2432 for (i = 0; i < SDDS_dataset->layout.n_columns; i++) {
2433 switch (SDDS_dataset->layout.column_definition[i].type) {
2434 case SDDS_FLOAT:
2435 ((double*)statData[i])[j % sparse_interval] = (double)(((float*)SDDS_dataset->data[i])[k]);
2436 break;
2437 case SDDS_DOUBLE:
2438 ((double*)statData[i])[j % sparse_interval] = ((double*)SDDS_dataset->data[i])[k];
2439 break;
2440 case SDDS_LONGDOUBLE:
2441 ((double*)statData[i])[j % sparse_interval] = (double)(((long double*)SDDS_dataset->data[i])[k]);
2442 break;
2443 }
2444 if (SDDS_FLOATING_TYPE(SDDS_dataset->layout.column_definition[i].type)) {
2445 if (sparse_statistics == 1) {
2446 // Sparse and get average statistics
2447 compute_average(&statResult, (double*)statData[i], (j % sparse_interval) + 1);
2448 } else if (sparse_statistics == 2) {
2449 // Sparse and get median statistics
2450 compute_median(&statResult, (double*)statData[i], (j % sparse_interval) + 1);
2451 } else if (sparse_statistics == 3) {
2452 // Sparse and get minimum statistics
2453 statResult = min_in_array((double*)statData[i], (j % sparse_interval) + 1);
2454 } else if (sparse_statistics == 4) {
2455 // Sparse and get maximum statistics
2456 statResult = max_in_array((double*)statData[i], (j % sparse_interval) + 1);
2457 }
2458 }
2459 switch (SDDS_dataset->layout.column_definition[i].type) {
2460 case SDDS_FLOAT:
2461 ((float*)SDDS_dataset->data[i])[k] = statResult;
2462 break;
2463 case SDDS_DOUBLE:
2464 ((double*)SDDS_dataset->data[i])[k] = statResult;
2465 break;
2466 case SDDS_LONGDOUBLE:
2467 ((long double*)SDDS_dataset->data[i])[k] = statResult;
2468 break;
2469 }
2470 }
2471 if (j % sparse_interval == sparse_interval - 1) {
2472 k++;
2473 }
2474 }
2475 for (i = 0; i < SDDS_dataset->layout.n_columns; i++) {
2476 if (SDDS_FLOATING_TYPE(SDDS_dataset->layout.column_definition[i].type)) {
2477 free(statData[i]);
2478 }
2479 }
2480 free(statData);
2481 } else {
2482 for (j = k = 0; j < n_rows; j++) {
2483 if (!SDDS_ReadBinaryRow(SDDS_dataset, k, mod = j % sparse_interval)) {
2484 SDDS_dataset->n_rows = k;
2485 if (SDDS_dataset->autoRecover) {
2486 SDDS_dataset->autoRecovered = 1;
2488 return (SDDS_dataset->page_number);
2489 }
2490 SDDS_SetError("Unable to read page--error reading data row (SDDS_ReadBinaryPageDetailed)");
2491 SDDS_SetReadRecoveryMode(SDDS_dataset, 1);
2492 return (0);
2493 }
2494 k += mod ? 0 : 1;
2495 }
2496 }
2497 SDDS_dataset->n_rows = k;
2498 return (SDDS_dataset->page_number);
2499 }
2500}
2501
2502/**
2503 * @brief Writes a binary string to a file with buffering.
2504 *
2505 * This function writes a binary string to the specified file by first writing the length of the string
2506 * followed by the string's content to ensure proper binary formatting. If the input string is NULL,
2507 * an empty string is written instead. The writing operation utilizes a buffered approach to enhance performance.
2508 *
2509 * @param[in] string The null-terminated string to be written. If NULL, an empty string is written.
2510 * @param[in] fp The file pointer to write to. Must be an open file in binary write mode.
2511 * @param[in,out] fBuffer Pointer to the file buffer used for buffered writing operations.
2512 *
2513 * @return int32_t Returns 1 on success, 0 on failure.
2514 * @retval 1 Operation was successful.
2515 * @retval 0 An error occurred during writing.
2516 */
2517int32_t SDDS_WriteBinaryString(char *string, FILE *fp, SDDS_FILEBUFFER *fBuffer) {
2518 int32_t length;
2519 static char *dummy_string = "";
2520 if (!string)
2521 string = dummy_string;
2522 length = strlen(string);
2523 if (!SDDS_BufferedWrite(&length, sizeof(length), fp, fBuffer)) {
2524 SDDS_SetError("Unable to write string--error writing length");
2525 return (0);
2526 }
2527 if (length && !SDDS_BufferedWrite(string, sizeof(*string) * length, fp, fBuffer)) {
2528 SDDS_SetError("Unable to write string--error writing contents");
2529 return (0);
2530 }
2531 return (1);
2532}
2533
2534/**
2535 * @brief Writes a binary string to a file with LZMA compression.
2536 *
2537 * This function writes a binary string to the specified LZMA-compressed file by first writing the length
2538 * of the string followed by the string's content. If the input string is NULL, an empty string is written instead.
2539 * The writing operation utilizes LZMA buffered write functions to ensure data is compressed appropriately.
2540 *
2541 * @param[in] string The null-terminated string to be written. If NULL, an empty string is written.
2542 * @param[in] lzmafp The LZMA file pointer to write to. Must be a valid, open LZMA-compressed file in write mode.
2543 * @param[in,out] fBuffer Pointer to the file buffer used for buffered writing operations.
2544 *
2545 * @return int32_t Returns 1 on success, 0 on failure.
2546 * @retval 1 Operation was successful.
2547 * @retval 0 An error occurred during writing.
2548 */
2549int32_t SDDS_LZMAWriteBinaryString(char *string, struct lzmafile *lzmafp, SDDS_FILEBUFFER *fBuffer) {
2550 int32_t length;
2551 static char *dummy_string = "";
2552 if (!string)
2553 string = dummy_string;
2554 length = strlen(string);
2555 if (!SDDS_LZMABufferedWrite(&length, sizeof(length), lzmafp, fBuffer)) {
2556 SDDS_SetError("Unable to write string--error writing length");
2557 return (0);
2558 }
2559 if (length && !SDDS_LZMABufferedWrite(string, sizeof(*string) * length, lzmafp, fBuffer)) {
2560 SDDS_SetError("Unable to write string--error writing contents");
2561 return (0);
2562 }
2563 return (1);
2564}
2565
2566#if defined(zLib)
2567/**
2568 * @brief Writes a binary string to a GZIP-compressed file with buffering.
2569 *
2570 * This function writes a binary string to the specified GZIP-compressed file by first writing the length
2571 * of the string followed by the string's content. If the input string is NULL, an empty string is written instead.
2572 * The writing operation uses GZIP buffered write functions to compress the data.
2573 *
2574 * @param[in] string The null-terminated string to be written. If NULL, an empty string is written.
2575 * @param[in] gzfp The GZIP file pointer to write to. Must be a valid, open GZIP-compressed file in write mode.
2576 * @param[in,out] fBuffer Pointer to the file buffer used for buffered writing operations.
2577 *
2578 * @return int32_t Returns 1 on success, 0 on failure.
2579 * @retval 1 Operation was successful.
2580 * @retval 0 An error occurred during writing.
2581 */
2582int32_t SDDS_GZipWriteBinaryString(char *string, gzFile gzfp, SDDS_FILEBUFFER *fBuffer) {
2583 int32_t length;
2584 static char *dummy_string = "";
2585 if (!string)
2586 string = dummy_string;
2587 length = strlen(string);
2588 if (!SDDS_GZipBufferedWrite(&length, sizeof(length), gzfp, fBuffer)) {
2589 SDDS_SetError("Unable to write string--error writing length");
2590 return (0);
2591 }
2592 if (length && !SDDS_GZipBufferedWrite(string, sizeof(*string) * length, gzfp, fBuffer)) {
2593 SDDS_SetError("Unable to write string--error writing contents");
2594 return (0);
2595 }
2596 return (1);
2597}
2598#endif
2599
2600/**
2601 * @brief Reads a binary string from a file with buffering.
2602 *
2603 * This function reads a binary string from the specified file by first reading the length of the string
2604 * and then reading the string content based on the length. If the 'skip' parameter is set, the string data
2605 * is skipped over instead of being stored. The function allocates memory for the string, which should be
2606 * freed by the caller when no longer needed.
2607 *
2608 * @param[in] fp The file pointer to read from. Must be an open file in binary read mode.
2609 * @param[in,out] fBuffer Pointer to the file buffer used for buffered reading operations.
2610 * @param[in] skip If non-zero, the string data is skipped without being stored.
2611 *
2612 * @return char* Returns a pointer to the read null-terminated string on success, or NULL if an error occurred.
2613 * @retval NULL An error occurred during reading or memory allocation.
2614 * @retval Non-NULL Pointer to the read string.
2615 */
2616char *SDDS_ReadBinaryString(FILE *fp, SDDS_FILEBUFFER *fBuffer, int32_t skip) {
2617 int32_t length;
2618 char *string;
2619
2620 if (!SDDS_BufferedRead(&length, sizeof(length), fp, fBuffer, SDDS_LONG, 0) || length < 0)
2621 return (0);
2622 if (!(string = SDDS_Malloc(sizeof(*string) * (length + 1))))
2623 return (NULL);
2624 if (length && !SDDS_BufferedRead(skip ? NULL : string, sizeof(*string) * length, fp, fBuffer, SDDS_STRING, 0))
2625 return (NULL);
2626 string[length] = 0;
2627 return (string);
2628}
2629
2630/**
2631 * @brief Reads a binary string from an LZMA-compressed file with buffering.
2632 *
2633 * This function reads a binary string from the specified LZMA-compressed file by first reading the length
2634 * of the string and then reading the string content based on the length. If the 'skip' parameter is set,
2635 * the string data is skipped over instead of being stored. The function allocates memory for the string,
2636 * which should be freed by the caller when no longer needed.
2637 *
2638 * @param[in] lzmafp The LZMA file pointer to read from. Must be an open LZMA-compressed file in read mode.
2639 * @param[in,out] fBuffer Pointer to the file buffer used for buffered reading operations.
2640 * @param[in] skip If non-zero, the string data is skipped without being stored.
2641 *
2642 * @return char* Returns a pointer to the read null-terminated string on success, or NULL if an error occurred.
2643 * @retval NULL An error occurred during reading or memory allocation.
2644 * @retval Non-NULL Pointer to the read string.
2645 */
2646char *SDDS_ReadLZMABinaryString(struct lzmafile *lzmafp, SDDS_FILEBUFFER *fBuffer, int32_t skip) {
2647 int32_t length;
2648 char *string;
2649
2650 if (!SDDS_LZMABufferedRead(&length, sizeof(length), lzmafp, fBuffer, SDDS_LONG, 0) || length < 0)
2651 return (0);
2652 if (!(string = SDDS_Malloc(sizeof(*string) * (length + 1))))
2653 return (NULL);
2654 if (length && !SDDS_LZMABufferedRead(skip ? NULL : string, sizeof(*string) * length, lzmafp, fBuffer, SDDS_STRING, 0))
2655 return (NULL);
2656 string[length] = 0;
2657 return (string);
2658}
2659
2660#if defined(zLib)
2661/**
2662 * @brief Reads a binary string from a GZIP-compressed file with buffering.
2663 *
2664 * This function reads a binary string from the specified GZIP-compressed file by first reading the length
2665 * of the string and then reading the string content based on the length. If the 'skip' parameter is set,
2666 * the string data is skipped over instead of being stored. The function allocates memory for the string,
2667 * which should be freed by the caller when no longer needed.
2668 *
2669 * @param[in] gzfp The GZIP file pointer to read from. Must be an open GZIP-compressed file in read mode.
2670 * @param[in,out] fBuffer Pointer to the file buffer used for buffered reading operations.
2671 * @param[in] skip If non-zero, the string data is skipped without being stored.
2672 *
2673 * @return char* Returns a pointer to the read null-terminated string on success, or NULL if an error occurred.
2674 * @retval NULL An error occurred during reading or memory allocation.
2675 * @retval Non-NULL Pointer to the read string.
2676 */
2677char *SDDS_ReadGZipBinaryString(gzFile gzfp, SDDS_FILEBUFFER *fBuffer, int32_t skip) {
2678 int32_t length;
2679 char *string;
2680
2681 if (!SDDS_GZipBufferedRead(&length, sizeof(length), gzfp, fBuffer, SDDS_LONG, 0) || length < 0)
2682 return (0);
2683 if (!(string = SDDS_Malloc(sizeof(*string) * (length + 1))))
2684 return (NULL);
2685 if (length && !SDDS_GZipBufferedRead(skip ? NULL : string, sizeof(*string) * length, gzfp, fBuffer, SDDS_STRING, 0))
2686 return (NULL);
2687 string[length] = 0;
2688 return (string);
2689}
2690#endif
2691
2692/**
2693 * @brief Reads a binary row from the specified SDDS dataset.
2694 *
2695 * This function reads a single row of data from the given SDDS dataset. Depending on the dataset's configuration,
2696 * it handles uncompressed, LZMA-compressed, or GZIP-compressed files. For each column in the dataset, the function
2697 * reads the appropriate data type. If a column is of type string, it reads the string using the corresponding
2698 * string reading function. If the 'skip' parameter is set, the function skips reading the data without storing it.
2699 *
2700 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
2701 * @param[in] row The row number to read. Must be within the allocated range of rows in the dataset.
2702 * @param[in] skip If non-zero, the function skips reading the data for each column without storing it.
2703 *
2704 * @return int32_t Returns 1 on successful reading of the row, or 0 if an error occurred.
2705 * @retval 1 The row was successfully read and stored (or skipped).
2706 * @retval 0 An error occurred during reading, such as I/O errors or memory allocation failures.
2707 *
2708 * @note This function may modify the dataset's data structures by allocating memory for string columns.
2709 * Ensure that the dataset is properly initialized and that memory is managed appropriately.
2710 */
2711int32_t SDDS_ReadBinaryRow(SDDS_DATASET *SDDS_dataset, int64_t row, int32_t skip) {
2712 int64_t i, type, size;
2713 SDDS_LAYOUT *layout;
2714#if defined(zLib)
2715 gzFile gzfp;
2716#endif
2717 FILE *fp;
2718 struct lzmafile *lzmafp;
2719 SDDS_FILEBUFFER *fBuffer;
2720
2721 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReadBinaryRow"))
2722 return (0);
2723 layout = &SDDS_dataset->layout;
2724 fBuffer = &SDDS_dataset->fBuffer;
2725
2726#if defined(zLib)
2727 if (SDDS_dataset->layout.gzipFile) {
2728 gzfp = layout->gzfp;
2729 for (i = 0; i < layout->n_columns; i++) {
2730 if (layout->column_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
2731 continue;
2732 if ((type = layout->column_definition[i].type) == SDDS_STRING) {
2733 if (!skip) {
2734 if (((char ***)SDDS_dataset->data)[i][row])
2735 free((((char ***)SDDS_dataset->data)[i][row]));
2736 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadGZipBinaryString(gzfp, fBuffer, 0))) {
2737 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadBinaryRows)");
2738 return (0);
2739 }
2740 } else {
2741 if (!SDDS_ReadGZipBinaryString(gzfp, fBuffer, 1)) {
2742 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadBinaryRows)");
2743 return 0;
2744 }
2745 }
2746 } else {
2747 size = SDDS_type_size[type - 1];
2748 if (!SDDS_GZipBufferedRead(skip ? NULL : (char *)SDDS_dataset->data[i] + row * size, size, gzfp, fBuffer, type, SDDS_dataset->layout.byteOrderDeclared)) {
2749 SDDS_SetError("Unable to read row--failure reading value (SDDS_ReadBinaryRow)");
2750 return (0);
2751 }
2752 }
2753 }
2754 } else {
2755#endif
2756 if (SDDS_dataset->layout.lzmaFile) {
2757 lzmafp = layout->lzmafp;
2758 for (i = 0; i < layout->n_columns; i++) {
2759 if (layout->column_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
2760 continue;
2761 if ((type = layout->column_definition[i].type) == SDDS_STRING) {
2762 if (!skip) {
2763 if (((char ***)SDDS_dataset->data)[i][row])
2764 free((((char ***)SDDS_dataset->data)[i][row]));
2765 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadLZMABinaryString(lzmafp, fBuffer, 0))) {
2766 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadBinaryRows)");
2767 return (0);
2768 }
2769 } else {
2770 if (!SDDS_ReadLZMABinaryString(lzmafp, fBuffer, 1)) {
2771 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadBinaryRows)");
2772 return 0;
2773 }
2774 }
2775 } else {
2776 size = SDDS_type_size[type - 1];
2777 if (!SDDS_LZMABufferedRead(skip ? NULL : (char *)SDDS_dataset->data[i] + row * size, size, lzmafp, fBuffer, type, SDDS_dataset->layout.byteOrderDeclared)) {
2778 SDDS_SetError("Unable to read row--failure reading value (SDDS_ReadBinaryRow)");
2779 return (0);
2780 }
2781 }
2782 }
2783 } else {
2784 fp = layout->fp;
2785 for (i = 0; i < layout->n_columns; i++) {
2786 if (layout->column_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
2787 continue;
2788 if ((type = layout->column_definition[i].type) == SDDS_STRING) {
2789 if (!skip) {
2790 if (((char ***)SDDS_dataset->data)[i][row])
2791 free((((char ***)SDDS_dataset->data)[i][row]));
2792 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadBinaryString(fp, fBuffer, 0))) {
2793 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadBinaryRows)");
2794 return (0);
2795 }
2796 } else {
2797 if (!SDDS_ReadBinaryString(fp, fBuffer, 1)) {
2798 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadBinaryRows)");
2799 return 0;
2800 }
2801 }
2802 } else {
2803 size = SDDS_type_size[type - 1];
2804 if (!SDDS_BufferedRead(skip ? NULL : (char *)SDDS_dataset->data[i] + row * size, size, fp, fBuffer, type, SDDS_dataset->layout.byteOrderDeclared)) {
2805 SDDS_SetError("Unable to read row--failure reading value (SDDS_ReadBinaryRow)");
2806 return (0);
2807 }
2808 }
2809 }
2810 }
2811#if defined(zLib)
2812 }
2813#endif
2814 return (1);
2815}
2816
2817/**
2818 * @brief Reads new binary rows from the SDDS dataset.
2819 *
2820 * This function updates the SDDS dataset by reading any new rows that have been added to the underlying file
2821 * since the last read operation. It verifies that the dataset is in a compatible binary format and ensures
2822 * that byte order and compression settings are supported. If the number of rows in the file exceeds the
2823 * currently allocated rows in memory, the function expands the dataset's internal storage to accommodate
2824 * the new rows.
2825 *
2826 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
2827 *
2828 * @return int32_t Returns the number of new rows successfully read on success, or -1 if an error occurred.
2829 * @retval >0 The number of new rows read and added to the dataset.
2830 * @retval -1 An error occurred during the read operation, such as unsupported file format,
2831 * I/O errors, or memory allocation failures.
2832 *
2833 * @note This function does not support MPI parallel I/O, ASCII files, column-major order binary files,
2834 * non-native byte orders, or compressed files (gzip or lzma). Attempts to use these features will
2835 * result in an error.
2836 */
2837int32_t SDDS_ReadNewBinaryRows(SDDS_DATASET *SDDS_dataset) {
2838 int64_t row, offset, newRows = 0;
2839 int32_t rowsPresent32;
2840 int64_t rowsPresent;
2841
2842#if SDDS_MPI_IO
2843 if (SDDS_dataset->parallel_io) {
2844 SDDS_SetError("Error: MPI mode not supported yet in SDDS_ReadNewBinaryRows");
2845 return -1;
2846 }
2847#endif
2848 if (SDDS_dataset->original_layout.data_mode.mode == SDDS_ASCII) {
2849 SDDS_SetError("Error: ASCII files not supported in SDDS_ReadNewBinaryRows");
2850 return -1;
2851 }
2852 if (SDDS_dataset->layout.data_mode.column_major) {
2853 SDDS_SetError("Error: column-major order binary files not supported in SDDS_ReadNewBinaryRows");
2854 return -1;
2855 }
2856 if (SDDS_dataset->swapByteOrder) {
2857 SDDS_SetError("Error: Non-native endian not supported yet in SDDS_ReadNewBinaryRows");
2858 return -1;
2859 }
2860#if defined(zLib)
2861 if (SDDS_dataset->layout.gzipFile) {
2862 SDDS_SetError("Error: gzip compressed files not supported yet in SDDS_ReadNewBinaryRows");
2863 return -1;
2864 } else {
2865#endif
2866 if (SDDS_dataset->layout.lzmaFile) {
2867 SDDS_SetError("Error: lzma compressed files not supported yet in SDDS_ReadNewBinaryRows");
2868 return -1;
2869 }
2870#if defined(zLib)
2871 }
2872#endif
2873
2874 // Read how many rows we have now
2875 offset = ftell(SDDS_dataset->layout.fp);
2876 fseek(SDDS_dataset->layout.fp, SDDS_dataset->rowcount_offset, 0);
2877 if (SDDS_dataset->layout.data_mode.mode == SDDS_BINARY) {
2878 if (fread(&rowsPresent32, sizeof(rowsPresent32), 1, SDDS_dataset->layout.fp) == 0) {
2879 SDDS_SetError("Error: row count not present or not correct length");
2880 return -1;
2881 }
2882 if (SDDS_dataset->swapByteOrder) {
2883 SDDS_SwapLong(&rowsPresent32);
2884 }
2885 if (rowsPresent32 == INT32_MIN) {
2886 if (fread(&rowsPresent, sizeof(rowsPresent), 1, SDDS_dataset->layout.fp) == 0) {
2887 SDDS_SetError("Error: row count not present or not correct length");
2888 return -1;
2889 }
2890 if (SDDS_dataset->swapByteOrder) {
2891 SDDS_SwapLong64(&rowsPresent);
2892 }
2893 } else {
2894 rowsPresent = rowsPresent32;
2895 }
2896 } else {
2897 char buffer[30];
2898 if (!fgets(buffer, 30, SDDS_dataset->layout.fp) || strlen(buffer) != 21 || sscanf(buffer, "%" SCNd64, &rowsPresent) != 1) {
2899 SDDS_SetError("Error: row count not present or not correct length");
2900 return -1;
2901 }
2902 }
2903 fseek(SDDS_dataset->layout.fp, offset, 0);
2904
2905 // If the row count listed in the file is greather than the allocated rows, then lengthen the table in memory
2906 if (rowsPresent > SDDS_dataset->n_rows_allocated) {
2907 if (!SDDS_LengthenTable(SDDS_dataset, rowsPresent + 3)) {
2908 return -1;
2909 }
2910 }
2911
2912 for (row = SDDS_dataset->n_rows; row < rowsPresent; row++) {
2913 if (!SDDS_ReadBinaryRow(SDDS_dataset, row, 0)) {
2914 if (SDDS_dataset->autoRecover) {
2915 row--;
2916 SDDS_dataset->autoRecovered = 1;
2918 break;
2919 }
2920 SDDS_SetError("Unable to read page--error reading data row");
2921 return -1;
2922 }
2923 }
2924 newRows = row + 1 - SDDS_dataset->n_rows;
2925 SDDS_dataset->n_rows = row + 1;
2926 return newRows;
2927}
2928
2929/**
2930 * @brief Reads binary parameters from the specified SDDS dataset.
2931 *
2932 * This function iterates through all the parameters defined in the SDDS dataset layout and reads their values
2933 * from the underlying file. It handles different data types, including strings, and manages memory allocation
2934 * for string parameters. Depending on the dataset's compression settings (uncompressed, LZMA, or GZIP),
2935 * it uses the appropriate reading functions to retrieve the parameter values.
2936 *
2937 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
2938 *
2939 * @return int32_t Returns 1 on successfully reading all binary parameters, or 0 if an error occurred.
2940 * @retval 1 All parameters were successfully read and stored.
2941 * @retval 0 An error occurred during the read operation, such as I/O errors, data type mismatches, or memory allocation failures.
2942 *
2943 * @note Parameters with the 'fixed_value' attribute are handled by scanning the fixed value string
2944 * instead of reading from the file. String parameters are dynamically allocated and should be
2945 * freed by the caller when no longer needed.
2946 */
2948 int32_t i;
2949 SDDS_LAYOUT *layout;
2950 /* char *predefined_format; */
2951 char buffer[SDDS_MAXLINE];
2952#if defined(zLib)
2953 gzFile gzfp = NULL;
2954#endif
2955 FILE *fp = NULL;
2956 struct lzmafile *lzmafp = NULL;
2957 SDDS_FILEBUFFER *fBuffer;
2958
2959 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReadBinaryParameters"))
2960 return (0);
2961 layout = &SDDS_dataset->layout;
2962 if (!layout->n_parameters)
2963 return (1);
2964#if defined(zLib)
2965 if (SDDS_dataset->layout.gzipFile) {
2966 gzfp = layout->gzfp;
2967 } else {
2968#endif
2969 if (SDDS_dataset->layout.lzmaFile) {
2970 lzmafp = layout->lzmafp;
2971 } else {
2972 fp = layout->fp;
2973 }
2974#if defined(zLib)
2975 }
2976#endif
2977 fBuffer = &SDDS_dataset->fBuffer;
2978 for (i = 0; i < layout->n_parameters; i++) {
2979 if (layout->parameter_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
2980 continue;
2981 if (layout->parameter_definition[i].fixed_value) {
2982 strcpy(buffer, layout->parameter_definition[i].fixed_value);
2983 if (!SDDS_ScanData(buffer, layout->parameter_definition[i].type, 0, SDDS_dataset->parameter[i], 0, 1)) {
2984 SDDS_SetError("Unable to read page--parameter scanning error (SDDS_ReadBinaryParameters)");
2985 return (0);
2986 }
2987 } else if (layout->parameter_definition[i].type == SDDS_STRING) {
2988 if (*(char **)SDDS_dataset->parameter[i])
2989 free(*(char **)SDDS_dataset->parameter[i]);
2990#if defined(zLib)
2991 if (SDDS_dataset->layout.gzipFile) {
2992 if (!(*((char **)SDDS_dataset->parameter[i]) = SDDS_ReadGZipBinaryString(gzfp, fBuffer, 0))) {
2993 SDDS_SetError("Unable to read parameters--failure reading string (SDDS_ReadBinaryParameters)");
2994 return (0);
2995 }
2996 } else {
2997#endif
2998 if (SDDS_dataset->layout.lzmaFile) {
2999 if (!(*((char **)SDDS_dataset->parameter[i]) = SDDS_ReadLZMABinaryString(lzmafp, fBuffer, 0))) {
3000 SDDS_SetError("Unable to read parameters--failure reading string (SDDS_ReadBinaryParameters)");
3001 return (0);
3002 }
3003 } else {
3004 if (!(*((char **)SDDS_dataset->parameter[i]) = SDDS_ReadBinaryString(fp, fBuffer, 0))) {
3005 SDDS_SetError("Unable to read parameters--failure reading string (SDDS_ReadBinaryParameters)");
3006 return (0);
3007 }
3008 }
3009#if defined(zLib)
3010 }
3011#endif
3012 } else {
3013#if defined(zLib)
3014 if (SDDS_dataset->layout.gzipFile) {
3015 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)) {
3016 SDDS_SetError("Unable to read parameters--failure reading value (SDDS_ReadBinaryParameters)");
3017 return (0);
3018 }
3019 } else {
3020#endif
3021 if (SDDS_dataset->layout.lzmaFile) {
3022 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)) {
3023 SDDS_SetError("Unable to read parameters--failure reading value (SDDS_ReadBinaryParameters)");
3024 return (0);
3025 }
3026 } else {
3027 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)) {
3028 SDDS_SetError("Unable to read parameters--failure reading value (SDDS_ReadBinaryParameters)");
3029 return (0);
3030 }
3031 }
3032#if defined(zLib)
3033 }
3034#endif
3035 }
3036 }
3037 return (1);
3038}
3039
3040/**
3041 * @brief Reads binary arrays from an SDDS dataset.
3042 *
3043 * This function iterates through all array definitions within the specified SDDS dataset and reads their
3044 * binary data from the underlying file. It handles various compression formats, including uncompressed,
3045 * LZMA-compressed, and GZIP-compressed files. For each array, the function reads its definition, dimensions,
3046 * and data elements, allocating and managing memory as necessary. String arrays are handled by reading
3047 * each string individually, while other data types are read in bulk.
3048 *
3049 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
3050 *
3051 * @return int32_t Returns 1 on successful reading of all arrays, or 0 if an error occurred.
3052 * @retval 1 All arrays were successfully read and stored.
3053 * @retval 0 An error occurred during the read operation, such as I/O failures, memory allocation issues,
3054 * or corrupted array definitions.
3055 *
3056 * @note The caller is responsible for ensuring that the SDDS_dataset structure is properly initialized
3057 * and that memory allocations for arrays are managed appropriately to prevent memory leaks.
3058 */
3059int32_t SDDS_ReadBinaryArrays(SDDS_DATASET *SDDS_dataset) {
3060 int32_t i, j;
3061 SDDS_LAYOUT *layout;
3062 /* char *predefined_format; */
3063 /* static char buffer[SDDS_MAXLINE]; */
3064#if defined(zLib)
3065 gzFile gzfp = NULL;
3066#endif
3067 FILE *fp = NULL;
3068 struct lzmafile *lzmafp = NULL;
3069 SDDS_ARRAY *array;
3070 SDDS_FILEBUFFER *fBuffer;
3071
3072 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReadBinaryArrays"))
3073 return (0);
3074 layout = &SDDS_dataset->layout;
3075 if (!layout->n_arrays)
3076 return (1);
3077#if defined(zLib)
3078 if (SDDS_dataset->layout.gzipFile) {
3079 gzfp = layout->gzfp;
3080 } else {
3081#endif
3082 if (SDDS_dataset->layout.lzmaFile) {
3083 lzmafp = layout->lzmafp;
3084 } else {
3085 fp = layout->fp;
3086 }
3087#if defined(zLib)
3088 }
3089#endif
3090 fBuffer = &SDDS_dataset->fBuffer;
3091 if (!SDDS_dataset->array) {
3092 SDDS_SetError("Unable to read array--pointer to structure storage area is NULL (SDDS_ReadBinaryArrays)");
3093 return (0);
3094 }
3095 for (i = 0; i < layout->n_arrays; i++) {
3096 array = SDDS_dataset->array + i;
3097 if (array->definition && !SDDS_FreeArrayDefinition(array->definition)) {
3098 SDDS_SetError("Unable to get array--array definition corrupted (SDDS_ReadBinaryArrays)");
3099 return (0);
3100 }
3101 if (!SDDS_CopyArrayDefinition(&array->definition, layout->array_definition + i)) {
3102 SDDS_SetError("Unable to read array--definition copy failed (SDDS_ReadBinaryArrays)");
3103 return (0);
3104 }
3105 /*if (array->dimension) free(array->dimension); */
3106 if (!(array->dimension = SDDS_Realloc(array->dimension, sizeof(*array->dimension) * array->definition->dimensions))) {
3107 SDDS_SetError("Unable to read array--allocation failure (SDDS_ReadBinaryArrays)");
3108 return (0);
3109 }
3110#if defined(zLib)
3111 if (SDDS_dataset->layout.gzipFile) {
3112 if (!SDDS_GZipBufferedRead(array->dimension, sizeof(*array->dimension) * array->definition->dimensions, gzfp, fBuffer, SDDS_LONG, SDDS_dataset->layout.byteOrderDeclared)) {
3113 SDDS_SetError("Unable to read arrays--failure reading dimensions (SDDS_ReadBinaryArrays)");
3114 return (0);
3115 }
3116 } else {
3117#endif
3118 if (SDDS_dataset->layout.lzmaFile) {
3119 if (!SDDS_LZMABufferedRead(array->dimension, sizeof(*array->dimension) * array->definition->dimensions, lzmafp, fBuffer, SDDS_LONG, SDDS_dataset->layout.byteOrderDeclared)) {
3120 SDDS_SetError("Unable to read arrays--failure reading dimensions (SDDS_ReadBinaryArrays)");
3121 return (0);
3122 }
3123 } else {
3124 if (!SDDS_BufferedRead(array->dimension, sizeof(*array->dimension) * array->definition->dimensions, fp, fBuffer, SDDS_LONG, SDDS_dataset->layout.byteOrderDeclared)) {
3125 SDDS_SetError("Unable to read arrays--failure reading dimensions (SDDS_ReadBinaryArrays)");
3126 return (0);
3127 }
3128 }
3129#if defined(zLib)
3130 }
3131#endif
3132 array->elements = 1;
3133 for (j = 0; j < array->definition->dimensions; j++)
3134 array->elements *= array->dimension[j];
3135 if (array->data)
3136 free(array->data);
3137 array->data = array->pointer = NULL;
3138 if (array->elements == 0)
3139 continue;
3140 if (array->elements < 0) {
3141 SDDS_SetError("Unable to read array--number of elements is negative (SDDS_ReadBinaryArrays)");
3142 return (0);
3143 }
3144 if (!(array->data = SDDS_Realloc(array->data, array->elements * SDDS_type_size[array->definition->type - 1]))) {
3145 SDDS_SetError("Unable to read array--allocation failure (SDDS_ReadBinaryArrays)");
3146 return (0);
3147 }
3148 if (array->definition->type == SDDS_STRING) {
3149#if defined(zLib)
3150 if (SDDS_dataset->layout.gzipFile) {
3151 for (j = 0; j < array->elements; j++) {
3152 if (!(((char **)(array->data))[j] = SDDS_ReadGZipBinaryString(gzfp, fBuffer, 0))) {
3153 SDDS_SetError("Unable to read arrays--failure reading string (SDDS_ReadBinaryArrays)");
3154 return (0);
3155 }
3156 }
3157 } else {
3158#endif
3159 if (SDDS_dataset->layout.lzmaFile) {
3160 for (j = 0; j < array->elements; j++) {
3161 if (!(((char **)(array->data))[j] = SDDS_ReadLZMABinaryString(lzmafp, fBuffer, 0))) {
3162 SDDS_SetError("Unable to read arrays--failure reading string (SDDS_ReadBinaryArrays)");
3163 return (0);
3164 }
3165 }
3166 } else {
3167 for (j = 0; j < array->elements; j++) {
3168 if (!(((char **)(array->data))[j] = SDDS_ReadBinaryString(fp, fBuffer, 0))) {
3169 SDDS_SetError("Unable to read arrays--failure reading string (SDDS_ReadBinaryArrays)");
3170 return (0);
3171 }
3172 }
3173 }
3174#if defined(zLib)
3175 }
3176#endif
3177 } else {
3178#if defined(zLib)
3179 if (SDDS_dataset->layout.gzipFile) {
3180 if (!SDDS_GZipBufferedRead(array->data, SDDS_type_size[array->definition->type - 1] * array->elements, gzfp, fBuffer, array->definition->type, SDDS_dataset->layout.byteOrderDeclared)) {
3181 SDDS_SetError("Unable to read arrays--failure reading values (SDDS_ReadBinaryArrays)");
3182 return (0);
3183 }
3184 } else {
3185#endif
3186 if (SDDS_dataset->layout.lzmaFile) {
3187 if (!SDDS_LZMABufferedRead(array->data, SDDS_type_size[array->definition->type - 1] * array->elements, lzmafp, fBuffer, array->definition->type, SDDS_dataset->layout.byteOrderDeclared)) {
3188 SDDS_SetError("Unable to read arrays--failure reading values (SDDS_ReadBinaryArrays)");
3189 return (0);
3190 }
3191 } else {
3192 if (!SDDS_BufferedRead(array->data, SDDS_type_size[array->definition->type - 1] * array->elements, fp, fBuffer, array->definition->type, SDDS_dataset->layout.byteOrderDeclared)) {
3193 SDDS_SetError("Unable to read arrays--failure reading values (SDDS_ReadBinaryArrays)");
3194 return (0);
3195 }
3196 }
3197#if defined(zLib)
3198 }
3199#endif
3200 }
3201 }
3202 return (1);
3203}
3204
3205/**
3206 * @brief Reads the binary columns from an SDDS dataset.
3207 *
3208 * This function iterates through all column definitions within the specified SDDS dataset and reads their
3209 * binary data from the underlying file. It handles various compression formats, including uncompressed,
3210 * LZMA-compressed, and GZIP-compressed files. For each column, the function reads data for each row,
3211 * managing memory allocation for string columns as necessary. Non-string data types are read in bulk for
3212 * each column.
3213 *
3214 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
3215 *
3216 * @return int32_t Returns 1 on successful reading of all columns, or 0 if an error occurred.
3217 * @retval 1 All columns were successfully read and stored.
3218 * @retval 0 An error occurred during the read operation, such as I/O failures, memory allocation issues,
3219 * or corrupted column definitions.
3220 *
3221 * @note The caller is responsible for ensuring that the SDDS_dataset structure is properly initialized
3222 * and that memory allocations for columns are managed appropriately to prevent memory leaks.
3223 */
3224int32_t SDDS_ReadBinaryColumns(SDDS_DATASET *SDDS_dataset, int64_t sparse_interval, int64_t sparse_offset) {
3225 int64_t i, j, k, row;
3226 SDDS_LAYOUT *layout;
3227 /* char *predefined_format; */
3228 /* static char buffer[SDDS_MAXLINE]; */
3229#if defined(zLib)
3230 gzFile gzfp = NULL;
3231#endif
3232 FILE *fp = NULL;
3233 struct lzmafile *lzmafp = NULL;
3234 SDDS_FILEBUFFER *fBuffer;
3235
3236 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReadBinaryColumns"))
3237 return (0);
3238 layout = &SDDS_dataset->layout;
3239 if (!layout->n_columns || !SDDS_dataset->n_rows)
3240 return (1);
3241#if defined(zLib)
3242 if (SDDS_dataset->layout.gzipFile) {
3243 gzfp = layout->gzfp;
3244 } else {
3245#endif
3246 if (SDDS_dataset->layout.lzmaFile) {
3247 lzmafp = layout->lzmafp;
3248 } else {
3249 fp = layout->fp;
3250 }
3251#if defined(zLib)
3252 }
3253#endif
3254 fBuffer = &SDDS_dataset->fBuffer;
3255
3256 for (i = 0; i < layout->n_columns; i++) {
3257 if (layout->column_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
3258 continue;
3259 if (layout->column_definition[i].type == SDDS_STRING) {
3260#if defined(zLib)
3261 if (SDDS_dataset->layout.gzipFile) {
3262 for (row = 0; row < SDDS_dataset->n_rows; row++) {
3263 if (((char ***)SDDS_dataset->data)[i][row])
3264 free((((char ***)SDDS_dataset->data)[i][row]));
3265 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadGZipBinaryString(gzfp, fBuffer, 0))) {
3266 SDDS_SetError("Unable to read columns--failure reading string (SDDS_ReadBinaryColumns)");
3267 return (0);
3268 }
3269 }
3270 } else {
3271#endif
3272 if (SDDS_dataset->layout.lzmaFile) {
3273 for (row = 0; row < SDDS_dataset->n_rows; row++) {
3274 if (((char ***)SDDS_dataset->data)[i][row])
3275 free((((char ***)SDDS_dataset->data)[i][row]));
3276 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadLZMABinaryString(lzmafp, fBuffer, 0))) {
3277 SDDS_SetError("Unable to read columns--failure reading string (SDDS_ReadBinaryColumms)");
3278 return (0);
3279 }
3280 }
3281 } else {
3282 for (row = 0; row < SDDS_dataset->n_rows; row++) {
3283 if (((char ***)SDDS_dataset->data)[i][row])
3284 free((((char ***)SDDS_dataset->data)[i][row]));
3285 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadBinaryString(fp, fBuffer, 0))) {
3286 SDDS_SetError("Unable to read columns--failure reading string (SDDS_ReadBinaryColumms)");
3287 return (0);
3288 }
3289 }
3290 }
3291#if defined(zLib)
3292 }
3293#endif
3294 } else {
3295#if defined(zLib)
3296 if (SDDS_dataset->layout.gzipFile) {
3297 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)) {
3298 SDDS_SetError("Unable to read columns--failure reading values (SDDS_ReadBinaryColumns)");
3299 return (0);
3300 }
3301 } else {
3302#endif
3303 if (SDDS_dataset->layout.lzmaFile) {
3304 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)) {
3305 SDDS_SetError("Unable to read columns--failure reading values (SDDS_ReadBinaryColumns)");
3306 return (0);
3307 }
3308 } else {
3309 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)) {
3310 SDDS_SetError("Unable to read columns--failure reading values (SDDS_ReadBinaryColumns)");
3311 return (0);
3312 }
3313 }
3314#if defined(zLib)
3315 }
3316#endif
3317 }
3318 }
3319
3320 if (sparse_interval == 1 && sparse_offset == 0) {
3321 return(1);
3322 }
3323
3324 j = SDDS_dataset->n_rows;
3325 for (i = 0; i < layout->n_columns; i++) {
3326 j = k = 0;
3327 switch (layout->column_definition[i].type) {
3328 case SDDS_SHORT:
3329 for (row = sparse_offset; row < SDDS_dataset->n_rows; row++) {
3330 if (k % sparse_interval == 0) {
3331 ((short*)SDDS_dataset->data[i])[j] = ((short*)SDDS_dataset->data[i])[row];
3332 j++;
3333 }
3334 k++;
3335 }
3336 break;
3337 case SDDS_USHORT:
3338 for (row = sparse_offset; row < SDDS_dataset->n_rows; row++) {
3339 if (k % sparse_interval == 0) {
3340 ((unsigned short*)SDDS_dataset->data[i])[j] = ((unsigned short*)SDDS_dataset->data[i])[row];
3341 j++;
3342 }
3343 k++;
3344 }
3345 break;
3346 case SDDS_LONG:
3347 for (row = sparse_offset; row < SDDS_dataset->n_rows; row++) {
3348 if (k % sparse_interval == 0) {
3349 ((int32_t*)SDDS_dataset->data[i])[j] = ((int32_t*)SDDS_dataset->data[i])[row];
3350 j++;
3351 }
3352 k++;
3353 }
3354 break;
3355 case SDDS_ULONG:
3356 for (row = sparse_offset; row < SDDS_dataset->n_rows; row++) {
3357 if (k % sparse_interval == 0) {
3358 ((uint32_t*)SDDS_dataset->data[i])[j] = ((uint32_t*)SDDS_dataset->data[i])[row];
3359 j++;
3360 }
3361 k++;
3362 }
3363 break;
3364 case SDDS_LONG64:
3365 for (row = sparse_offset; row < SDDS_dataset->n_rows; row++) {
3366 if (k % sparse_interval == 0) {
3367 ((int64_t*)SDDS_dataset->data[i])[j] = ((int64_t*)SDDS_dataset->data[i])[row];
3368 j++;
3369 }
3370 k++;
3371 }
3372 break;
3373 case SDDS_ULONG64:
3374 for (row = sparse_offset; row < SDDS_dataset->n_rows; row++) {
3375 if (k % sparse_interval == 0) {
3376 ((uint64_t*)SDDS_dataset->data[i])[j] = ((uint64_t*)SDDS_dataset->data[i])[row];
3377 j++;
3378 }
3379 k++;
3380 }
3381 break;
3382 case SDDS_FLOAT:
3383 for (row = sparse_offset; row < SDDS_dataset->n_rows; row++) {
3384 if (k % sparse_interval == 0) {
3385 ((float*)SDDS_dataset->data[i])[j] = ((float*)SDDS_dataset->data[i])[row];
3386 j++;
3387 }
3388 k++;
3389 }
3390 break;
3391 case SDDS_DOUBLE:
3392 for (row = sparse_offset; row < SDDS_dataset->n_rows; row++) {
3393 if (k % sparse_interval == 0) {
3394 ((double*)SDDS_dataset->data[i])[j] = ((double*)SDDS_dataset->data[i])[row];
3395 j++;
3396 }
3397 k++;
3398 }
3399 break;
3400 case SDDS_LONGDOUBLE:
3401 for (row = sparse_offset; row < SDDS_dataset->n_rows; row++) {
3402 if (k % sparse_interval == 0) {
3403 ((long double*)SDDS_dataset->data[i])[j] = ((long double*)SDDS_dataset->data[i])[row];
3404 j++;
3405 }
3406 k++;
3407 }
3408 break;
3409 case SDDS_STRING:
3410 for (row = sparse_offset; row < SDDS_dataset->n_rows; row++) {
3411 if (k % sparse_interval == 0) {
3412 ((char**)SDDS_dataset->data[i])[j] = ((char**)SDDS_dataset->data[i])[row];
3413 j++;
3414 }
3415 k++;
3416 }
3417 for (k=j; k<SDDS_dataset->n_rows; k++) {
3418 if (((char ***)SDDS_dataset->data)[i][k]) {
3419 free((((char ***)SDDS_dataset->data)[i][k]));
3420 ((char ***)SDDS_dataset->data)[i][k] = NULL;
3421 }
3422 }
3423
3424 break;
3425 case SDDS_CHARACTER:
3426 for (row = sparse_offset; row < SDDS_dataset->n_rows; row++) {
3427 if (k % sparse_interval == 0) {
3428 ((char*)SDDS_dataset->data[i])[j] = ((char*)SDDS_dataset->data[i])[row];
3429 j++;
3430 }
3431 k++;
3432 }
3433 break;
3434 default:
3435 break;
3436 }
3437 }
3438
3439 SDDS_dataset->n_rows = j;
3440
3441 return (1);
3442}
3443
3444/**
3445 * @brief Reads the non-native endian binary columns from an SDDS dataset.
3446 *
3447 * This function is similar to SDDS_ReadBinaryColumns but specifically handles columns with non-native
3448 * endianness. It iterates through all column definitions within the specified SDDS dataset and reads
3449 * their binary data from the underlying file, ensuring that the byte order is correctly swapped
3450 * to match the system's native endianness. The function supports various compression formats,
3451 * including uncompressed, LZMA-compressed, and GZIP-compressed files.
3452 *
3453 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
3454 *
3455 * @return int32_t Returns 1 on successful reading and byte-swapping of all columns, or 0 if an error occurred.
3456 * @retval 1 All non-native endian columns were successfully read and byte-swapped.
3457 * @retval 0 An error occurred during the read or byte-swapping operation, such as I/O failures,
3458 * memory allocation issues, or corrupted column definitions.
3459 *
3460 * @note This function assumes that the dataset's byte order has been declared and that the
3461 * underlying file's byte order differs from the system's native byte order. Proper
3462 * initialization and configuration of the SDDS_dataset structure are required before
3463 * calling this function.
3464 */
3466 int64_t i, row;
3467 SDDS_LAYOUT *layout;
3468 /* char *predefined_format; */
3469 /* static char buffer[SDDS_MAXLINE]; */
3470#if defined(zLib)
3471 gzFile gzfp = NULL;
3472#endif
3473 FILE *fp = NULL;
3474 struct lzmafile *lzmafp = NULL;
3475 SDDS_FILEBUFFER *fBuffer;
3476
3477 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReadNonNativeBinaryColumns"))
3478 return (0);
3479 layout = &SDDS_dataset->layout;
3480 if (!layout->n_columns || !SDDS_dataset->n_rows)
3481 return (1);
3482#if defined(zLib)
3483 if (SDDS_dataset->layout.gzipFile) {
3484 gzfp = layout->gzfp;
3485 } else {
3486#endif
3487 if (SDDS_dataset->layout.lzmaFile) {
3488 lzmafp = layout->lzmafp;
3489 } else {
3490 fp = layout->fp;
3491 }
3492#if defined(zLib)
3493 }
3494#endif
3495 fBuffer = &SDDS_dataset->fBuffer;
3496
3497 for (i = 0; i < layout->n_columns; i++) {
3498 if (layout->column_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
3499 continue;
3500 if (layout->column_definition[i].type == SDDS_STRING) {
3501#if defined(zLib)
3502 if (SDDS_dataset->layout.gzipFile) {
3503 for (row = 0; row < SDDS_dataset->n_rows; row++) {
3504 if (((char ***)SDDS_dataset->data)[i][row])
3505 free((((char ***)SDDS_dataset->data)[i][row]));
3506 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadNonNativeGZipBinaryString(gzfp, fBuffer, 0))) {
3507 SDDS_SetError("Unable to read columns--failure reading string (SDDS_ReadNonNativeBinaryColumns)");
3508 return (0);
3509 }
3510 }
3511 } else {
3512#endif
3513 if (SDDS_dataset->layout.lzmaFile) {
3514 for (row = 0; row < SDDS_dataset->n_rows; row++) {
3515 if (((char ***)SDDS_dataset->data)[i][row])
3516 free((((char ***)SDDS_dataset->data)[i][row]));
3517 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadNonNativeLZMABinaryString(lzmafp, fBuffer, 0))) {
3518 SDDS_SetError("Unable to read columns--failure reading string (SDDS_ReadNonNativeBinaryColumms)");
3519 return (0);
3520 }
3521 }
3522 } else {
3523 for (row = 0; row < SDDS_dataset->n_rows; row++) {
3524 if (((char ***)SDDS_dataset->data)[i][row])
3525 free((((char ***)SDDS_dataset->data)[i][row]));
3526 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadNonNativeBinaryString(fp, fBuffer, 0))) {
3527 SDDS_SetError("Unable to read columns--failure reading string (SDDS_ReadNonNativeBinaryColumms)");
3528 return (0);
3529 }
3530 }
3531 }
3532#if defined(zLib)
3533 }
3534#endif
3535 } else {
3536#if defined(zLib)
3537 if (SDDS_dataset->layout.gzipFile) {
3538 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)) {
3539 SDDS_SetError("Unable to read columns--failure reading values (SDDS_ReadNonNativeBinaryColumns)");
3540 return (0);
3541 }
3542 } else {
3543#endif
3544 if (SDDS_dataset->layout.lzmaFile) {
3545 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)) {
3546 SDDS_SetError("Unable to read columns--failure reading values (SDDS_ReadNonNativeBinaryColumns)");
3547 return (0);
3548 }
3549 } else {
3550 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)) {
3551 SDDS_SetError("Unable to read columns--failure reading values (SDDS_ReadNonNativeBinaryColumns)");
3552 return (0);
3553 }
3554 }
3555#if defined(zLib)
3556 }
3557#endif
3558 }
3559 }
3560 return (1);
3561}
3562
3563/**
3564 * @brief Swaps the endianness of the column data in an SDDS dataset.
3565 *
3566 * This function iterates through all columns in the specified SDDS dataset and swaps the byte order
3567 * of each data element to match the system's native endianness. It supports various data types,
3568 * including short, unsigned short, long, unsigned long, long long, unsigned long long, float,
3569 * double, and long double. The function ensures that binary data is correctly interpreted on systems
3570 * with different byte orders.
3571 *
3572 * @param[in,out] SDDSin Pointer to the SDDS_DATASET structure representing the dataset whose
3573 * column data endianness is to be swapped.
3574 *
3575 * @return int32_t Always returns 1.
3576 * @retval 1 The endianness of all applicable column data elements was successfully swapped.
3577 *
3578 * @note This function modifies the dataset's column data in place. It should be called only when
3579 * the dataset's byte order is known to differ from the system's native byte order.
3580 * String data types are not affected by this function.
3581 */
3583 int32_t i, row;
3584 SDDS_LAYOUT *layout;
3585 short *sData;
3586 unsigned short *suData;
3587 int32_t *lData;
3588 uint32_t *luData;
3589 int64_t *lData64;
3590 uint64_t *luData64;
3591 float *fData;
3592 double *dData;
3593 long double *ldData;
3594
3595 layout = &SDDSin->layout;
3596 for (i = 0; i < layout->n_columns; i++) {
3597 switch (layout->column_definition[i].type) {
3598 case SDDS_SHORT:
3599 sData = SDDSin->data[i];
3600 for (row = 0; row < SDDSin->n_rows; row++)
3601 SDDS_SwapShort(sData + row);
3602 break;
3603 case SDDS_USHORT:
3604 suData = SDDSin->data[i];
3605 for (row = 0; row < SDDSin->n_rows; row++)
3606 SDDS_SwapUShort(suData + row);
3607 break;
3608 case SDDS_LONG:
3609 lData = SDDSin->data[i];
3610 for (row = 0; row < SDDSin->n_rows; row++)
3611 SDDS_SwapLong(lData + row);
3612 break;
3613 case SDDS_ULONG:
3614 luData = SDDSin->data[i];
3615 for (row = 0; row < SDDSin->n_rows; row++)
3616 SDDS_SwapULong(luData + row);
3617 break;
3618 case SDDS_LONG64:
3619 lData64 = SDDSin->data[i];
3620 for (row = 0; row < SDDSin->n_rows; row++)
3621 SDDS_SwapLong64(lData64 + row);
3622 break;
3623 case SDDS_ULONG64:
3624 luData64 = SDDSin->data[i];
3625 for (row = 0; row < SDDSin->n_rows; row++)
3626 SDDS_SwapULong64(luData64 + row);
3627 break;
3628 case SDDS_LONGDOUBLE:
3629 ldData = SDDSin->data[i];
3630 for (row = 0; row < SDDSin->n_rows; row++)
3631 SDDS_SwapLongDouble(ldData + row);
3632 break;
3633 case SDDS_DOUBLE:
3634 dData = SDDSin->data[i];
3635 for (row = 0; row < SDDSin->n_rows; row++)
3636 SDDS_SwapDouble(dData + row);
3637 break;
3638 case SDDS_FLOAT:
3639 fData = SDDSin->data[i];
3640 for (row = 0; row < SDDSin->n_rows; row++)
3641 SDDS_SwapFloat(fData + row);
3642 break;
3643 default:
3644 break;
3645 }
3646 }
3647 return (1);
3648}
3649
3650/**
3651 * @brief Swaps the endianness of the parameter data in an SDDS dataset.
3652 *
3653 * This function iterates through all parameters in the specified SDDS dataset and swaps the byte order
3654 * of each data element to match the system's native endianness. It handles various data types, including
3655 * short, unsigned short, long, unsigned long, long long, unsigned long long, float, double, and
3656 * long double. Parameters with fixed values are skipped as their byte order is already consistent.
3657 *
3658 * @param[in,out] SDDSin Pointer to the SDDS_DATASET structure representing the dataset whose
3659 * parameter data endianness is to be swapped.
3660 *
3661 * @return int32_t Always returns 1.
3662 * @retval 1 The endianness of all applicable parameter data elements was successfully swapped.
3663 *
3664 * @note This function modifies the dataset's parameter data in place. It should be called only when
3665 * the dataset's byte order is known to differ from the system's native byte order.
3666 * String data types and parameters with fixed values are not affected by this function.
3667 */
3669 int32_t i;
3670 SDDS_LAYOUT *layout;
3671 short *sData;
3672 unsigned short *suData;
3673 int32_t *lData;
3674 uint32_t *luData;
3675 int64_t *lData64;
3676 uint64_t *luData64;
3677 float *fData;
3678 double *dData;
3679 long double *ldData;
3680
3681 layout = &SDDSin->layout;
3682 for (i = 0; i < layout->n_parameters; i++) {
3683 if (layout->parameter_definition[i].fixed_value) {
3684 continue;
3685 }
3686 switch (layout->parameter_definition[i].type) {
3687 case SDDS_SHORT:
3688 sData = SDDSin->parameter[i];
3689 SDDS_SwapShort(sData);
3690 break;
3691 case SDDS_USHORT:
3692 suData = SDDSin->parameter[i];
3693 SDDS_SwapUShort(suData);
3694 break;
3695 case SDDS_LONG:
3696 lData = SDDSin->parameter[i];
3697 SDDS_SwapLong(lData);
3698 break;
3699 case SDDS_ULONG:
3700 luData = SDDSin->parameter[i];
3701 SDDS_SwapULong(luData);
3702 break;
3703 case SDDS_LONG64:
3704 lData64 = SDDSin->parameter[i];
3705 SDDS_SwapLong64(lData64);
3706 break;
3707 case SDDS_ULONG64:
3708 luData64 = SDDSin->parameter[i];
3709 SDDS_SwapULong64(luData64);
3710 break;
3711 case SDDS_LONGDOUBLE:
3712 ldData = SDDSin->parameter[i];
3713 SDDS_SwapLongDouble(ldData);
3714 break;
3715 case SDDS_DOUBLE:
3716 dData = SDDSin->parameter[i];
3717 SDDS_SwapDouble(dData);
3718 break;
3719 case SDDS_FLOAT:
3720 fData = SDDSin->parameter[i];
3721 SDDS_SwapFloat(fData);
3722 break;
3723 default:
3724 break;
3725 }
3726 }
3727 return (1);
3728}
3729
3730/**
3731 * @brief Swaps the endianness of the array data in an SDDS dataset.
3732 *
3733 * This function iterates through all arrays defined in the specified SDDS dataset and swaps the byte order
3734 * of each element to match the system's native endianness. It supports various data types including
3735 * short, unsigned short, long, unsigned long, long long, unsigned long long, float, double, and long double.
3736 * The function ensures that binary data is correctly interpreted on systems with different byte orders.
3737 *
3738 * @param[in,out] SDDSin Pointer to the SDDS_DATASET structure representing the dataset whose
3739 * array data endianness is to be swapped.
3740 *
3741 * @return int32_t Always returns 1.
3742 * @retval 1 The endianness of all applicable array data elements was successfully swapped.
3743 *
3744 * @note This function modifies the dataset's array data in place. It should be called only when
3745 * the dataset's byte order is known to differ from the system's native byte order.
3746 */
3748 int32_t i, j;
3749 SDDS_LAYOUT *layout;
3750 short *sData;
3751 unsigned short *suData;
3752 int32_t *lData;
3753 uint32_t *luData;
3754 int64_t *lData64;
3755 uint64_t *luData64;
3756 float *fData;
3757 double *dData;
3758 long double *ldData;
3759
3760 layout = &SDDSin->layout;
3761
3762 for (i = 0; i < layout->n_arrays; i++) {
3763 switch (layout->array_definition[i].type) {
3764 case SDDS_SHORT:
3765 sData = SDDSin->array[i].data;
3766 for (j = 0; j < SDDSin->array[i].elements; j++)
3767 SDDS_SwapShort(sData + j);
3768 break;
3769 case SDDS_USHORT:
3770 suData = SDDSin->array[i].data;
3771 for (j = 0; j < SDDSin->array[i].elements; j++)
3772 SDDS_SwapUShort(suData + j);
3773 break;
3774 case SDDS_LONG:
3775 lData = SDDSin->array[i].data;
3776 for (j = 0; j < SDDSin->array[i].elements; j++)
3777 SDDS_SwapLong(lData + j);
3778 break;
3779 case SDDS_ULONG:
3780 luData = SDDSin->array[i].data;
3781 for (j = 0; j < SDDSin->array[i].elements; j++)
3782 SDDS_SwapULong(luData + j);
3783 break;
3784 case SDDS_LONG64:
3785 lData64 = SDDSin->array[i].data;
3786 for (j = 0; j < SDDSin->array[i].elements; j++)
3787 SDDS_SwapLong64(lData64 + j);
3788 break;
3789 case SDDS_ULONG64:
3790 luData64 = SDDSin->array[i].data;
3791 for (j = 0; j < SDDSin->array[i].elements; j++)
3792 SDDS_SwapULong64(luData64 + j);
3793 break;
3794 case SDDS_LONGDOUBLE:
3795 ldData = SDDSin->array[i].data;
3796 for (j = 0; j < SDDSin->array[i].elements; j++)
3797 SDDS_SwapLongDouble(ldData + j);
3798 break;
3799 case SDDS_DOUBLE:
3800 dData = SDDSin->array[i].data;
3801 for (j = 0; j < SDDSin->array[i].elements; j++)
3802 SDDS_SwapDouble(dData + j);
3803 break;
3804 case SDDS_FLOAT:
3805 fData = SDDSin->array[i].data;
3806 for (j = 0; j < SDDSin->array[i].elements; j++)
3807 SDDS_SwapFloat(fData + j);
3808 break;
3809 default:
3810 break;
3811 }
3812 }
3813 return (1);
3814}
3815
3816/**
3817 * @brief Swaps the endianness of a short integer.
3818 *
3819 * This function swaps the byte order of a 16-bit short integer pointed to by the provided data pointer.
3820 * It effectively converts the data between little-endian and big-endian formats.
3821 *
3822 * @param[in,out] data Pointer to the short integer whose byte order is to be swapped.
3823 *
3824 * @note The function modifies the data in place. Ensure that the pointer is valid and points to a
3825 * properly aligned 16-bit short integer.
3826 */
3827void SDDS_SwapShort(short *data) {
3828 unsigned char c1;
3829 c1 = *((char *)data);
3830 *((char *)data) = *(((char *)data) + 1);
3831 *(((char *)data) + 1) = c1;
3832}
3833
3834/**
3835 * @brief Swaps the endianness of an unsigned short integer.
3836 *
3837 * This function swaps the byte order of a 16-bit unsigned short integer pointed to by the provided data pointer.
3838 * It effectively converts the data between little-endian and big-endian formats.
3839 *
3840 * @param[in,out] data Pointer to the unsigned short integer whose byte order is to be swapped.
3841 *
3842 * @note The function modifies the data in place. Ensure that the pointer is valid and points to a
3843 * properly aligned 16-bit unsigned short integer.
3844 */
3845void SDDS_SwapUShort(unsigned short *data) {
3846 unsigned char c1;
3847 c1 = *((char *)data);
3848 *((char *)data) = *(((char *)data) + 1);
3849 *(((char *)data) + 1) = c1;
3850}
3851
3852/**
3853 * @brief Swaps the endianness of a 32-bit integer.
3854 *
3855 * This function swaps the byte order of a 32-bit integer pointed to by the provided data pointer.
3856 * It effectively converts the data between little-endian and big-endian formats.
3857 *
3858 * @param[in,out] data Pointer to the 32-bit integer whose byte order is to be swapped.
3859 *
3860 * @note The function modifies the data in place. Ensure that the pointer is valid and points to a
3861 * properly aligned 32-bit integer.
3862 */
3863void SDDS_SwapLong(int32_t *data) {
3864 int32_t copy;
3865 short i, j;
3866 copy = *data;
3867 for (i = 0, j = 3; i < 4; i++, j--)
3868 *(((char *)data) + i) = *(((char *)&copy) + j);
3869}
3870
3871/**
3872 * @brief Swaps the endianness of a 32-bit unsigned integer.
3873 *
3874 * This function swaps the byte order of a 32-bit unsigned integer pointed to by the provided data pointer.
3875 * It effectively converts the data between little-endian and big-endian formats.
3876 *
3877 * @param[in,out] data Pointer to the 32-bit unsigned integer whose byte order is to be swapped.
3878 *
3879 * @note The function modifies the data in place. Ensure that the pointer is valid and points to a
3880 * properly aligned 32-bit unsigned integer.
3881 */
3882void SDDS_SwapULong(uint32_t *data) {
3883 uint32_t copy;
3884 short i, j;
3885 copy = *data;
3886 for (i = 0, j = 3; i < 4; i++, j--)
3887 *(((char *)data) + i) = *(((char *)&copy) + j);
3888}
3889
3890/**
3891 * @brief Swaps the endianness of a 64-bit integer.
3892 *
3893 * This function swaps the byte order of a 64-bit integer pointed to by the provided data pointer.
3894 * It effectively converts the data between little-endian and big-endian formats.
3895 *
3896 * @param[in,out] data Pointer to the 64-bit integer whose byte order is to be swapped.
3897 *
3898 * @note The function modifies the data in place. Ensure that the pointer is valid and points to a
3899 * properly aligned 64-bit integer.
3900 */
3901void SDDS_SwapLong64(int64_t *data) {
3902 int64_t copy;
3903 short i, j;
3904 copy = *data;
3905 for (i = 0, j = 7; i < 8; i++, j--)
3906 *(((char *)data) + i) = *(((char *)&copy) + j);
3907}
3908
3909/**
3910 * @brief Swaps the endianness of a 64-bit unsigned integer.
3911 *
3912 * This function swaps the byte order of a 64-bit unsigned integer pointed to by the provided data pointer.
3913 * It effectively converts the data between little-endian and big-endian formats.
3914 *
3915 * @param[in,out] data Pointer to the 64-bit unsigned integer whose byte order is to be swapped.
3916 *
3917 * @note The function modifies the data in place. Ensure that the pointer is valid and points to a
3918 * properly aligned 64-bit unsigned integer.
3919 */
3920void SDDS_SwapULong64(uint64_t *data) {
3921 uint64_t copy;
3922 short i, j;
3923 copy = *data;
3924 for (i = 0, j = 7; i < 8; i++, j--)
3925 *(((char *)data) + i) = *(((char *)&copy) + j);
3926}
3927
3928/**
3929 * @brief Swaps the endianness of a float.
3930 *
3931 * This function swaps the byte order of a 32-bit floating-point number pointed to by the provided data pointer.
3932 * It effectively converts the data between little-endian and big-endian formats.
3933 *
3934 * @param[in,out] data Pointer to the float whose byte order is to be swapped.
3935 *
3936 * @note The function modifies the data in place. Ensure that the pointer is valid and points to a
3937 * properly aligned float.
3938 */
3939void SDDS_SwapFloat(float *data) {
3940 float copy;
3941 short i, j;
3942 copy = *data;
3943 for (i = 0, j = 3; i < 4; i++, j--)
3944 *(((char *)data) + i) = *(((char *)&copy) + j);
3945}
3946
3947/**
3948 * @brief Swaps the endianness of a double.
3949 *
3950 * This function swaps the byte order of a 64-bit double-precision floating-point number pointed to by the
3951 * provided data pointer. It effectively converts the data between little-endian and big-endian formats.
3952 *
3953 * @param[in,out] data Pointer to the double whose byte order is to be swapped.
3954 *
3955 * @note The function modifies the data in place. Ensure that the pointer is valid and points to a
3956 * properly aligned double.
3957 */
3958void SDDS_SwapDouble(double *data) {
3959 double copy;
3960 short i, j;
3961 copy = *data;
3962 for (i = 0, j = 7; i < 8; i++, j--)
3963 *(((char *)data) + i) = *(((char *)&copy) + j);
3964}
3965
3966/**
3967 * @brief Swaps the endianness of a long double.
3968 *
3969 * This function swaps the byte order of a long double floating-point number pointed to by the provided data pointer.
3970 * It effectively converts the data between little-endian and big-endian formats. The function accounts for
3971 * different sizes of long double based on the system's architecture.
3972 *
3973 * @param[in,out] data Pointer to the long double whose byte order is to be swapped.
3974 *
3975 * @note The function modifies the data in place. Ensure that the pointer is valid and points to a
3976 * properly aligned long double. The size of long double may vary between different systems.
3977 */
3978void SDDS_SwapLongDouble(long double *data) {
3979 long double copy;
3980 short i, j;
3981 copy = *data;
3982 if (LDBL_DIG == 18) {
3983 for (i = 0, j = 11; i < 12; i++, j--)
3984 *(((char *)data) + i) = *(((char *)&copy) + j);
3985 } else {
3986 for (i = 0, j = 7; i < 8; i++, j--)
3987 *(((char *)data) + i) = *(((char *)&copy) + j);
3988 }
3989}
3990
3991/**
3992 * @brief Reads a non-native endian page from an SDDS dataset.
3993 *
3994 * This function reads a page of data from the specified SDDS dataset, handling data with non-native
3995 * endianness. It supports both ASCII and binary data modes, performing necessary byte order
3996 * conversions to ensure correct data interpretation on the host system.
3997 *
3998 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
3999 *
4000 * @return int32_t Returns the number of rows read on success, or 0 on failure.
4001 * @retval >0 Number of rows successfully read.
4002 * @retval 0 An error occurred during the read operation, such as I/O failures, data corruption,
4003 * or unsupported data modes.
4004 *
4005 * @note This function is a wrapper for SDDS_ReadNonNativePageDetailed with default parameters.
4006 * It should be used when no specific mode, sparse interval, or offset is required.
4007 */
4008int32_t SDDS_ReadNonNativePage(SDDS_DATASET *SDDS_dataset) {
4009 return SDDS_ReadNonNativePageDetailed(SDDS_dataset, 0, 1, 0, 0);
4010}
4011/**
4012 * @brief Reads a sparse non-native endian page from an SDDS dataset.
4013 *
4014 * This function reads a sparse page of data from the specified SDDS dataset, handling data with non-native
4015 * endianness. Sparse reading allows for selective row retrieval based on the provided interval and offset.
4016 *
4017 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
4018 * @param[in] mode Mode flag to support future expansion.
4019 * @param[in] sparse_interval Interval between rows to be read for sparsity.
4020 * @param[in] sparse_offset Offset to start reading rows for sparsity.
4021 *
4022 * @return int32_t Returns the number of rows read on success, or 0 on failure.
4023 * @retval >0 Number of rows successfully read.
4024 * @retval 0 An error occurred during the read operation, such as I/O failures, data corruption,
4025 * or unsupported data modes.
4026 *
4027 * @note This function is a wrapper for SDDS_ReadNonNativePageDetailed with specific parameters
4028 * to enable sparse reading. It should be used when selective row retrieval is desired.
4029 */
4030int32_t SDDS_ReadNonNativePageSparse(SDDS_DATASET *SDDS_dataset, uint32_t mode, int64_t sparse_interval, int64_t sparse_offset) {
4031 return SDDS_ReadNonNativePageDetailed(SDDS_dataset, mode, sparse_interval, sparse_offset, 0);
4032}
4033
4034/**
4035 * @brief Reads a detailed non-native endian page from an SDDS dataset.
4036 *
4037 * This function reads a page of data from the specified SDDS dataset, handling data with non-native
4038 * endianness. It supports both ASCII and binary data modes, performing necessary byte order
4039 * conversions to ensure correct data interpretation on the host system. Additionally, it allows
4040 * for sparse reading and reading of the last few rows based on the provided parameters.
4041 *
4042 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
4043 * @param[in] mode Mode flag to support future expansion.
4044 * @param[in] sparse_interval Interval between rows to be read for sparsity.
4045 * @param[in] sparse_offset Offset to start reading rows for sparsity.
4046 * @param[in] last_rows Number of last rows to read from the dataset.
4047 *
4048 * @return int32_t Returns the number of rows read on success, or 0 on failure.
4049 * @retval >0 Number of rows successfully read.
4050 * @retval 0 An error occurred during the read operation, such as I/O failures, data corruption,
4051 * or unsupported data modes.
4052 *
4053 * @note This function handles various compression formats, including uncompressed, LZMA-compressed,
4054 * and GZIP-compressed files. It manages memory allocation for parameters, arrays, and columns,
4055 * ensuring that data is correctly stored and byte-swapped as necessary.
4056 */
4057int32_t SDDS_ReadNonNativePageDetailed(SDDS_DATASET *SDDS_dataset, uint32_t mode, int64_t sparse_interval, int64_t sparse_offset, int64_t last_rows)
4058/* the mode argument is to support future expansion */
4059{
4060 int32_t retval;
4061 /* SDDS_LAYOUT layout_copy; */
4062
4063 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReadNonNativePageDetailed"))
4064 return (0);
4065 if (SDDS_dataset->layout.disconnected) {
4066 SDDS_SetError("Can't read page--file is disconnected (SDDS_ReadNonNativePageDetailed)");
4067 return 0;
4068 }
4069#if defined(zLib)
4070 if (SDDS_dataset->layout.gzipFile) {
4071 if (!SDDS_dataset->layout.gzfp) {
4072 SDDS_SetError("Unable to read page--NULL file pointer (SDDS_ReadNonNativePageDetailed)");
4073 return (0);
4074 }
4075 } else {
4076#endif
4077 if (SDDS_dataset->layout.lzmaFile) {
4078 if (!SDDS_dataset->layout.lzmafp) {
4079 SDDS_SetError("Unable to read page--NULL file pointer (SDDS_ReadNonNativePageDetailed)");
4080 return (0);
4081 }
4082 } else {
4083 if (!SDDS_dataset->layout.fp) {
4084 SDDS_SetError("Unable to read page--NULL file pointer (SDDS_ReadNonNativePageDetailed)");
4085 return (0);
4086 }
4087 }
4088#if defined(zLib)
4089 }
4090#endif
4091 if (SDDS_dataset->original_layout.data_mode.mode == SDDS_ASCII) {
4092 if ((retval = SDDS_ReadAsciiPage(SDDS_dataset, sparse_interval, sparse_offset, 0)) < 1) {
4093 return (retval);
4094 }
4095 } else if (SDDS_dataset->original_layout.data_mode.mode == SDDS_BINARY) {
4096 if ((retval = SDDS_ReadNonNativeBinaryPage(SDDS_dataset, sparse_interval, sparse_offset)) < 1) {
4097 return (retval);
4098 }
4099 } else {
4100 SDDS_SetError("Unable to read page--unrecognized data mode (SDDS_ReadNonNativePageDetailed)");
4101 return (0);
4102 }
4103 return (retval);
4104}
4105
4106/**
4107 * @brief Reads the last few rows from a non-native endian page in an SDDS dataset.
4108 *
4109 * This function reads the specified number of last rows from the non-native endian page of the
4110 * given SDDS dataset. It handles data with non-native endianness, performing necessary byte order
4111 * conversions to ensure correct data interpretation on the host system.
4112 *
4113 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
4114 * @param[in] last_rows Number of last rows to read from the dataset.
4115 *
4116 * @return int32_t Returns the number of rows read on success, or 0 on failure.
4117 * @retval >0 Number of rows successfully read.
4118 * @retval 0 An error occurred during the read operation, such as I/O failures, data corruption,
4119 * or unsupported data modes.
4120 *
4121 * @note This function is a wrapper for SDDS_ReadNonNativePageDetailed with specific parameters
4122 * to read the last few rows. It should be used when only the most recent rows are needed.
4123 */
4124int32_t SDDS_ReadNonNativePageLastRows(SDDS_DATASET *SDDS_dataset, int64_t last_rows) {
4125 int32_t retval;
4126 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReadNonNativePageLastRows"))
4127 return (0);
4128 if (SDDS_dataset->layout.disconnected) {
4129 SDDS_SetError("Can't read page--file is disconnected (SDDS_ReadNonNativePageLastRows)");
4130 return 0;
4131 }
4132#if defined(zLib)
4133 if (SDDS_dataset->layout.gzipFile) {
4134 if (!SDDS_dataset->layout.gzfp) {
4135 SDDS_SetError("Unable to read page--NULL file pointer (SDDS_ReadNonNativePageLastRows)");
4136 return (0);
4137 }
4138 } else {
4139#endif
4140 if (SDDS_dataset->layout.lzmaFile) {
4141 if (!SDDS_dataset->layout.lzmafp) {
4142 SDDS_SetError("Unable to read page--NULL file pointer (SDDS_ReadNonNativePageLastRows)");
4143 return (0);
4144 }
4145 } else {
4146 if (!SDDS_dataset->layout.fp) {
4147 SDDS_SetError("Unable to read page--NULL file pointer (SDDS_ReadNonNativePageLastRows)");
4148 return (0);
4149 }
4150 }
4151#if defined(zLib)
4152 }
4153#endif
4154 if (SDDS_dataset->original_layout.data_mode.mode == SDDS_ASCII) {
4155 if ((retval = SDDS_ReadAsciiPageLastRows(SDDS_dataset, last_rows)) < 1) {
4156 return (retval);
4157 }
4158 } else if (SDDS_dataset->original_layout.data_mode.mode == SDDS_BINARY) {
4159 if ((retval = SDDS_ReadNonNativeBinaryPageLastRows(SDDS_dataset, last_rows)) < 1) {
4160 return (retval);
4161 }
4162 } else {
4163 SDDS_SetError("Unable to read page--unrecognized data mode (SDDS_ReadNonNativePageLastRows)");
4164 return (0);
4165 }
4166 return (retval);
4167}
4168
4169/**
4170 * @brief Reads a non-native endian binary page from an SDDS dataset.
4171 *
4172 * This function reads a binary page from the specified SDDS dataset, handling data with non-native
4173 * endianness. It performs necessary byte order conversions to ensure correct data interpretation on
4174 * the host system. The function supports sparse reading based on the provided interval and offset.
4175 *
4176 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
4177 * @param[in] sparse_interval Interval between rows to be read for sparsity.
4178 * @param[in] sparse_offset Offset to start reading rows for sparsity.
4179 *
4180 * @return int32_t Returns the number of rows read on success, or 0 on failure.
4181 * @retval >0 Number of rows successfully read.
4182 * @retval 0 An error occurred during the read operation, such as I/O failures, data corruption,
4183 * or unsupported data modes.
4184 *
4185 * @note This function is a wrapper for SDDS_ReadNonNativeBinaryPageDetailed with specific parameters.
4186 */
4187int32_t SDDS_ReadNonNativeBinaryPage(SDDS_DATASET *SDDS_dataset, int64_t sparse_interval, int64_t sparse_offset) {
4188 return SDDS_ReadNonNativeBinaryPageDetailed(SDDS_dataset, sparse_interval, sparse_offset, 0);
4189}
4190
4191/**
4192 * @brief Reads the last few rows from a non-native endian binary page in an SDDS dataset.
4193 *
4194 * This function reads the specified number of last rows from a binary page in the given SDDS dataset,
4195 * handling data with non-native endianness. It performs necessary byte order conversions to ensure
4196 * correct data interpretation on the host system.
4197 *
4198 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
4199 * @param[in] last_rows Number of last rows to read from the dataset.
4200 *
4201 * @return int32_t Returns the number of rows read on success, or 0 on failure.
4202 * @retval >0 Number of rows successfully read.
4203 * @retval 0 An error occurred during the read operation, such as I/O failures, data corruption,
4204 * or unsupported data modes.
4205 *
4206 * @note This function is a wrapper for SDDS_ReadNonNativeBinaryPageDetailed with specific parameters
4207 * to read the last few rows. It should be used when only the most recent rows are needed.
4208 */
4209int32_t SDDS_ReadNonNativeBinaryPageLastRows(SDDS_DATASET *SDDS_dataset, int64_t last_rows) {
4210 return SDDS_ReadNonNativeBinaryPageDetailed(SDDS_dataset, 1, 0, last_rows);
4211}
4212
4213/**
4214 * @brief Reads a detailed non-native endian binary page from an SDDS dataset.
4215 *
4216 * This function reads a binary page from the specified SDDS dataset, handling data with non-native
4217 * endianness. It supports both sparse reading and reading of the last few rows based on the provided
4218 * parameters. The function performs necessary byte order conversions to ensure correct data interpretation
4219 * on the host system.
4220 *
4221 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
4222 * @param[in] sparse_interval Interval between rows to be read for sparsity.
4223 * @param[in] sparse_offset Offset to start reading rows for sparsity.
4224 * @param[in] last_rows Number of last rows to read from the dataset.
4225 *
4226 * @return int32_t Returns the page number on success, or 0 on failure.
4227 * @retval >0 Page number successfully read.
4228 * @retval 0 An error occurred during the read operation, such as I/O failures, data corruption,
4229 * or unsupported data modes.
4230 *
4231 * @note This function handles various compression formats, including uncompressed, LZMA-compressed,
4232 * and GZIP-compressed files. It manages memory allocation for parameters, arrays, and columns,
4233 * ensuring that data is correctly stored and byte-swapped as necessary.
4234 * The function also updates the dataset's row count and handles auto-recovery in case of errors.
4235 */
4236int32_t SDDS_ReadNonNativeBinaryPageDetailed(SDDS_DATASET *SDDS_dataset, int64_t sparse_interval, int64_t sparse_offset, int64_t last_rows) {
4237 int32_t n_rows32 = 0;
4238 int64_t n_rows, j, k, alloc_rows, rows_to_store, mod;
4239 /* int32_t page_number, i; */
4240#if defined(zLib)
4241 gzFile gzfp = NULL;
4242#endif
4243 FILE *fp = NULL;
4244 struct lzmafile *lzmafp = NULL;
4245 SDDS_FILEBUFFER *fBuffer;
4246
4247 /* static char s[SDDS_MAXLINE]; */
4248 n_rows = 0;
4249 SDDS_SetReadRecoveryMode(SDDS_dataset, 0);
4250#if defined(zLib)
4251 if (SDDS_dataset->layout.gzipFile) {
4252 gzfp = SDDS_dataset->layout.gzfp;
4253 } else {
4254#endif
4255 if (SDDS_dataset->layout.lzmaFile) {
4256 lzmafp = SDDS_dataset->layout.lzmafp;
4257 } else {
4258 fp = SDDS_dataset->layout.fp;
4259 }
4260#if defined(zLib)
4261 }
4262#endif
4263 fBuffer = &SDDS_dataset->fBuffer;
4264 if (!fBuffer->buffer) {
4265 if (!(fBuffer->buffer = fBuffer->data = SDDS_Malloc(sizeof(char) * defaultIOBufferSize))) {
4266 SDDS_SetError("Unable to do buffered read--allocation failure");
4267 return 0;
4268 }
4269 fBuffer->bufferSize = defaultIOBufferSize;
4270 fBuffer->bytesLeft = 0;
4271 }
4272 SDDS_dataset->rowcount_offset = -1;
4273#if defined(zLib)
4274 if (SDDS_dataset->layout.gzipFile) {
4275 if (!SDDS_GZipBufferedRead(&n_rows32, sizeof(n_rows32), gzfp, &SDDS_dataset->fBuffer, SDDS_LONG, SDDS_dataset->layout.byteOrderDeclared)) {
4276 if (gzeof(gzfp))
4277 return (SDDS_dataset->page_number = -1);
4278 SDDS_SetError("Unable to read page--failure reading number of rows (SDDS_ReadNonNativeBinaryPage)");
4279 return (0);
4280 }
4281 SDDS_SwapLong(&n_rows32);
4282 if (n_rows32 == INT32_MIN) {
4283 if (!SDDS_GZipBufferedRead(&n_rows, sizeof(n_rows), gzfp, &SDDS_dataset->fBuffer, SDDS_LONG64, SDDS_dataset->layout.byteOrderDeclared)) {
4284 if (gzeof(gzfp))
4285 return (SDDS_dataset->page_number = -1);
4286 SDDS_SetError("Unable to read page--failure reading number of rows (SDDS_ReadNonNativeBinaryPage)");
4287 return (0);
4288 }
4289 SDDS_SwapLong64(&n_rows);
4290 } else {
4291 n_rows = n_rows32;
4292 }
4293 } else {
4294#endif
4295 /* This value will only be valid if read buffering is turned off, which is done for
4296 * certain append operations! Should really modify SDDS_BufferedRead and SDDS_BufferedWrite
4297 * to provide ftell capability.
4298 */
4299 if (SDDS_dataset->layout.lzmaFile) {
4300 if (!SDDS_LZMABufferedRead(&n_rows32, sizeof(n_rows32), lzmafp, &SDDS_dataset->fBuffer, SDDS_LONG, SDDS_dataset->layout.byteOrderDeclared)) {
4301 if (lzma_eof(lzmafp))
4302 return (SDDS_dataset->page_number = -1);
4303 SDDS_SetError("Unable to read page--failure reading number of rows (SDDS_ReadNonNativeBinaryPage)");
4304 return (0);
4305 }
4306 SDDS_SwapLong(&n_rows32);
4307 if (n_rows32 == INT32_MIN) {
4308 if (!SDDS_LZMABufferedRead(&n_rows, sizeof(n_rows), lzmafp, &SDDS_dataset->fBuffer, SDDS_LONG64, SDDS_dataset->layout.byteOrderDeclared)) {
4309 if (lzma_eof(lzmafp))
4310 return (SDDS_dataset->page_number = -1);
4311 SDDS_SetError("Unable to read page--failure reading number of rows (SDDS_ReadNonNativeBinaryPage)");
4312 return (0);
4313 }
4314 SDDS_SwapLong64(&n_rows);
4315 } else {
4316 n_rows = n_rows32;
4317 }
4318 } else {
4319 SDDS_dataset->rowcount_offset = ftell(fp);
4320 if (!SDDS_BufferedRead(&n_rows32, sizeof(n_rows32), fp, &SDDS_dataset->fBuffer, SDDS_LONG, SDDS_dataset->layout.byteOrderDeclared)) {
4321 if (feof(fp))
4322 return (SDDS_dataset->page_number = -1);
4323 SDDS_SetError("Unable to read page--failure reading number of rows (SDDS_ReadNonNativeBinaryPage)");
4324 return (0);
4325 }
4326 SDDS_SwapLong(&n_rows32);
4327 if (n_rows32 == INT32_MIN) {
4328 if (!SDDS_BufferedRead(&n_rows, sizeof(n_rows), fp, &SDDS_dataset->fBuffer, SDDS_LONG64, SDDS_dataset->layout.byteOrderDeclared)) {
4329 if (feof(fp))
4330 return (SDDS_dataset->page_number = -1);
4331 SDDS_SetError("Unable to read page--failure reading number of rows (SDDS_ReadNonNativeBinaryPage)");
4332 return (0);
4333 }
4334 SDDS_SwapLong64(&n_rows);
4335 } else {
4336 n_rows = n_rows32;
4337 }
4338 }
4339#if defined(zLib)
4340 }
4341#endif
4342 if (n_rows < 0) {
4343 SDDS_SetError("Unable to read page--negative number of rows (SDDS_ReadNonNativeBinaryPage)");
4344 return (0);
4345 }
4346 if (last_rows < 0)
4347 last_rows = 0;
4348 /* Fix this limitation later */
4349 if (SDDS_dataset->layout.data_mode.column_major) {
4350 sparse_interval = 1;
4351 sparse_offset = 0;
4352 last_rows = 0;
4353 }
4354 if (last_rows) {
4355 sparse_interval = 1;
4356 sparse_offset = n_rows - last_rows;
4357 rows_to_store = last_rows + 2;
4358 alloc_rows = rows_to_store - SDDS_dataset->n_rows_allocated;
4359 }
4360 if (sparse_interval <= 0)
4361 sparse_interval = 1;
4362 if (sparse_offset < 0)
4363 sparse_offset = 0;
4364
4365 rows_to_store = (n_rows - sparse_offset) / sparse_interval + 2;
4366 alloc_rows = rows_to_store - SDDS_dataset->n_rows_allocated;
4367 if (!SDDS_StartPage(SDDS_dataset, 0) || !SDDS_LengthenTable(SDDS_dataset, alloc_rows)) {
4368 SDDS_SetError("Unable to read page--couldn't start page (SDDS_ReadNonNativeBinaryPage)");
4369 return (0);
4370 }
4371
4372 /* read the parameter values */
4373 if (!SDDS_ReadNonNativeBinaryParameters(SDDS_dataset)) {
4374 SDDS_SetError("Unable to read page--parameter reading error (SDDS_ReadNonNativeBinaryPage)");
4375 return (0);
4376 }
4377
4378 /* read the array values */
4379 if (!SDDS_ReadNonNativeBinaryArrays(SDDS_dataset)) {
4380 SDDS_SetError("Unable to read page--array reading error (SDDS_ReadNonNativeBinaryPage)");
4381 return (0);
4382 }
4383 if (SDDS_dataset->layout.data_mode.column_major) {
4384 SDDS_dataset->n_rows = n_rows;
4385 if (!SDDS_ReadNonNativeBinaryColumns(SDDS_dataset)) {
4386 SDDS_SetError("Unable to read page--column reading error (SDDS_ReadNonNativeBinaryPage)");
4387 return (0);
4388 }
4389 SDDS_SwapEndsColumnData(SDDS_dataset);
4390 return (SDDS_dataset->page_number);
4391 }
4392 if ((sparse_interval <= 1) && (sparse_offset == 0)) {
4393 for (j = 0; j < n_rows; j++) {
4394 if (!SDDS_ReadNonNativeBinaryRow(SDDS_dataset, j, 0)) {
4395 SDDS_dataset->n_rows = j - 1;
4396 if (SDDS_dataset->autoRecover) {
4398 SDDS_SwapEndsColumnData(SDDS_dataset);
4399 return (SDDS_dataset->page_number);
4400 }
4401 SDDS_SetError("Unable to read page--error reading data row (SDDS_ReadNonNativeBinaryPage)");
4402 SDDS_SetReadRecoveryMode(SDDS_dataset, 1);
4403 return (0);
4404 }
4405 }
4406 SDDS_dataset->n_rows = j;
4407 SDDS_SwapEndsColumnData(SDDS_dataset);
4408 return (SDDS_dataset->page_number);
4409 } else {
4410 for (j = 0; j < sparse_offset; j++) {
4411 if (!SDDS_ReadNonNativeBinaryRow(SDDS_dataset, 0, 1)) {
4412 SDDS_dataset->n_rows = 0;
4413 if (SDDS_dataset->autoRecover) {
4415 SDDS_SwapEndsColumnData(SDDS_dataset);
4416 return (SDDS_dataset->page_number);
4417 }
4418 SDDS_SetError("Unable to read page--error reading data row (SDDS_ReadNonNativeBinaryPage)");
4419 SDDS_SetReadRecoveryMode(SDDS_dataset, 1);
4420 return (0);
4421 }
4422 }
4423 n_rows -= sparse_offset;
4424 for (j = k = 0; j < n_rows; j++) {
4425 if (!SDDS_ReadNonNativeBinaryRow(SDDS_dataset, k, mod = j % sparse_interval)) {
4426 SDDS_dataset->n_rows = k - 1;
4427 if (SDDS_dataset->autoRecover) {
4429 SDDS_SwapEndsColumnData(SDDS_dataset);
4430 return (SDDS_dataset->page_number);
4431 }
4432 SDDS_SetError("Unable to read page--error reading data row (SDDS_ReadNonNativeBinaryPage)");
4433 SDDS_SetReadRecoveryMode(SDDS_dataset, 1);
4434 return (0);
4435 }
4436 k += mod ? 0 : 1;
4437 }
4438 SDDS_dataset->n_rows = k;
4439 SDDS_SwapEndsColumnData(SDDS_dataset);
4440 return (SDDS_dataset->page_number);
4441 }
4442}
4443
4444/**
4445 * @brief Reads non-native endian binary parameters from an SDDS dataset.
4446 *
4447 * This function iterates through all parameter definitions in the specified SDDS dataset and reads their
4448 * binary data from the underlying file. It handles various data types, including short, unsigned short,
4449 * long, unsigned long, long long, unsigned long long, float, double, and long double. For string
4450 * parameters, it reads each string individually, ensuring proper memory allocation and byte order
4451 * conversion. Parameters with fixed values are processed by scanning the fixed value strings into
4452 * the appropriate data types. The function supports different compression formats, including uncompressed,
4453 * LZMA-compressed, and GZIP-compressed files.
4454 *
4455 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
4456 *
4457 * @return int32_t Returns 1 on successful reading and byte-swapping of all parameters, or 0 if an error occurred.
4458 * @retval 1 All non-native endian parameters were successfully read and byte-swapped.
4459 * @retval 0 An error occurred during the read or byte-swapping process, such as I/O failures, memory allocation issues,
4460 * or corrupted parameter definitions.
4461 *
4462 * @note This function modifies the dataset's parameter data in place. It should be called after successfully opening
4463 * and preparing the dataset for reading. Ensure that the dataset structure is properly initialized to prevent
4464 * undefined behavior.
4465 */
4467 int32_t i;
4468 SDDS_LAYOUT *layout;
4469 /* char *predefined_format; */
4470 char buffer[SDDS_MAXLINE];
4471#if defined(zLib)
4472 gzFile gzfp = NULL;
4473#endif
4474 FILE *fp = NULL;
4475 struct lzmafile *lzmafp = NULL;
4476 SDDS_FILEBUFFER *fBuffer;
4477
4478 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReadNonNativeBinaryParameters"))
4479 return (0);
4480 layout = &SDDS_dataset->layout;
4481 if (!layout->n_parameters)
4482 return (1);
4483#if defined(zLib)
4484 if (SDDS_dataset->layout.gzipFile) {
4485 gzfp = layout->gzfp;
4486 } else {
4487#endif
4488 if (SDDS_dataset->layout.lzmaFile) {
4489 lzmafp = layout->lzmafp;
4490 } else {
4491 fp = layout->fp;
4492 }
4493#if defined(zLib)
4494 }
4495#endif
4496 fBuffer = &SDDS_dataset->fBuffer;
4497 for (i = 0; i < layout->n_parameters; i++) {
4498 if (layout->parameter_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
4499 continue;
4500 if (layout->parameter_definition[i].fixed_value) {
4501 strcpy(buffer, layout->parameter_definition[i].fixed_value);
4502 if (!SDDS_ScanData(buffer, layout->parameter_definition[i].type, 0, SDDS_dataset->parameter[i], 0, 1)) {
4503 SDDS_SetError("Unable to read page--parameter scanning error (SDDS_ReadNonNativeBinaryParameters)");
4504 return (0);
4505 }
4506 } else if (layout->parameter_definition[i].type == SDDS_STRING) {
4507 if (*(char **)SDDS_dataset->parameter[i])
4508 free(*(char **)SDDS_dataset->parameter[i]);
4509#if defined(zLib)
4510 if (SDDS_dataset->layout.gzipFile) {
4511 if (!(*((char **)SDDS_dataset->parameter[i]) = SDDS_ReadNonNativeGZipBinaryString(gzfp, fBuffer, 0))) {
4512 SDDS_SetError("Unable to read parameters--failure reading string (SDDS_ReadNonNativeBinaryParameters)");
4513 return (0);
4514 }
4515 } else {
4516#endif
4517 if (SDDS_dataset->layout.lzmaFile) {
4518 if (!(*((char **)SDDS_dataset->parameter[i]) = SDDS_ReadNonNativeLZMABinaryString(lzmafp, fBuffer, 0))) {
4519 SDDS_SetError("Unable to read parameters--failure reading string (SDDS_ReadNonNativeBinaryParameters)");
4520 return (0);
4521 }
4522 } else {
4523 if (!(*((char **)SDDS_dataset->parameter[i]) = SDDS_ReadNonNativeBinaryString(fp, fBuffer, 0))) {
4524 SDDS_SetError("Unable to read parameters--failure reading string (SDDS_ReadNonNativeBinaryParameters)");
4525 return (0);
4526 }
4527 }
4528#if defined(zLib)
4529 }
4530#endif
4531 } else {
4532#if defined(zLib)
4533 if (SDDS_dataset->layout.gzipFile) {
4534 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)) {
4535 SDDS_SetError("Unable to read parameters--failure reading value (SDDS_ReadNonNativeBinaryParameters)");
4536 return (0);
4537 }
4538 } else {
4539#endif
4540 if (SDDS_dataset->layout.lzmaFile) {
4541 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)) {
4542 SDDS_SetError("Unable to read parameters--failure reading value (SDDS_ReadNonNativeBinaryParameters)");
4543 return (0);
4544 }
4545 } else {
4546 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)) {
4547 SDDS_SetError("Unable to read parameters--failure reading value (SDDS_ReadNonNativeBinaryParameters)");
4548 return (0);
4549 }
4550 }
4551#if defined(zLib)
4552 }
4553#endif
4554 }
4555 }
4556 SDDS_SwapEndsParameterData(SDDS_dataset);
4557 return (1);
4558}
4559
4560/**
4561 * @brief Reads non-native endian binary arrays from an SDDS dataset.
4562 *
4563 * This function iterates through all array definitions in the specified SDDS dataset and reads their
4564 * binary data from the underlying file. It handles various data types, including short, unsigned short,
4565 * long, unsigned long, long long, unsigned long long, float, double, and long double. For string
4566 * arrays, it reads each string individually, ensuring proper memory allocation and byte order conversion.
4567 * The function supports different compression formats, including uncompressed, LZMA-compressed, and
4568 * GZIP-compressed files. After reading, it swaps the endianness of the array data to match the system's
4569 * native byte order.
4570 *
4571 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
4572 *
4573 * @return int32_t Returns 1 on successful reading and byte-swapping of all arrays, or 0 if an error occurred.
4574 * @retval 1 All non-native endian arrays were successfully read and byte-swapped.
4575 * @retval 0 An error occurred during the read or byte-swapping process, such as I/O failures, memory allocation issues,
4576 * or corrupted array definitions.
4577 *
4578 * @note This function modifies the dataset's array data in place. It should be called after successfully opening
4579 * and preparing the dataset for reading. Ensure that the dataset structure is properly initialized to prevent
4580 * undefined behavior.
4581 */
4583 int32_t i, j;
4584 SDDS_LAYOUT *layout;
4585 /* char *predefined_format; */
4586 /* static char buffer[SDDS_MAXLINE]; */
4587#if defined(zLib)
4588 gzFile gzfp = NULL;
4589#endif
4590 FILE *fp = NULL;
4591 struct lzmafile *lzmafp = NULL;
4592 SDDS_ARRAY *array;
4593 SDDS_FILEBUFFER *fBuffer;
4594
4595 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReadNonNativeBinaryArrays"))
4596 return (0);
4597 layout = &SDDS_dataset->layout;
4598 if (!layout->n_arrays)
4599 return (1);
4600#if defined(zLib)
4601 if (SDDS_dataset->layout.gzipFile) {
4602 gzfp = layout->gzfp;
4603 } else {
4604#endif
4605 if (SDDS_dataset->layout.lzmaFile) {
4606 lzmafp = layout->lzmafp;
4607 } else {
4608 fp = layout->fp;
4609 }
4610#if defined(zLib)
4611 }
4612#endif
4613 fBuffer = &SDDS_dataset->fBuffer;
4614 if (!SDDS_dataset->array) {
4615 SDDS_SetError("Unable to read array--pointer to structure storage area is NULL (SDDS_ReadNonNativeBinaryArrays)");
4616 return (0);
4617 }
4618 for (i = 0; i < layout->n_arrays; i++) {
4619 array = SDDS_dataset->array + i;
4620 if (array->definition && !SDDS_FreeArrayDefinition(array->definition)) {
4621 SDDS_SetError("Unable to get array--array definition corrupted (SDDS_ReadNonNativeBinaryArrays)");
4622 return (0);
4623 }
4624 if (!SDDS_CopyArrayDefinition(&array->definition, layout->array_definition + i)) {
4625 SDDS_SetError("Unable to read array--definition copy failed (SDDS_ReadNonNativeBinaryArrays)");
4626 return (0);
4627 }
4628 /*if (array->dimension) free(array->dimension); */
4629 if (!(array->dimension = SDDS_Realloc(array->dimension, sizeof(*array->dimension) * array->definition->dimensions))) {
4630 SDDS_SetError("Unable to read array--allocation failure (SDDS_ReadNonNativeBinaryArrays)");
4631 return (0);
4632 }
4633#if defined(zLib)
4634 if (SDDS_dataset->layout.gzipFile) {
4635 if (!SDDS_GZipBufferedRead(array->dimension, sizeof(*array->dimension) * array->definition->dimensions, gzfp, fBuffer, SDDS_LONG, SDDS_dataset->layout.byteOrderDeclared)) {
4636 SDDS_SetError("Unable to read arrays--failure reading dimensions (SDDS_ReadNonNativeBinaryArrays)");
4637 return (0);
4638 }
4639 } else {
4640#endif
4641 if (SDDS_dataset->layout.lzmaFile) {
4642 if (!SDDS_LZMABufferedRead(array->dimension, sizeof(*array->dimension) * array->definition->dimensions, lzmafp, fBuffer, SDDS_LONG, SDDS_dataset->layout.byteOrderDeclared)) {
4643 SDDS_SetError("Unable to read arrays--failure reading dimensions (SDDS_ReadNonNativeBinaryArrays)");
4644 return (0);
4645 }
4646 } else {
4647 if (!SDDS_BufferedRead(array->dimension, sizeof(*array->dimension) * array->definition->dimensions, fp, fBuffer, SDDS_LONG, SDDS_dataset->layout.byteOrderDeclared)) {
4648 SDDS_SetError("Unable to read arrays--failure reading dimensions (SDDS_ReadNonNativeBinaryArrays)");
4649 return (0);
4650 }
4651 }
4652#if defined(zLib)
4653 }
4654#endif
4655 array->elements = 1;
4656 for (j = 0; j < array->definition->dimensions; j++) {
4657 SDDS_SwapLong(&(array->dimension[j]));
4658 array->elements *= array->dimension[j];
4659 }
4660 if (array->data)
4661 free(array->data);
4662 array->data = array->pointer = NULL;
4663 if (array->elements == 0)
4664 continue;
4665 if (array->elements < 0) {
4666 SDDS_SetError("Unable to read array--number of elements is negative (SDDS_ReadNonNativeBinaryArrays)");
4667 return (0);
4668 }
4669 if (!(array->data = SDDS_Realloc(array->data, array->elements * SDDS_type_size[array->definition->type - 1]))) {
4670 SDDS_SetError("Unable to read array--allocation failure (SDDS_ReadNonNativeBinaryArrays)");
4671 return (0);
4672 }
4673 if (array->definition->type == SDDS_STRING) {
4674#if defined(zLib)
4675 if (SDDS_dataset->layout.gzipFile) {
4676 for (j = 0; j < array->elements; j++) {
4677 if (!(((char **)(array->data))[j] = SDDS_ReadNonNativeGZipBinaryString(gzfp, fBuffer, 0))) {
4678 SDDS_SetError("Unable to read arrays--failure reading string (SDDS_ReadNonNativeBinaryArrays)");
4679 return (0);
4680 }
4681 }
4682 } else {
4683#endif
4684 if (SDDS_dataset->layout.lzmaFile) {
4685 for (j = 0; j < array->elements; j++) {
4686 if (!(((char **)(array->data))[j] = SDDS_ReadNonNativeLZMABinaryString(lzmafp, fBuffer, 0))) {
4687 SDDS_SetError("Unable to read arrays--failure reading string (SDDS_ReadNonNativeBinaryArrays)");
4688 return (0);
4689 }
4690 }
4691 } else {
4692 for (j = 0; j < array->elements; j++) {
4693 if (!(((char **)(array->data))[j] = SDDS_ReadNonNativeBinaryString(fp, fBuffer, 0))) {
4694 SDDS_SetError("Unable to read arrays--failure reading string (SDDS_ReadNonNativeBinaryArrays)");
4695 return (0);
4696 }
4697 }
4698 }
4699#if defined(zLib)
4700 }
4701#endif
4702 } else {
4703#if defined(zLib)
4704 if (SDDS_dataset->layout.gzipFile) {
4705 if (!SDDS_GZipBufferedRead(array->data, SDDS_type_size[array->definition->type - 1] * array->elements, gzfp, fBuffer, array->definition->type, SDDS_dataset->layout.byteOrderDeclared)) {
4706 SDDS_SetError("Unable to read arrays--failure reading values (SDDS_ReadNonNativeBinaryArrays)");
4707 return (0);
4708 }
4709 } else {
4710#endif
4711 if (SDDS_dataset->layout.lzmaFile) {
4712 if (!SDDS_LZMABufferedRead(array->data, SDDS_type_size[array->definition->type - 1] * array->elements, lzmafp, fBuffer, array->definition->type, SDDS_dataset->layout.byteOrderDeclared)) {
4713 SDDS_SetError("Unable to read arrays--failure reading values (SDDS_ReadNonNativeBinaryArrays)");
4714 return (0);
4715 }
4716 } else {
4717 if (!SDDS_BufferedRead(array->data, SDDS_type_size[array->definition->type - 1] * array->elements, fp, fBuffer, array->definition->type, SDDS_dataset->layout.byteOrderDeclared)) {
4718 SDDS_SetError("Unable to read arrays--failure reading values (SDDS_ReadNonNativeBinaryArrays)");
4719 return (0);
4720 }
4721 }
4722#if defined(zLib)
4723 }
4724#endif
4725 }
4726 }
4727 SDDS_SwapEndsArrayData(SDDS_dataset);
4728 return (1);
4729}
4730
4731/**
4732 * @brief Reads a non-native endian binary row from an SDDS dataset.
4733 *
4734 * This function reads a single row of data from the specified SDDS dataset, handling data with
4735 * non-native endianness. It iterates through all column definitions and reads each column's data
4736 * for the given row. For string columns, it ensures proper memory allocation and byte order conversion.
4737 * For other data types, it reads the binary data and performs necessary byte swapping. The function
4738 * supports different compression formats, including uncompressed, LZMA-compressed, and GZIP-compressed files.
4739 *
4740 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to read from.
4741 * @param[in] row The index of the row to read.
4742 * @param[in] skip If non-zero, the function will skip reading the row data, useful for sparse reading.
4743 *
4744 * @return int32_t Returns 1 on successful reading of the row, or 0 if an error occurred.
4745 * @retval 1 The row was successfully read and byte-swapped.
4746 * @retval 0 An error occurred during the read or byte-swapping process, such as I/O failures or corrupted data.
4747 *
4748 * @note This function modifies the dataset's data in place. It should be called after successfully
4749 * opening and preparing the dataset for reading. Ensure that the dataset structure is properly initialized
4750 * to prevent undefined behavior.
4751 */
4752int32_t SDDS_ReadNonNativeBinaryRow(SDDS_DATASET *SDDS_dataset, int64_t row, int32_t skip) {
4753 int64_t i, type, size;
4754 SDDS_LAYOUT *layout;
4755#if defined(zLib)
4756 gzFile gzfp;
4757#endif
4758 FILE *fp;
4759 struct lzmafile *lzmafp;
4760 SDDS_FILEBUFFER *fBuffer;
4761
4762 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReadNonNativeBinaryRow"))
4763 return (0);
4764 layout = &SDDS_dataset->layout;
4765 fBuffer = &SDDS_dataset->fBuffer;
4766
4767#if defined(zLib)
4768 if (SDDS_dataset->layout.gzipFile) {
4769 gzfp = layout->gzfp;
4770 for (i = 0; i < layout->n_columns; i++) {
4771 if (layout->column_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
4772 continue;
4773 if ((type = layout->column_definition[i].type) == SDDS_STRING) {
4774 if (!skip) {
4775 if (((char ***)SDDS_dataset->data)[i][row])
4776 free((((char ***)SDDS_dataset->data)[i][row]));
4777 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadNonNativeGZipBinaryString(gzfp, fBuffer, 0))) {
4778 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadNonNativeBinaryRow)");
4779 return (0);
4780 }
4781 } else {
4782 if (!SDDS_ReadNonNativeGZipBinaryString(gzfp, fBuffer, 1)) {
4783 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadNonNativeBinaryRow)");
4784 return 0;
4785 }
4786 }
4787 } else {
4788 size = SDDS_type_size[type - 1];
4789 if (!SDDS_GZipBufferedRead(skip ? NULL : (char *)SDDS_dataset->data[i] + row * size, size, gzfp, fBuffer, type, SDDS_dataset->layout.byteOrderDeclared)) {
4790 SDDS_SetError("Unable to read row--failure reading value (SDDS_ReadNonNativeBinaryRow)");
4791 return (0);
4792 }
4793 }
4794 }
4795 } else {
4796#endif
4797 if (SDDS_dataset->layout.lzmaFile) {
4798 lzmafp = layout->lzmafp;
4799 for (i = 0; i < layout->n_columns; i++) {
4800 if (layout->column_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
4801 continue;
4802 if ((type = layout->column_definition[i].type) == SDDS_STRING) {
4803 if (!skip) {
4804 if (((char ***)SDDS_dataset->data)[i][row])
4805 free((((char ***)SDDS_dataset->data)[i][row]));
4806 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadNonNativeLZMABinaryString(lzmafp, fBuffer, 0))) {
4807 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadNonNativeBinaryRow)");
4808 return (0);
4809 }
4810 } else {
4811 if (!SDDS_ReadNonNativeLZMABinaryString(lzmafp, fBuffer, 1)) {
4812 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadNonNativeBinaryRow)");
4813 return 0;
4814 }
4815 }
4816 } else {
4817 size = SDDS_type_size[type - 1];
4818 if (!SDDS_LZMABufferedRead(skip ? NULL : (char *)SDDS_dataset->data[i] + row * size, size, lzmafp, fBuffer, type, SDDS_dataset->layout.byteOrderDeclared)) {
4819 SDDS_SetError("Unable to read row--failure reading value (SDDS_ReadNonNativeBinaryRow)");
4820 return (0);
4821 }
4822 }
4823 }
4824 } else {
4825 fp = layout->fp;
4826 for (i = 0; i < layout->n_columns; i++) {
4827 if (layout->column_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
4828 continue;
4829 if ((type = layout->column_definition[i].type) == SDDS_STRING) {
4830 if (!skip) {
4831 if (((char ***)SDDS_dataset->data)[i][row])
4832 free((((char ***)SDDS_dataset->data)[i][row]));
4833 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_ReadNonNativeBinaryString(fp, fBuffer, 0))) {
4834 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadNonNativeBinaryRow)");
4835 return (0);
4836 }
4837 } else {
4838 if (!SDDS_ReadNonNativeBinaryString(fp, fBuffer, 1)) {
4839 SDDS_SetError("Unable to read rows--failure reading string (SDDS_ReadNonNativeBinaryRow)");
4840 return 0;
4841 }
4842 }
4843 } else {
4844 size = SDDS_type_size[type - 1];
4845 if (!SDDS_BufferedRead(skip ? NULL : (char *)SDDS_dataset->data[i] + row * size, size, fp, fBuffer, type, SDDS_dataset->layout.byteOrderDeclared)) {
4846 SDDS_SetError("Unable to read row--failure reading value (SDDS_ReadNonNativeBinaryRow)");
4847 return (0);
4848 }
4849 }
4850 }
4851 }
4852#if defined(zLib)
4853 }
4854#endif
4855 return (1);
4856}
4857
4858/**
4859 * @brief Reads a non-native endian binary string from a file.
4860 *
4861 * This function reads a binary string from the specified file pointer, handling non-native endianness.
4862 * It first reads the length of the string, swaps its byte order if necessary, allocates memory for the
4863 * string, reads the string data, and null-terminates it.
4864 *
4865 * @param[in] fp Pointer to the FILE from which to read the string.
4866 * @param[in,out] fBuffer Pointer to the SDDS_FILEBUFFER structure used for buffered reading.
4867 * @param[in] skip If non-zero, the function will skip reading the string data, useful for sparse reading.
4868 *
4869 * @return char* Returns a pointer to the read string on success, or NULL if an error occurred.
4870 * @retval Non-NULL Pointer to the newly allocated string.
4871 * @retval NULL An error occurred during reading or memory allocation.
4872 *
4873 * @note The caller is responsible for freeing the returned string to prevent memory leaks.
4874 */
4875char *SDDS_ReadNonNativeBinaryString(FILE *fp, SDDS_FILEBUFFER *fBuffer, int32_t skip) {
4876 int32_t length;
4877 char *string;
4878
4879 if (!SDDS_BufferedRead(&length, sizeof(length), fp, fBuffer, SDDS_LONG, 0))
4880 return (0);
4881 SDDS_SwapLong(&length);
4882 if (length < 0)
4883 return (0);
4884 if (!(string = SDDS_Malloc(sizeof(*string) * (length + 1))))
4885 return (NULL);
4886 if (length && !SDDS_BufferedRead(skip ? NULL : string, sizeof(*string) * length, fp, fBuffer, SDDS_STRING, 0))
4887 return (NULL);
4888 string[length] = 0;
4889 return (string);
4890}
4891
4892/**
4893 * @brief Reads a non-native endian binary string from an LZMA-compressed file.
4894 *
4895 * This function reads a binary string from the specified LZMA-compressed file pointer, handling
4896 * non-native endianness. It first reads the length of the string, swaps its byte order if necessary,
4897 * allocates memory for the string, reads the string data, and null-terminates it.
4898 *
4899 * @param[in] lzmafp Pointer to the LZMAFILE from which to read the string.
4900 * @param[in,out] fBuffer Pointer to the SDDS_FILEBUFFER structure used for buffered reading.
4901 * @param[in] skip If non-zero, the function will skip reading the string data, useful for sparse reading.
4902 *
4903 * @return char* Returns a pointer to the read string on success, or NULL if an error occurred.
4904 * @retval Non-NULL Pointer to the newly allocated string.
4905 * @retval NULL An error occurred during reading or memory allocation.
4906 *
4907 * @note The caller is responsible for freeing the returned string to prevent memory leaks.
4908 */
4909char *SDDS_ReadNonNativeLZMABinaryString(struct lzmafile *lzmafp, SDDS_FILEBUFFER *fBuffer, int32_t skip) {
4910 int32_t length;
4911 char *string;
4912
4913 if (!SDDS_LZMABufferedRead(&length, sizeof(length), lzmafp, fBuffer, SDDS_LONG, 0))
4914 return (0);
4915 SDDS_SwapLong(&length);
4916 if (length < 0)
4917 return (0);
4918 if (!(string = SDDS_Malloc(sizeof(*string) * (length + 1))))
4919 return (NULL);
4920 if (length && !SDDS_LZMABufferedRead(skip ? NULL : string, sizeof(*string) * length, lzmafp, fBuffer, SDDS_STRING, 0))
4921 return (NULL);
4922 string[length] = 0;
4923 return (string);
4924}
4925
4926#if defined(zLib)
4927/**
4928 * @brief Reads a non-native endian binary string from a GZIP-compressed file.
4929 *
4930 * This function reads a binary string from the specified GZIP-compressed file pointer, handling
4931 * non-native endianness. It first reads the length of the string, swaps its byte order if necessary,
4932 * allocates memory for the string, reads the string data, and null-terminates it.
4933 *
4934 * @param[in] gzfp Pointer to the gzFile from which to read the string.
4935 * @param[in,out] fBuffer Pointer to the SDDS_FILEBUFFER structure used for buffered reading.
4936 * @param[in] skip If non-zero, the function will skip reading the string data, useful for sparse reading.
4937 *
4938 * @return char* Returns a pointer to the read string on success, or NULL if an error occurred.
4939 * @retval Non-NULL Pointer to the newly allocated string.
4940 * @retval NULL An error occurred during reading or memory allocation.
4941 *
4942 * @note The caller is responsible for freeing the returned string to prevent memory leaks.
4943 */
4944char *SDDS_ReadNonNativeGZipBinaryString(gzFile gzfp, SDDS_FILEBUFFER *fBuffer, int32_t skip) {
4945 int32_t length;
4946 char *string;
4947
4948 if (!SDDS_GZipBufferedRead(&length, sizeof(length), gzfp, fBuffer, SDDS_LONG, 0))
4949 return (0);
4950 SDDS_SwapLong(&length);
4951 if (length < 0)
4952 return (0);
4953 if (!(string = SDDS_Malloc(sizeof(*string) * (length + 1))))
4954 return (NULL);
4955 if (length && !SDDS_GZipBufferedRead(skip ? NULL : string, sizeof(*string) * length, gzfp, fBuffer, SDDS_STRING, 0))
4956 return (NULL);
4957 string[length] = 0;
4958 return (string);
4959}
4960#endif
4961
4962/**
4963 * @brief Writes a non-native endian binary page to an SDDS dataset.
4964 *
4965 * This function writes a binary page to the specified SDDS dataset, handling byte order reversal
4966 * to convert between little-endian and big-endian formats. It manages various compression formats,
4967 * including uncompressed, GZIP-compressed, and LZMA-compressed files. The function performs the
4968 * following operations:
4969 * - Counts the number of rows to write.
4970 * - Writes the row count with appropriate byte order handling.
4971 * - Writes non-native endian parameters and arrays.
4972 * - Writes column data in either column-major or row-major format based on the dataset's configuration.
4973 * - Flushes the buffer to ensure all data is written to the file.
4974 *
4975 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to write to.
4976 *
4977 * @return int32_t Returns 1 on successful writing of the binary page, or 0 if an error occurred.
4978 * @retval 1 The binary page was successfully written and byte-swapped.
4979 * @retval 0 An error occurred during the write operation, such as I/O failures, memory allocation issues,
4980 * or corrupted dataset definitions.
4981 *
4982 * @note This function modifies the dataset's internal structures during the write process. Ensure that
4983 * the dataset is properly initialized and opened for writing before invoking this function. After
4984 * writing, the dataset's state is updated to reflect the newly written page.
4985 */
4987/* Write binary page with byte order reversed. Used for little-to-big
4988 * and big-to-little endian conversion
4989 */
4990{
4991 FILE *fp;
4992 struct lzmafile *lzmafp = NULL;
4993 int64_t i, rows, fixed_rows;
4994 int32_t min32 = INT32_MIN, rows32;
4995 SDDS_FILEBUFFER *fBuffer;
4996#if defined(zLib)
4997 gzFile gzfp = NULL;
4998#endif
4999
5000 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WriteNonNativeBinaryPage"))
5001 return (0);
5002 if (!(fp = SDDS_dataset->layout.fp)) {
5003 SDDS_SetError("Unable to write page--file pointer is NULL (SDDS_WriteNonNativeBinaryPage)");
5004 return (0);
5005 }
5006 fBuffer = &SDDS_dataset->fBuffer;
5007
5008 if (!fBuffer->buffer) {
5009 if (!(fBuffer->buffer = fBuffer->data = SDDS_Malloc(sizeof(char) * defaultIOBufferSize))) {
5010 SDDS_SetError("Unable to do buffered read--allocation failure (SDDS_WriteNonNativeBinaryPage)");
5011 return 0;
5012 }
5013 fBuffer->bufferSize = defaultIOBufferSize;
5014 fBuffer->bytesLeft = defaultIOBufferSize;
5015 }
5016 SDDS_SwapLong(&min32);
5017
5018 rows = SDDS_CountRowsOfInterest(SDDS_dataset);
5019#if defined(zLib)
5020 if (SDDS_dataset->layout.gzipFile) {
5021 if (!(gzfp = SDDS_dataset->layout.gzfp)) {
5022 SDDS_SetError("Unable to write page--file pointer is NULL (SDDS_WriteNonNativeBinaryPage)");
5023 return (0);
5024 }
5025 SDDS_dataset->rowcount_offset = gztell(gzfp);
5026 if (SDDS_dataset->layout.data_mode.fixed_row_count) {
5027 fixed_rows = ((rows / SDDS_dataset->layout.data_mode.fixed_row_increment) + 2) * SDDS_dataset->layout.data_mode.fixed_row_increment;
5028 if (fixed_rows > INT32_MAX) {
5029 if (!SDDS_GZipBufferedWrite(&min32, sizeof(min32), gzfp, fBuffer)) {
5030 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5031 return (0);
5032 }
5033 SDDS_SwapLong64(&fixed_rows);
5034 if (!SDDS_GZipBufferedWrite(&fixed_rows, sizeof(fixed_rows), gzfp, fBuffer)) {
5035 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5036 return (0);
5037 }
5038 SDDS_SwapLong64(&fixed_rows);
5039 } else {
5040 rows32 = (int32_t)fixed_rows;
5041 SDDS_SwapLong(&rows32);
5042 if (!SDDS_GZipBufferedWrite(&rows32, sizeof(rows32), gzfp, fBuffer)) {
5043 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5044 return (0);
5045 }
5046 }
5047 } else {
5048 if (rows > INT32_MAX) {
5049 if (!SDDS_GZipBufferedWrite(&min32, sizeof(min32), gzfp, fBuffer)) {
5050 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5051 return (0);
5052 }
5053 SDDS_SwapLong64(&rows);
5054 if (!SDDS_GZipBufferedWrite(&rows, sizeof(rows), gzfp, fBuffer)) {
5055 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5056 return (0);
5057 }
5058 SDDS_SwapLong64(&rows);
5059 } else {
5060 rows32 = (int32_t)rows;
5061 SDDS_SwapLong(&rows32);
5062 if (!SDDS_GZipBufferedWrite(&rows32, sizeof(rows32), gzfp, fBuffer)) {
5063 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5064 return (0);
5065 }
5066 }
5067 }
5068 } else {
5069#endif
5070 if (SDDS_dataset->layout.lzmaFile) {
5071 if (!(lzmafp = SDDS_dataset->layout.lzmafp)) {
5072 SDDS_SetError("Unable to write page--file pointer is NULL (SDDS_WriteNonNativeBinaryPage)");
5073 return (0);
5074 }
5075 SDDS_dataset->rowcount_offset = lzma_tell(lzmafp);
5076 if (SDDS_dataset->layout.data_mode.fixed_row_count) {
5077 fixed_rows = ((rows / SDDS_dataset->layout.data_mode.fixed_row_increment) + 2) * SDDS_dataset->layout.data_mode.fixed_row_increment;
5078 if (fixed_rows > INT32_MAX) {
5079 if (!SDDS_LZMABufferedWrite(&min32, sizeof(min32), lzmafp, fBuffer)) {
5080 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5081 return (0);
5082 }
5083 SDDS_SwapLong64(&fixed_rows);
5084 if (!SDDS_LZMABufferedWrite(&fixed_rows, sizeof(fixed_rows), lzmafp, fBuffer)) {
5085 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5086 return (0);
5087 }
5088 SDDS_SwapLong64(&fixed_rows);
5089 } else {
5090 rows32 = (int32_t)fixed_rows;
5091 SDDS_SwapLong(&rows32);
5092 if (!SDDS_LZMABufferedWrite(&rows32, sizeof(rows32), lzmafp, fBuffer)) {
5093 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5094 return (0);
5095 }
5096 }
5097 } else {
5098 if (rows > INT32_MAX) {
5099 if (!SDDS_LZMABufferedWrite(&min32, sizeof(min32), lzmafp, fBuffer)) {
5100 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5101 return (0);
5102 }
5103 SDDS_SwapLong64(&rows);
5104 if (!SDDS_LZMABufferedWrite(&rows, sizeof(rows), lzmafp, fBuffer)) {
5105 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5106 return (0);
5107 }
5108 SDDS_SwapLong64(&rows);
5109 } else {
5110 rows32 = (int32_t)rows;
5111 SDDS_SwapLong(&rows32);
5112 if (!SDDS_LZMABufferedWrite(&rows32, sizeof(rows32), lzmafp, fBuffer)) {
5113 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5114 return (0);
5115 }
5116 }
5117 }
5118 } else {
5119 SDDS_dataset->rowcount_offset = ftell(fp);
5120 if (SDDS_dataset->layout.data_mode.fixed_row_count) {
5121 fixed_rows = ((rows / SDDS_dataset->layout.data_mode.fixed_row_increment) + 2) * SDDS_dataset->layout.data_mode.fixed_row_increment;
5122 if (fixed_rows > INT32_MAX) {
5123 if (!SDDS_BufferedWrite(&min32, sizeof(min32), fp, fBuffer)) {
5124 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5125 return (0);
5126 }
5127 SDDS_SwapLong64(&fixed_rows);
5128 if (!SDDS_BufferedWrite(&fixed_rows, sizeof(fixed_rows), fp, fBuffer)) {
5129 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5130 return (0);
5131 }
5132 SDDS_SwapLong64(&fixed_rows);
5133 } else {
5134 rows32 = (int32_t)fixed_rows;
5135 SDDS_SwapLong(&rows32);
5136 if (!SDDS_BufferedWrite(&rows32, sizeof(rows32), fp, fBuffer)) {
5137 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5138 return (0);
5139 }
5140 }
5141 } else {
5142 if (rows > INT32_MAX) {
5143 if (!SDDS_BufferedWrite(&min32, sizeof(min32), fp, fBuffer)) {
5144 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5145 return (0);
5146 }
5147 SDDS_SwapLong64(&rows);
5148 if (!SDDS_BufferedWrite(&rows, sizeof(rows), fp, fBuffer)) {
5149 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5150 return (0);
5151 }
5152 SDDS_SwapLong64(&rows);
5153 } else {
5154 rows32 = (int32_t)rows;
5155 SDDS_SwapLong(&rows32);
5156 if (!SDDS_BufferedWrite(&rows32, sizeof(rows32), fp, fBuffer)) {
5157 SDDS_SetError("Unable to write page--failure writing number of rows (SDDS_WriteNonNativeBinaryPage)");
5158 return (0);
5159 }
5160 }
5161 }
5162 }
5163#if defined(zLib)
5164 }
5165#endif
5166 if (!SDDS_WriteNonNativeBinaryParameters(SDDS_dataset)) {
5167 SDDS_SetError("Unable to write page--parameter writing problem (SDDS_WriteNonNativeBinaryPage)");
5168 return 0;
5169 }
5170 if (!SDDS_WriteNonNativeBinaryArrays(SDDS_dataset)) {
5171 SDDS_SetError("Unable to write page--array writing problem (SDDS_WriteNonNativeBinaryPage)");
5172 return 0;
5173 }
5174 SDDS_SwapEndsColumnData(SDDS_dataset);
5175 if (SDDS_dataset->layout.n_columns) {
5176 if (SDDS_dataset->layout.data_mode.column_major) {
5177 if (!SDDS_WriteNonNativeBinaryColumns(SDDS_dataset)) {
5178 SDDS_SetError("Unable to write page--column writing problem (SDDS_WriteNonNativeBinaryPage)");
5179 return 0;
5180 }
5181 } else {
5182 for (i = 0; i < SDDS_dataset->n_rows; i++) {
5183 if (SDDS_dataset->row_flag[i]) {
5184 if (!SDDS_WriteNonNativeBinaryRow(SDDS_dataset, i)) {
5185 SDDS_SetError("Unable to write page--row writing problem (SDDS_WriteNonNativeBinaryPage)");
5186 return 0;
5187 }
5188 }
5189 }
5190 }
5191 }
5192 SDDS_SwapEndsColumnData(SDDS_dataset);
5193#if defined(zLib)
5194 if (SDDS_dataset->layout.gzipFile) {
5195 if (!SDDS_GZipFlushBuffer(gzfp, fBuffer)) {
5196 SDDS_SetError("Unable to write page--buffer flushing problem (SDDS_WriteNonNativeBinaryPage)");
5197 return 0;
5198 }
5199 } else {
5200#endif
5201 if (SDDS_dataset->layout.lzmaFile) {
5202 if (!SDDS_LZMAFlushBuffer(lzmafp, fBuffer)) {
5203 SDDS_SetError("Unable to write page--buffer flushing problem (SDDS_WriteNonNativeBinaryPage)");
5204 return 0;
5205 }
5206 } else {
5207 if (!SDDS_FlushBuffer(fp, fBuffer)) {
5208 SDDS_SetError("Unable to write page--buffer flushing problem (SDDS_WriteNonNativeBinaryPage)");
5209 return 0;
5210 }
5211 }
5212#if defined(zLib)
5213 }
5214#endif
5215 SDDS_dataset->last_row_written = SDDS_dataset->n_rows - 1;
5216 SDDS_dataset->n_rows_written = rows;
5217 SDDS_dataset->writing_page = 1;
5218 return (1);
5219}
5220
5221/**
5222 * @brief Writes non-native endian binary parameters to an SDDS dataset.
5223 *
5224 * This function iterates through all parameter definitions in the specified SDDS dataset and writes their
5225 * binary data to the underlying file. It handles various data types, including short, unsigned short,
5226 * long, unsigned long, long long, unsigned long long, float, double, and long double. For string
5227 * parameters, it writes each string individually, ensuring proper memory management and byte order
5228 * conversion. Parameters with fixed values are skipped during the write process. The function supports
5229 * different compression formats, including uncompressed, LZMA-compressed, and GZIP-compressed files.
5230 *
5231 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to write to.
5232 *
5233 * @return int32_t Returns 1 on successful writing of all parameters, or 0 if an error occurred.
5234 * @retval 1 All non-native endian parameters were successfully written and byte-swapped.
5235 * @retval 0 An error occurred during the write operation, such as I/O failures, memory allocation issues,
5236 * or corrupted parameter definitions.
5237 *
5238 * @note This function modifies the dataset's parameter data during the write process. Ensure that the
5239 * dataset is properly initialized and opened for writing before invoking this function. After
5240 * writing, the dataset's state is updated to reflect the written parameters.
5241 */
5243 int32_t i;
5244 SDDS_LAYOUT *layout;
5245 FILE *fp;
5246 struct lzmafile *lzmafp;
5247 SDDS_FILEBUFFER *fBuffer;
5248#if defined(zLib)
5249 gzFile gzfp;
5250#endif
5251
5252 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WriteNonNativeBinaryParameters"))
5253 return (0);
5254
5255 SDDS_SwapEndsParameterData(SDDS_dataset);
5256
5257 layout = &SDDS_dataset->layout;
5258 fBuffer = &SDDS_dataset->fBuffer;
5259#if defined(zLib)
5260 if (SDDS_dataset->layout.gzipFile) {
5261 if (!(gzfp = layout->gzfp)) {
5262 SDDS_SetError("Unable to write parameters--file pointer is NULL (SDDS_WriteNonNativeBinaryParameters)");
5263 return (0);
5264 }
5265 for (i = 0; i < layout->n_parameters; i++) {
5266 if (layout->parameter_definition[i].fixed_value)
5267 continue;
5268 if (layout->parameter_definition[i].type == SDDS_STRING) {
5269 if (!SDDS_GZipWriteNonNativeBinaryString(*((char **)SDDS_dataset->parameter[i]), gzfp, fBuffer)) {
5270 SDDS_SetError("Unable to write parameters--failure writing string (SDDS_WriteNonNativeBinaryParameters)");
5271 SDDS_SwapEndsParameterData(SDDS_dataset);
5272 return (0);
5273 }
5274 } else if (!SDDS_GZipBufferedWrite(SDDS_dataset->parameter[i], SDDS_type_size[layout->parameter_definition[i].type - 1], gzfp, fBuffer)) {
5275 SDDS_SetError("Unable to write parameters--failure writing value (SDDS_WriteBinaryParameters)");
5276 SDDS_SwapEndsParameterData(SDDS_dataset);
5277 return (0);
5278 }
5279 }
5280 } else {
5281#endif
5282 if (SDDS_dataset->layout.lzmaFile) {
5283 if (!(lzmafp = layout->lzmafp)) {
5284 SDDS_SetError("Unable to write parameters--file pointer is NULL (SDDS_WriteNonNativeBinaryParameters)");
5285 return (0);
5286 }
5287 for (i = 0; i < layout->n_parameters; i++) {
5288 if (layout->parameter_definition[i].fixed_value)
5289 continue;
5290 if (layout->parameter_definition[i].type == SDDS_STRING) {
5291 if (!SDDS_LZMAWriteNonNativeBinaryString(*((char **)SDDS_dataset->parameter[i]), lzmafp, fBuffer)) {
5292 SDDS_SetError("Unable to write parameters--failure writing string (SDDS_WriteNonNativeBinaryParameters)");
5293 SDDS_SwapEndsParameterData(SDDS_dataset);
5294 return (0);
5295 }
5296 } else if (!SDDS_LZMABufferedWrite(SDDS_dataset->parameter[i], SDDS_type_size[layout->parameter_definition[i].type - 1], lzmafp, fBuffer)) {
5297 SDDS_SetError("Unable to write parameters--failure writing value (SDDS_WriteBinaryParameters)");
5298 SDDS_SwapEndsParameterData(SDDS_dataset);
5299 return (0);
5300 }
5301 }
5302 } else {
5303 fp = layout->fp;
5304 for (i = 0; i < layout->n_parameters; i++) {
5305 if (layout->parameter_definition[i].fixed_value)
5306 continue;
5307 if (layout->parameter_definition[i].type == SDDS_STRING) {
5308 if (!SDDS_WriteNonNativeBinaryString(*((char **)SDDS_dataset->parameter[i]), fp, fBuffer)) {
5309 SDDS_SetError("Unable to write parameters--failure writing string (SDDS_WriteNonNativeBinaryParameters)");
5310 SDDS_SwapEndsParameterData(SDDS_dataset);
5311 return (0);
5312 }
5313 } else if (!SDDS_BufferedWrite(SDDS_dataset->parameter[i], SDDS_type_size[layout->parameter_definition[i].type - 1], fp, fBuffer)) {
5314 SDDS_SetError("Unable to write parameters--failure writing value (SDDS_WriteBinaryParameters)");
5315 SDDS_SwapEndsParameterData(SDDS_dataset);
5316 return (0);
5317 }
5318 }
5319 }
5320#if defined(zLib)
5321 }
5322#endif
5323
5324 SDDS_SwapEndsParameterData(SDDS_dataset);
5325 return (1);
5326}
5327
5328/**
5329 * @brief Writes non-native endian binary arrays to an SDDS dataset.
5330 *
5331 * This function iterates through all array definitions in the specified SDDS dataset and writes their
5332 * binary data to the underlying file. It handles various data types, including short, unsigned short,
5333 * long, unsigned long, long long, unsigned long long, float, double, and long double. For string
5334 * arrays, it writes each string individually, ensuring proper memory management and byte order
5335 * conversion. The function supports different compression formats, including uncompressed, LZMA-compressed,
5336 * and GZIP-compressed files. After writing, it swaps the endianness of the array data to match the system's
5337 * native byte order.
5338 *
5339 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to write to.
5340 *
5341 * @return int32_t Returns 1 on successful writing of all arrays, or 0 if an error occurred.
5342 * @retval 1 All non-native endian arrays were successfully written and byte-swapped.
5343 * @retval 0 An error occurred during the write operation, such as I/O failures, memory allocation issues,
5344 * or corrupted array definitions.
5345 *
5346 * @note This function modifies the dataset's array data during the write process. Ensure that the
5347 * dataset is properly initialized and opened for writing before invoking this function. After
5348 * writing, the dataset's state is updated to reflect the written arrays.
5349 */
5351 int32_t i, j, dimension, zero = 0;
5352 SDDS_LAYOUT *layout;
5353 FILE *fp;
5354 struct lzmafile *lzmafp;
5355 SDDS_FILEBUFFER *fBuffer;
5356#if defined(zLib)
5357 gzFile gzfp;
5358#endif
5359 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WriteNonNativeBinaryArrays"))
5360 return (0);
5361 SDDS_SwapEndsArrayData(SDDS_dataset);
5362
5363 layout = &SDDS_dataset->layout;
5364 fBuffer = &SDDS_dataset->fBuffer;
5365#if defined(zLib)
5366 if (SDDS_dataset->layout.gzipFile) {
5367 gzfp = layout->gzfp;
5368 for (i = 0; i < layout->n_arrays; i++) {
5369 if (!SDDS_dataset->array[i].dimension) {
5370 for (j = 0; j < layout->array_definition[i].dimensions; j++)
5371 if (!SDDS_GZipBufferedWrite(&zero, sizeof(zero), gzfp, fBuffer)) {
5372 SDDS_SetError("Unable to write null array--failure writing dimensions (SDDS_WriteNonNativeBinaryArrays)");
5373 SDDS_SwapEndsArrayData(SDDS_dataset);
5374 return 0;
5375 }
5376 continue;
5377 }
5378
5379 for (j = 0; j < layout->array_definition[i].dimensions; j++) {
5380 dimension = SDDS_dataset->array[i].dimension[j];
5381 SDDS_SwapLong(&dimension);
5382 if (!SDDS_GZipBufferedWrite(&dimension, sizeof(dimension), gzfp, fBuffer)) {
5383 SDDS_SetError("Unable to write arrays--failure writing dimensions (SDDS_WriteNonNativeBinaryArrays)");
5384 SDDS_SwapEndsArrayData(SDDS_dataset);
5385 return (0);
5386 }
5387 }
5388 if (layout->array_definition[i].type == SDDS_STRING) {
5389 for (j = 0; j < SDDS_dataset->array[i].elements; j++) {
5390 if (!SDDS_GZipWriteNonNativeBinaryString(((char **)SDDS_dataset->array[i].data)[j], gzfp, fBuffer)) {
5391 SDDS_SetError("Unable to write arrays--failure writing string (SDDS_WriteNonNativeBinaryArrays)");
5392 SDDS_SwapEndsArrayData(SDDS_dataset);
5393 return (0);
5394 }
5395 }
5396 } 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)) {
5397 SDDS_SetError("Unable to write arrays--failure writing values (SDDS_WriteNonNativeBinaryArrays)");
5398 SDDS_SwapEndsArrayData(SDDS_dataset);
5399 return (0);
5400 }
5401 }
5402 } else {
5403#endif
5404 if (SDDS_dataset->layout.lzmaFile) {
5405 lzmafp = layout->lzmafp;
5406 for (i = 0; i < layout->n_arrays; i++) {
5407 if (!SDDS_dataset->array[i].dimension) {
5408 for (j = 0; j < layout->array_definition[i].dimensions; j++)
5409 if (!SDDS_LZMABufferedWrite(&zero, sizeof(zero), lzmafp, fBuffer)) {
5410 SDDS_SetError("Unable to write null array--failure writing dimensions (SDDS_WriteNonNativeBinaryArrays)");
5411 SDDS_SwapEndsArrayData(SDDS_dataset);
5412 return 0;
5413 }
5414 continue;
5415 }
5416
5417 for (j = 0; j < layout->array_definition[i].dimensions; j++) {
5418 dimension = SDDS_dataset->array[i].dimension[j];
5419 SDDS_SwapLong(&dimension);
5420 if (!SDDS_LZMABufferedWrite(&dimension, sizeof(dimension), lzmafp, fBuffer)) {
5421 SDDS_SetError("Unable to write arrays--failure writing dimensions (SDDS_WriteNonNativeBinaryArrays)");
5422 SDDS_SwapEndsArrayData(SDDS_dataset);
5423 return (0);
5424 }
5425 }
5426 if (layout->array_definition[i].type == SDDS_STRING) {
5427 for (j = 0; j < SDDS_dataset->array[i].elements; j++) {
5428 if (!SDDS_LZMAWriteNonNativeBinaryString(((char **)SDDS_dataset->array[i].data)[j], lzmafp, fBuffer)) {
5429 SDDS_SetError("Unable to write arrays--failure writing string (SDDS_WriteNonNativeBinaryArrays)");
5430 SDDS_SwapEndsArrayData(SDDS_dataset);
5431 return (0);
5432 }
5433 }
5434 } 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)) {
5435 SDDS_SetError("Unable to write arrays--failure writing values (SDDS_WriteNonNativeBinaryArrays)");
5436 SDDS_SwapEndsArrayData(SDDS_dataset);
5437 return (0);
5438 }
5439 }
5440 } else {
5441 fp = layout->fp;
5442 for (i = 0; i < layout->n_arrays; i++) {
5443 if (!SDDS_dataset->array[i].dimension) {
5444 for (j = 0; j < layout->array_definition[i].dimensions; j++)
5445 if (!SDDS_BufferedWrite(&zero, sizeof(zero), fp, fBuffer)) {
5446 SDDS_SetError("Unable to write null array--failure writing dimensions (SDDS_WriteNonNativeBinaryArrays)");
5447 SDDS_SwapEndsArrayData(SDDS_dataset);
5448 return 0;
5449 }
5450 continue;
5451 }
5452
5453 for (j = 0; j < layout->array_definition[i].dimensions; j++) {
5454 dimension = SDDS_dataset->array[i].dimension[j];
5455 SDDS_SwapLong(&dimension);
5456 if (!SDDS_BufferedWrite(&dimension, sizeof(dimension), fp, fBuffer)) {
5457 SDDS_SetError("Unable to write arrays--failure writing dimensions (SDDS_WriteNonNativeBinaryArrays)");
5458 SDDS_SwapEndsArrayData(SDDS_dataset);
5459 return (0);
5460 }
5461 }
5462 if (layout->array_definition[i].type == SDDS_STRING) {
5463 for (j = 0; j < SDDS_dataset->array[i].elements; j++) {
5464 if (!SDDS_WriteNonNativeBinaryString(((char **)SDDS_dataset->array[i].data)[j], fp, fBuffer)) {
5465 SDDS_SetError("Unable to write arrays--failure writing string (SDDS_WriteNonNativeBinaryArrays)");
5466 SDDS_SwapEndsArrayData(SDDS_dataset);
5467 return (0);
5468 }
5469 }
5470 } 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)) {
5471 SDDS_SetError("Unable to write arrays--failure writing values (SDDS_WriteNonNativeBinaryArrays)");
5472 SDDS_SwapEndsArrayData(SDDS_dataset);
5473 return (0);
5474 }
5475 }
5476 }
5477#if defined(zLib)
5478 }
5479#endif
5480 SDDS_SwapEndsArrayData(SDDS_dataset);
5481 return (1);
5482}
5483
5484/**
5485 * @brief Writes a non-native endian binary row to an SDDS dataset.
5486 *
5487 * This function writes a single row of data to the specified SDDS dataset, handling byte order reversal
5488 * to convert between little-endian and big-endian formats. It supports various compression formats,
5489 * including uncompressed, GZIP-compressed, and LZMA-compressed files. The function iterates through all
5490 * column definitions, writing each column's data appropriately based on its type. For string columns,
5491 * it ensures proper memory management and byte order conversion by utilizing specialized string writing
5492 * functions. For non-string data types, it writes the binary data directly with the correct byte ordering.
5493 *
5494 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to write to.
5495 * @param[in] row The index of the row to write to the dataset.
5496 *
5497 * @return int32_t Returns 1 on successful writing of the binary row, or 0 if an error occurred.
5498 * @retval 1 The binary row was successfully written and byte-swapped.
5499 * @retval 0 An error occurred during the write operation, such as I/O failures or corrupted data.
5500 *
5501 * @note This function modifies the dataset's internal data structures during the write process. Ensure that
5502 * the dataset is properly initialized and opened for writing before invoking this function.
5503 * After writing, the dataset's state is updated to reflect the newly written row.
5504 */
5505int32_t SDDS_WriteNonNativeBinaryRow(SDDS_DATASET *SDDS_dataset, int64_t row) {
5506 int64_t i, type, size;
5507 SDDS_LAYOUT *layout;
5508 FILE *fp;
5509 struct lzmafile *lzmafp;
5510 SDDS_FILEBUFFER *fBuffer;
5511#if defined(zLib)
5512 gzFile gzfp;
5513#endif
5514
5515 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WriteNonNativeBinaryRow"))
5516 return (0);
5517 layout = &SDDS_dataset->layout;
5518 fBuffer = &SDDS_dataset->fBuffer;
5519#if defined(zLib)
5520 if (SDDS_dataset->layout.gzipFile) {
5521 gzfp = layout->gzfp;
5522 for (i = 0; i < layout->n_columns; i++) {
5523 if ((type = layout->column_definition[i].type) == SDDS_STRING) {
5524 if (!SDDS_GZipWriteNonNativeBinaryString(*((char **)SDDS_dataset->data[i] + row), gzfp, fBuffer)) {
5525 SDDS_SetError("Unable to write rows--failure writing string (SDDS_WriteNonNativeBinaryRows)");
5526 return (0);
5527 }
5528 } else {
5529 size = SDDS_type_size[type - 1];
5530 if (!SDDS_GZipBufferedWrite((char *)SDDS_dataset->data[i] + row * size, size, gzfp, fBuffer)) {
5531 SDDS_SetError("Unable to write row--failure writing value (SDDS_WriteNonNativeBinaryRow)");
5532 return (0);
5533 }
5534 }
5535 }
5536 } else {
5537#endif
5538 if (SDDS_dataset->layout.lzmaFile) {
5539 lzmafp = layout->lzmafp;
5540 for (i = 0; i < layout->n_columns; i++) {
5541 if ((type = layout->column_definition[i].type) == SDDS_STRING) {
5542 if (!SDDS_LZMAWriteNonNativeBinaryString(*((char **)SDDS_dataset->data[i] + row), lzmafp, fBuffer)) {
5543 SDDS_SetError("Unable to write rows--failure writing string (SDDS_WriteNonNativeBinaryRows)");
5544 return (0);
5545 }
5546 } else {
5547 size = SDDS_type_size[type - 1];
5548 if (!SDDS_LZMABufferedWrite((char *)SDDS_dataset->data[i] + row * size, size, lzmafp, fBuffer)) {
5549 SDDS_SetError("Unable to write row--failure writing value (SDDS_WriteNonNativeBinaryRow)");
5550 return (0);
5551 }
5552 }
5553 }
5554 } else {
5555 fp = layout->fp;
5556 for (i = 0; i < layout->n_columns; i++) {
5557 if ((type = layout->column_definition[i].type) == SDDS_STRING) {
5558 if (!SDDS_WriteNonNativeBinaryString(*((char **)SDDS_dataset->data[i] + row), fp, fBuffer)) {
5559 SDDS_SetError("Unable to write rows--failure writing string (SDDS_WriteNonNativeBinaryRows)");
5560 return (0);
5561 }
5562 } else {
5563 size = SDDS_type_size[type - 1];
5564 if (!SDDS_BufferedWrite((char *)SDDS_dataset->data[i] + row * size, size, fp, fBuffer)) {
5565 SDDS_SetError("Unable to write row--failure writing value (SDDS_WriteNonNativeBinaryRow)");
5566 return (0);
5567 }
5568 }
5569 }
5570 }
5571#if defined(zLib)
5572 }
5573#endif
5574 return (1);
5575}
5576
5577/**
5578 * @brief Writes a non-native endian binary string to a file.
5579 *
5580 * This function writes a binary string to the specified file pointer, handling non-native endianness.
5581 * It first writes the length of the string as a 32-bit integer with byte order swapped. If the string
5582 * is not to be skipped, it then writes the string data itself followed by a null terminator. If the
5583 * input string is NULL, an empty string is written instead.
5584 *
5585 * @param[in] string The string to write. If NULL, an empty string is written.
5586 * @param[in] fp Pointer to the FILE where the string will be written.
5587 * @param[in] fBuffer Pointer to the SDDS_FILEBUFFER structure used for buffered writing.
5588 *
5589 * @return int32_t Returns 1 on successful writing of the string, or 0 if an error occurred.
5590 * @retval 1 The string was successfully written and byte-swapped.
5591 * @retval 0 An error occurred during the write operation, such as I/O failures or memory allocation issues.
5592 *
5593 * @note The caller is responsible for ensuring that the file pointer `fp` is valid and open for writing.
5594 * This function does not perform memory allocation for the string; it assumes that the string
5595 * is already allocated and managed appropriately.
5596 */
5597int32_t SDDS_WriteNonNativeBinaryString(char *string, FILE *fp, SDDS_FILEBUFFER *fBuffer) {
5598 int32_t length;
5599 static char *dummy_string = "";
5600 if (!string)
5601 string = dummy_string;
5602 length = strlen(string);
5603 SDDS_SwapLong(&length);
5604 if (!SDDS_BufferedWrite(&length, sizeof(length), fp, fBuffer)) {
5605 SDDS_SetError("Unable to write string--error writing length");
5606 return (0);
5607 }
5608 SDDS_SwapLong(&length);
5609 if (length && !SDDS_BufferedWrite(string, sizeof(*string) * length, fp, fBuffer)) {
5610 SDDS_SetError("Unable to write string--error writing contents");
5611 return (0);
5612 }
5613 return (1);
5614}
5615
5616/**
5617 * @brief Writes a non-native endian binary string to an LZMA-compressed file.
5618 *
5619 * This function writes a binary string to the specified LZMA-compressed file pointer, handling
5620 * non-native endianness. It first writes the length of the string as a 32-bit integer with byte
5621 * order swapped. If the string is not to be skipped, it then writes the string data itself
5622 * followed by a null terminator. If the input string is NULL, an empty string is written instead.
5623 *
5624 * @param[in] string The string to write. If NULL, an empty string is written.
5625 * @param[in] lzmafp Pointer to the LZMAFILE where the string will be written.
5626 * @param[in] fBuffer Pointer to the SDDS_FILEBUFFER structure used for buffered writing.
5627 *
5628 * @return int32_t Returns 1 on successful writing of the string, or 0 if an error occurred.
5629 * @retval 1 The string was successfully written and byte-swapped.
5630 * @retval 0 An error occurred during the write operation, such as I/O failures or memory allocation issues.
5631 *
5632 * @note The caller is responsible for ensuring that the LZMAFILE pointer `lzmafp` is valid and open for writing.
5633 * This function does not perform memory allocation for the string; it assumes that the string
5634 * is already allocated and managed appropriately.
5635 */
5636int32_t SDDS_LZMAWriteNonNativeBinaryString(char *string, struct lzmafile *lzmafp, SDDS_FILEBUFFER *fBuffer) {
5637 int32_t length;
5638 static char *dummy_string = "";
5639 if (!string)
5640 string = dummy_string;
5641 length = strlen(string);
5642 SDDS_SwapLong(&length);
5643 if (!SDDS_LZMABufferedWrite(&length, sizeof(length), lzmafp, fBuffer)) {
5644 SDDS_SetError("Unable to write string--error writing length");
5645 return (0);
5646 }
5647 SDDS_SwapLong(&length);
5648 if (length && !SDDS_LZMABufferedWrite(string, sizeof(*string) * length, lzmafp, fBuffer)) {
5649 SDDS_SetError("Unable to write string--error writing contents");
5650 return (0);
5651 }
5652 return (1);
5653}
5654
5655#if defined(zLib)
5656/**
5657 * @brief Writes a non-native endian binary string to a GZIP-compressed file.
5658 *
5659 * This function writes a binary string to the specified GZIP-compressed file pointer, handling
5660 * non-native endianness. It first writes the length of the string as a 32-bit integer with byte
5661 * order swapped. If the string is not to be skipped, it then writes the string data itself
5662 * followed by a null terminator. If the input string is NULL, an empty string is written instead.
5663 *
5664 * @param[in] string The string to write. If NULL, an empty string is written.
5665 * @param[in] gzfp Pointer to the gzFile where the string will be written.
5666 * @param[in] fBuffer Pointer to the SDDS_FILEBUFFER structure used for buffered writing.
5667 *
5668 * @return int32_t Returns 1 on successful writing of the string, or 0 if an error occurred.
5669 * @retval 1 The string was successfully written and byte-swapped.
5670 * @retval 0 An error occurred during the write operation, such as I/O failures or memory allocation issues.
5671 *
5672 * @note The caller is responsible for ensuring that the gzFile pointer `gzfp` is valid and open for writing.
5673 * This function does not perform memory allocation for the string; it assumes that the string
5674 * is already allocated and managed appropriately.
5675 */
5676int32_t SDDS_GZipWriteNonNativeBinaryString(char *string, gzFile gzfp, SDDS_FILEBUFFER *fBuffer) {
5677 int32_t length;
5678 static char *dummy_string = "";
5679 if (!string)
5680 string = dummy_string;
5681 length = strlen(string);
5682 SDDS_SwapLong(&length);
5683 if (!SDDS_GZipBufferedWrite(&length, sizeof(length), gzfp, fBuffer)) {
5684 SDDS_SetError("Unable to write string--error writing length");
5685 return (0);
5686 }
5687 SDDS_SwapLong(&length);
5688 if (length && !SDDS_GZipBufferedWrite(string, sizeof(*string) * length, gzfp, fBuffer)) {
5689 SDDS_SetError("Unable to write string--error writing contents");
5690 return (0);
5691 }
5692 return (1);
5693}
5694#endif
5695
5696/**
5697 * @brief Updates a non-native endian binary page in an SDDS dataset.
5698 *
5699 * This function updates an existing binary page in the specified SDDS dataset, handling byte order
5700 * reversal to convert between little-endian and big-endian formats. It supports updating rows
5701 * based on the provided mode flags, such as flushing the table. The function ensures that the buffer
5702 * is flushed before performing the update and writes any new rows that have been flagged for writing.
5703 * It also handles fixed row counts and manages byte order conversions as necessary.
5704 *
5705 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset to update.
5706 * @param[in] mode Bitmask indicating the update mode (e.g., FLUSH_TABLE).
5707 *
5708 * @return int32_t Returns 1 on successful update of the binary page, or 0 if an error occurred.
5709 * @retval 1 The binary page was successfully updated and byte-swapped.
5710 * @retval 0 An error occurred during the update operation, such as I/O failures, invalid row counts,
5711 * or corrupted dataset definitions.
5712 *
5713 * @note This function modifies the dataset's internal structures during the update process. Ensure that
5714 * the dataset is properly initialized and opened for writing before invoking this function.
5715 * After updating, the dataset's state is updated to reflect the changes made to the page.
5716 */
5717int32_t SDDS_UpdateNonNativeBinaryPage(SDDS_DATASET *SDDS_dataset, uint32_t mode) {
5718 FILE *fp;
5719 int32_t code, min32 = INT32_MIN, rows32;
5720 int64_t i, rows, offset, fixed_rows;
5721 SDDS_FILEBUFFER *fBuffer;
5722
5723 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_UpdateNonNativeBinaryPage"))
5724 return (0);
5725#if defined(zLib)
5726 if (SDDS_dataset->layout.gzipFile) {
5727 SDDS_SetError("Unable to perform page updates on a gzip file (SDDS_UpdateNonNativeBinaryPage)");
5728 return 0;
5729 }
5730#endif
5731 if (SDDS_dataset->layout.lzmaFile) {
5732 SDDS_SetError("Unable to perform page updates on .lzma or .xz files (SDDS_UpdateNonNativeBinaryPage)");
5733 return 0;
5734 }
5735 if (SDDS_dataset->layout.data_mode.column_major) {
5736 SDDS_SetError("Unable to perform page updates on a column major order file (SDDS_UpdateNonNativeBinaryPage)");
5737 return 0;
5738 }
5739 if (!SDDS_dataset->writing_page) {
5740#ifdef DEBUG
5741 fprintf(stderr, "Page not being written---calling SDDS_UpdateNonNativeBinaryPage\n");
5742#endif
5743 if (!(code = SDDS_WriteNonNativeBinaryPage(SDDS_dataset))) {
5744 return 0;
5745 }
5746 if (mode & FLUSH_TABLE) {
5747 SDDS_FreeTableStrings(SDDS_dataset);
5748 SDDS_dataset->first_row_in_mem = SDDS_CountRowsOfInterest(SDDS_dataset);
5749 SDDS_dataset->last_row_written = -1;
5750 SDDS_dataset->n_rows = 0;
5751 }
5752 return code;
5753 }
5754
5755 if (!(fp = SDDS_dataset->layout.fp)) {
5756 SDDS_SetError("Unable to update page--file pointer is NULL (SDDS_UpdateNonNativeBinaryPage)");
5757 return (0);
5758 }
5759 fBuffer = &SDDS_dataset->fBuffer;
5760 if (!SDDS_FlushBuffer(fp, fBuffer)) {
5761 SDDS_SetError("Unable to write page--buffer flushing problem (SDDS_UpdateNonNativeBinaryPage)");
5762 return 0;
5763 }
5764 offset = ftell(fp);
5765
5766 rows = SDDS_CountRowsOfInterest(SDDS_dataset) + SDDS_dataset->first_row_in_mem;
5767#ifdef DEBUG
5768 fprintf(stderr, "%" PRId64 " rows stored in table, %" PRId32 " already written\n", rows, SDDS_dataset->n_rows_written);
5769#endif
5770 if (rows == SDDS_dataset->n_rows_written) {
5771 return (1);
5772 }
5773 if (rows < SDDS_dataset->n_rows_written) {
5774 SDDS_SetError("Unable to update page--new number of rows less than previous number (SDDS_UpdateNonNativeBinaryPage)");
5775 return (0);
5776 }
5777 SDDS_SwapLong(&min32);
5778 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))) {
5779 if (SDDS_fseek(fp, SDDS_dataset->rowcount_offset, 0) == -1) {
5780 SDDS_SetError("Unable to update page--failure doing fseek (SDDS_UpdateNonNativeBinaryPage)");
5781 return (0);
5782 }
5783 if (SDDS_dataset->layout.data_mode.fixed_row_count) {
5784 if ((rows - SDDS_dataset->n_rows_written) + 1 > SDDS_dataset->layout.data_mode.fixed_row_increment) {
5785 SDDS_dataset->layout.data_mode.fixed_row_increment = (rows - SDDS_dataset->n_rows_written) + 1;
5786 }
5787 fixed_rows = ((rows / SDDS_dataset->layout.data_mode.fixed_row_increment) + 2) * SDDS_dataset->layout.data_mode.fixed_row_increment;
5788#if defined(DEBUG)
5789 fprintf(stderr, "Setting %" PRId64 " fixed rows\n", fixed_rows);
5790#endif
5791 if ((fixed_rows > INT32_MAX) && (SDDS_dataset->n_rows_written <= INT32_MAX)) {
5792 SDDS_SetError("Unable to update page--crossed the INT32_MAX row boundary (SDDS_UpdateNonNativeBinaryPage)");
5793 return (0);
5794 }
5795 if (fixed_rows > INT32_MAX) {
5796 if (fwrite(&min32, sizeof(min32), 1, fp) != 1) {
5797 SDDS_SetError("Unable to update page--failure writing number of rows (SDDS_UpdateBinaryPage)");
5798 return (0);
5799 }
5800 SDDS_SwapLong64(&fixed_rows);
5801 if (fwrite(&fixed_rows, sizeof(fixed_rows), 1, fp) != 1) {
5802 SDDS_SetError("Unable to update page--failure writing number of rows (SDDS_UpdateNonNativeBinaryPage)");
5803 return (0);
5804 }
5805 SDDS_SwapLong64(&fixed_rows);
5806 } else {
5807 rows32 = (int32_t)fixed_rows;
5808 SDDS_SwapLong(&rows32);
5809 if (fwrite(&rows32, sizeof(rows32), 1, fp) != 1) {
5810 SDDS_SetError("Unable to update page--failure writing number of rows (SDDS_UpdateNonNativeBinaryPage)");
5811 return (0);
5812 }
5813 }
5814 } else {
5815#if defined(DEBUG)
5816 fprintf(stderr, "Setting %" PRId64 " rows\n", rows);
5817#endif
5818 if ((rows > INT32_MAX) && (SDDS_dataset->n_rows_written <= INT32_MAX)) {
5819 SDDS_SetError("Unable to update page--crossed the INT32_MAX row boundary (SDDS_UpdateNonNativeBinaryPage)");
5820 return (0);
5821 }
5822 if (rows > INT32_MAX) {
5823 if (fwrite(&min32, sizeof(min32), 1, fp) != 1) {
5824 SDDS_SetError("Unable to update page--failure writing number of rows (SDDS_UpdateBinaryPage)");
5825 return (0);
5826 }
5827 SDDS_SwapLong64(&rows);
5828 if (fwrite(&rows, sizeof(rows), 1, fp) != 1) {
5829 SDDS_SetError("Unable to update page--failure writing number of rows (SDDS_UpdateNonNativeBinaryPage)");
5830 return (0);
5831 }
5832 SDDS_SwapLong64(&rows);
5833 } else {
5834 rows32 = (int32_t)rows;
5835 SDDS_SwapLong(&rows32);
5836 if (fwrite(&rows32, sizeof(rows32), 1, fp) != 1) {
5837 SDDS_SetError("Unable to update page--failure writing number of rows (SDDS_UpdateNonNativeBinaryPage)");
5838 return (0);
5839 }
5840 }
5841 }
5842 if (SDDS_fseek(fp, offset, 0) == -1) {
5843 SDDS_SetError("Unable to update page--failure doing fseek to end of page (SDDS_UpdateNonNativeBinaryPage)");
5844 return (0);
5845 }
5846 }
5847 SDDS_SwapEndsColumnData(SDDS_dataset);
5848 for (i = SDDS_dataset->last_row_written + 1; i < SDDS_dataset->n_rows; i++) {
5849 if (SDDS_dataset->row_flag[i] && !SDDS_WriteNonNativeBinaryRow(SDDS_dataset, i)) {
5850 SDDS_SetError("Unable to update page--failure writing row (SDDS_UpdateNonNativeBinaryPage)");
5851 return (0);
5852 }
5853 }
5854 SDDS_SwapEndsColumnData(SDDS_dataset);
5855#ifdef DEBUG
5856 fprintf(stderr, "Flushing buffer\n");
5857#endif
5858 if (!SDDS_FlushBuffer(fp, fBuffer)) {
5859 SDDS_SetError("Unable to write page--buffer flushing problem (SDDS_UpdateNonNativeBinaryPage)");
5860 return 0;
5861 }
5862 SDDS_dataset->last_row_written = SDDS_dataset->n_rows - 1;
5863 SDDS_dataset->n_rows_written = rows;
5864 if (mode & FLUSH_TABLE) {
5865 SDDS_FreeTableStrings(SDDS_dataset);
5866 SDDS_dataset->first_row_in_mem = rows;
5867 SDDS_dataset->last_row_written = -1;
5868 SDDS_dataset->n_rows = 0;
5869 }
5870 return (1);
5871}
5872
5873/**
5874 * @brief Converts a 16-byte array representing a float80 value to a double.
5875 *
5876 * This function converts a 16-byte array, which represents an 80-bit floating-point (float80) value,
5877 * to a standard double-precision (64-bit) floating-point value. The conversion handles different
5878 * byte orders, supporting both big-endian and little-endian formats. On systems where `long double`
5879 * is implemented as 64-bit (such as Windows and Mac), this function allows reading SDDS_LONGDOUBLE
5880 * SDDS files with a loss of precision by translating float80 values to double.
5881 *
5882 * @param[in] x The 16-byte array representing the float80 value.
5883 * @param[in] byteOrder The byte order of the array, either `SDDS_BIGENDIAN_SEEN` or `SDDS_LITTLEENDIAN_SEEN`.
5884 *
5885 * @return double The converted double-precision floating-point value.
5886 *
5887 * @note This function assumes that the input array `x` is correctly formatted as an 80-bit floating-point
5888 * value. On systems where `long double` is 80 bits, the conversion preserves as much precision as
5889 * possible within the limitations of the double-precision format. On systems with 64-bit `long double`,
5890 * the function translates the value with inherent precision loss.
5891 */
5892double makeFloat64FromFloat80(unsigned char x[16], int32_t byteOrder) {
5893 int exponent;
5894 uint64_t mantissa;
5895 unsigned char d[8] = {0};
5896 double result;
5897
5898 if (byteOrder == SDDS_BIGENDIAN_SEEN) {
5899 /* conversion is done in little endian */
5900 char xx;
5901 int i;
5902 for (i = 0; i < 6; i++) {
5903 xx = x[0 + i];
5904 x[0 + i] = x[11 - i];
5905 x[11 - i] = xx;
5906 }
5907 }
5908
5909 exponent = (((x[9] << 8) | x[8]) & 0x7FFF);
5910 mantissa =
5911 ((uint64_t)x[7] << 56) | ((uint64_t)x[6] << 48) | ((uint64_t)x[5] << 40) | ((uint64_t)x[4] << 32) |
5912 ((uint64_t)x[3] << 24) | ((uint64_t)x[2] << 16) | ((uint64_t)x[1] << 8) | (uint64_t)x[0];
5913
5914 d[7] = x[9] & 0x80; /* Set sign. */
5915
5916 if ((exponent == 0x7FFF) || (exponent == 0)) {
5917 /* Infinite, NaN or denormal */
5918 if (exponent == 0x7FFF) {
5919 /* Infinite or NaN */
5920 d[7] |= 0x7F;
5921 d[6] = 0xF0;
5922 } else {
5923 /* Otherwise it's denormal. It cannot be represented as double. Translate as singed zero. */
5924 memcpy(&result, d, 8);
5925 return result;
5926 }
5927 } else {
5928 /* Normal number. */
5929 exponent = exponent - 0x3FFF + 0x03FF; /*< exponent for double precision. */
5930
5931 if (exponent <= -52) /*< Too small to represent. Translate as (signed) zero. */
5932 {
5933 memcpy(&result, d, 8);
5934 return result;
5935 } else if (exponent < 0) {
5936 /* Denormal, exponent bits are already zero here. */
5937 } else if (exponent >= 0x7FF) /*< Too large to represent. Translate as infinite. */
5938 {
5939 d[7] |= 0x7F;
5940 d[6] = 0xF0;
5941 memset(d, 0x00, 6);
5942 memcpy(&result, d, 8);
5943 return result;
5944 } else {
5945 /* Representable number */
5946 d[7] |= (exponent & 0x7F0) >> 4;
5947 d[6] |= (exponent & 0xF) << 4;
5948 }
5949 }
5950 /* Translate mantissa. */
5951
5952 mantissa >>= 11;
5953
5954 if (exponent < 0) {
5955 /* Denormal, further shifting is required here. */
5956 mantissa >>= (-exponent + 1);
5957 }
5958
5959 d[0] = mantissa & 0xFF;
5960 d[1] = (mantissa >> 8) & 0xFF;
5961 d[2] = (mantissa >> 16) & 0xFF;
5962 d[3] = (mantissa >> 24) & 0xFF;
5963 d[4] = (mantissa >> 32) & 0xFF;
5964 d[5] = (mantissa >> 40) & 0xFF;
5965 d[6] |= (mantissa >> 48) & 0x0F;
5966
5967 memcpy(&result, d, 8);
5968
5969 if (byteOrder == SDDS_BIGENDIAN_SEEN) {
5970 /* convert back to big endian */
5971 SDDS_SwapDouble(&result);
5972 }
5973
5974 return result;
5975}
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_ReadBinaryColumns(SDDS_DATASET *SDDS_dataset, int64_t sparse_interval, int64_t sparse_offset)
Reads the binary columns from an SDDS dataset.
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.
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_CHARACTER
Identifier for the character data type.
Definition SDDStypes.h:91
#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
double max_in_array(double *array, long n)
Finds the maximum value in an array of doubles.
Definition findMinMax.c:318
double min_in_array(double *array, long n)
Finds the minimum value in an array of doubles.
Definition findMinMax.c:336
long compute_average(double *value, double *data, int64_t n)
Computes the average of an array of doubles.
Definition median.c:144
long compute_median(double *value, double *x, long n)
Computes the median of an array of doubles.
Definition median.c:29