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