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