1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Copyright by The HDF Group. *
3 * Copyright by the Board of Trustees of the University of Illinois. *
4 * All rights reserved. *
5 * *
6 * This file is part of HDF5. The full HDF5 copyright notice, including *
7 * terms governing use, modification, and redistribution, is contained in *
8 * the COPYING file, which can be found at the root of the source code *
9 * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
10 * If you do not have access to either file, you may request a copy from *
11 * help@hdfgroup.org. *
12 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13
14 /*
15 * Purpose: A library for displaying the values of a dataset in a human
16 * readable format.
17 */
18
19 #include "h5tools.h"
20 #include "h5tools_dump.h"
21 #include "h5tools_ref.h"
22 #include "h5tools_utils.h"
23 #include "H5private.h"
24
25 /* global variables */
26 hid_t H5tools_ERR_STACK_g = 0;
27 hid_t H5tools_ERR_CLS_g = -1;
28 hid_t H5E_tools_g = -1;
29 hid_t H5E_tools_min_id_g = -1;
30 int compound_data;
31 FILE *rawattrstream = NULL; /* should initialize to stdout but gcc moans about it */
32 FILE *rawdatastream = NULL; /* should initialize to stdout but gcc moans about it */
33 FILE *rawinstream = NULL; /* should initialize to stdin but gcc moans about it */
34 FILE *rawoutstream = NULL; /* should initialize to stdout but gcc moans about it */
35 FILE *rawerrorstream = NULL; /* should initialize to stderr but gcc moans about it */
36 int bin_output; /* binary output */
37 int bin_form = 0; /* binary form, default NATIVE */
38 int region_output; /* region output */
39 int oid_output; /* oid output */
40 int data_output; /* data output */
41 int attr_data_output; /* attribute data output */
42 unsigned packed_bits_num; /* number of packed bits to display */
43 unsigned packed_data_offset; /* offset of packed bits to display */
44 unsigned packed_data_length; /* length of packed bits to display */
45 unsigned long long packed_data_mask; /* mask in which packed bits to display */
46 int enable_error_stack = 0; /* re-enable error stack; disable=0 enable=1 */
47
48 /* sort parameters */
49 H5_index_t sort_by = H5_INDEX_NAME; /*sort_by [creation_order | name] */
50 H5_iter_order_t sort_order = H5_ITER_INC; /*sort_order [ascending | descending] */
51
52 /* module-scoped variables */
53 static int h5tools_init_g; /* if h5tools lib has been initialized */
54
55 /* Names of VFDs */
56 static const char *drivernames[]={
57 "sec2",
58 "family",
59 "split",
60 "multi",
61 #ifdef H5_HAVE_PARALLEL
62 "mpio",
63 #endif /* H5_HAVE_PARALLEL */
64 };
65
66 /* This enum should match the entries in the above drivers_list since they
67 * are indexes into the drivers_list array. */
68 typedef enum {
69 SEC2_IDX = 0
70 ,FAMILY_IDX
71 ,SPLIT_IDX
72 ,MULTI_IDX
73 #ifdef H5_HAVE_PARALLEL
74 ,MPIO_IDX
75 #endif /* H5_HAVE_PARALLEL */
76 } driver_idx;
77 #define NUM_DRIVERS (sizeof(drivernames) / sizeof(drivernames[0]))
78
79 /*-------------------------------------------------------------------------
80 * Function: h5tools_init
81 *
82 * Purpose: This should be called before any other h5tools function is called.
83 * Effect of any h5tools function called before this has been called is
84 * undetermined.
85 *
86 * Return None
87 *-------------------------------------------------------------------------
88 */
89 void
h5tools_init(void)90 h5tools_init(void)
91 {
92 char lib_str[256];
93
94 if (!h5tools_init_g) {
95 /* register the error class */
96 HDsnprintf(lib_str, sizeof(lib_str), "%d.%d.%d",H5_VERS_MAJOR, H5_VERS_MINOR, H5_VERS_RELEASE);
97
98 H5tools_ERR_STACK_g = H5Ecreate_stack();
99 H5TOOLS_INIT_ERROR()
100
101 if (!rawattrstream)
102 rawattrstream = stdout;
103 if (!rawdatastream)
104 rawdatastream = stdout;
105 if (!rawinstream)
106 rawinstream = stdin;
107 if (!rawoutstream)
108 rawoutstream = stdout;
109 if (!rawerrorstream)
110 rawerrorstream = stderr;
111
112 h5tools_dump_init();
113
114 h5tools_init_g++;
115 }
116 }
117
118 /*-------------------------------------------------------------------------
119 * Function: h5tools_close
120 *
121 * Purpose: Close or release resources such as files opened by the library. This
122 * should be called after all other h5tools functions have been called.
123 * Effect of any h5tools function called after this has been called is
124 * undetermined.
125 *
126 * Return: None
127 *-------------------------------------------------------------------------
128 */
129 void
h5tools_close(void)130 h5tools_close(void)
131 {
132 H5E_auto2_t tools_func;
133 void *tools_edata;
134 if (h5tools_init_g) {
135 /* special case where only data is output to stdout */
136 if((rawoutstream == NULL) && rawdatastream && (rawdatastream == stdout))
137 HDfprintf(rawdatastream, "\n");
138
139 H5Eget_auto2(H5tools_ERR_STACK_g, &tools_func, &tools_edata);
140 if(tools_func!=NULL)
141 H5Eprint2(H5tools_ERR_STACK_g, rawerrorstream);
142 if (rawattrstream && rawattrstream != stdout) {
143 if (fclose(rawattrstream))
144 perror("closing rawattrstream");
145 else
146 rawattrstream = NULL;
147 }
148 if (rawdatastream && rawdatastream != stdout) {
149 if (fclose(rawdatastream))
150 perror("closing rawdatastream");
151 else
152 rawdatastream = NULL;
153 }
154 if (rawinstream && rawinstream != stdin) {
155 if (fclose(rawinstream))
156 perror("closing rawinstream");
157 else
158 rawinstream = NULL;
159 }
160 if (rawoutstream && rawoutstream != stdout) {
161 if (fclose(rawoutstream))
162 perror("closing rawoutstream");
163 else
164 rawoutstream = NULL;
165 }
166 if (rawerrorstream && rawerrorstream != stderr) {
167 if (fclose(rawerrorstream))
168 perror("closing rawerrorstream");
169 else
170 rawerrorstream = NULL;
171 }
172
173 /* Clean up the reference path table, if it's been used */
174 term_ref_path_table();
175
176 H5TOOLS_CLOSE_ERROR()
177 H5Eclose_stack(H5tools_ERR_STACK_g);
178 /* Shut down the library */
179 H5close();
180
181 h5tools_init_g = 0;
182 }
183 }
184
185 /*-------------------------------------------------------------------------
186 * Function: h5tools_set_data_output_file
187 *
188 * Purpose: Open fname as the output file for dataset raw data.
189 * Set rawdatastream as its file stream.
190 *
191 * Return: 0 -- succeeded
192 * negative -- failed
193 *-------------------------------------------------------------------------
194 */
195 int
h5tools_set_data_output_file(const char * fname,int is_bin)196 h5tools_set_data_output_file(const char *fname, int is_bin)
197 {
198 int retvalue = FAIL;
199 FILE *f; /* temporary holding place for the stream pointer
200 * so that rawdatastream is changed only when succeeded */
201
202 if (rawdatastream && rawdatastream != stdout) {
203 if (HDfclose(rawdatastream))
204 HDperror("closing rawdatastream");
205 else
206 rawdatastream = NULL;
207 }
208
209 /* First check if filename is string "NULL" */
210 if (fname != NULL) {
211 /* binary output */
212 if (is_bin) {
213 if ((f = HDfopen(fname, "wb")) != NULL) {
214 rawdatastream = f;
215 retvalue = SUCCEED;
216 }
217 }
218 else {
219 if ((f = HDfopen(fname, "w")) != NULL) {
220 rawdatastream = f;
221 retvalue = SUCCEED;
222 }
223 }
224 }
225 else {
226 rawdatastream = NULL;
227 retvalue = SUCCEED;
228 }
229
230 return retvalue;
231 }
232
233 /*-------------------------------------------------------------------------
234 * Function: h5tools_set_attr_output_file
235 *
236 * Purpose: Open fname as the output file for attribute raw data.
237 * Set rawattrstream as its file stream.
238 *
239 * Return: 0 -- succeeded
240 * negative -- failed
241 *-------------------------------------------------------------------------
242 */
243 int
h5tools_set_attr_output_file(const char * fname,int is_bin)244 h5tools_set_attr_output_file(const char *fname, int is_bin)
245 {
246 int retvalue = FAIL;
247 FILE *f; /* temporary holding place for the stream pointer
248 * so that rawattrstream is changed only when succeeded */
249
250 if (rawattrstream && rawattrstream != stdout) {
251 if (HDfclose(rawattrstream))
252 HDperror("closing rawattrstream");
253 else
254 rawattrstream = NULL;
255 }
256
257 /* First check if filename is string "NULL" */
258 if (fname != NULL) {
259 /* binary output */
260 if (is_bin) {
261 if ((f = HDfopen(fname, "wb")) != NULL) {
262 rawattrstream = f;
263 retvalue = SUCCEED;
264 }
265 }
266 else {
267 if ((f = HDfopen(fname, "w")) != NULL) {
268 rawattrstream = f;
269 retvalue = SUCCEED;
270 }
271 }
272 }
273 else {
274 rawattrstream = NULL;
275 retvalue = SUCCEED;
276 }
277
278 return retvalue;
279 }
280
281 /*-------------------------------------------------------------------------
282 * Function: h5tools_set_input_file
283 *
284 * Purpose: Open fname as the input file for raw input.
285 * Set rawinstream as its file stream.
286 *
287 * Return: 0 -- succeeded
288 * negative -- failed
289 *
290 *-------------------------------------------------------------------------
291 */
292 int
h5tools_set_input_file(const char * fname,int is_bin)293 h5tools_set_input_file(const char *fname, int is_bin)
294 {
295 int retvalue = FAIL;
296 FILE *f; /* temporary holding place for the stream pointer
297 * so that rawinstream is changed only when succeeded */
298
299 if (rawinstream && rawinstream != stdin) {
300 if (HDfclose(rawinstream))
301 HDperror("closing rawinstream");
302 else
303 rawinstream = NULL;
304 }
305 /* First check if filename is string "NULL" */
306 if (fname != NULL) {
307 /* binary output */
308 if (is_bin) {
309 if ((f = HDfopen(fname, "rb")) != NULL) {
310 rawinstream = f;
311 retvalue = SUCCEED;
312 }
313 }
314 else {
315 if ((f = HDfopen(fname, "r")) != NULL) {
316 rawinstream = f;
317 retvalue = SUCCEED;
318 }
319 }
320 }
321 else {
322 rawinstream = NULL;
323 retvalue = SUCCEED;
324 }
325
326 return retvalue;
327 }
328
329 /*-------------------------------------------------------------------------
330 * Function: h5tools_set_output_file
331 *
332 * Purpose: Open fname as the output file for raw output.
333 * Set rawoutstream as its file stream.
334 *
335 * Return: 0 -- succeeded
336 * negative -- failed
337 *
338 *-------------------------------------------------------------------------
339 */
340 int
h5tools_set_output_file(const char * fname,int is_bin)341 h5tools_set_output_file(const char *fname, int is_bin)
342 {
343 int retvalue = FAIL;
344 FILE *f; /* temporary holding place for the stream pointer
345 * so that rawoutstream is changed only when succeeded */
346
347 if (rawoutstream && rawoutstream != stdout) {
348 if (HDfclose(rawoutstream))
349 HDperror("closing rawoutstream");
350 else
351 rawoutstream = NULL;
352 }
353 /* First check if filename is string "NULL" */
354 if (fname != NULL) {
355 /* binary output */
356 if (is_bin) {
357 if ((f = HDfopen(fname, "wb")) != NULL) {
358 rawoutstream = f;
359 retvalue = SUCCEED;
360 }
361 }
362 else {
363 if ((f = HDfopen(fname, "w")) != NULL) {
364 rawoutstream = f;
365 retvalue = SUCCEED;
366 }
367 }
368 }
369 else {
370 rawoutstream = NULL;
371 retvalue = SUCCEED;
372 }
373
374 return retvalue;
375 }
376
377 /*-------------------------------------------------------------------------
378 * Function: h5tools_set_error_file
379 *
380 * Purpose: Open fname as the error output file for dataset raw error.
381 * Set rawerrorstream as its file stream.
382 *
383 * Return: 0 -- succeeded
384 * negative -- failed
385 *-------------------------------------------------------------------------
386 */
387 int
h5tools_set_error_file(const char * fname,int is_bin)388 h5tools_set_error_file(const char *fname, int is_bin)
389 {
390 int retvalue = FAIL;
391 FILE *f; /* temporary holding place for the stream pointer
392 * so that rawerrorstream is changed only when succeeded */
393
394 if (rawerrorstream && rawerrorstream != stderr) {
395 if (HDfclose(rawerrorstream))
396 HDperror("closing rawerrorstream");
397 else
398 rawerrorstream = NULL;
399 }
400
401 /* First check if filename is string "NULL" */
402 if (fname != NULL) {
403 /* binary output */
404 if (is_bin) {
405 if ((f = HDfopen(fname, "wb")) != NULL) {
406 rawerrorstream = f;
407 retvalue = SUCCEED;
408 }
409 }
410 else {
411 if ((f = HDfopen(fname, "w")) != NULL) {
412 rawerrorstream = f;
413 retvalue = SUCCEED;
414 }
415 }
416 }
417 else {
418 rawerrorstream = NULL;
419 retvalue = SUCCEED;
420 }
421
422 return retvalue;
423 }
424
425 /*-------------------------------------------------------------------------
426 * Function: h5tools_get_fapl
427 *
428 * Purpose: Get a FAPL for a given VFL driver name.
429 *
430 * Return: positive - succeeded
431 * negative - failed
432 *-------------------------------------------------------------------------
433 */
434 static hid_t
h5tools_get_fapl(hid_t fapl,const char * driver,unsigned * drivernum)435 h5tools_get_fapl(hid_t fapl, const char *driver, unsigned *drivernum)
436 {
437 hid_t new_fapl = -1; /* Copy of file access property list passed in, or new property list */
438 int ret_value = SUCCEED;
439
440 /* Make a copy of the FAPL, for the file open call to use, eventually */
441 if (fapl == H5P_DEFAULT) {
442 if ((new_fapl = H5Pcreate(H5P_FILE_ACCESS)) < 0)
443 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Pcreate failed");
444 } /* end if */
445 else {
446 if ((new_fapl = H5Pcopy(fapl)) < 0)
447 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Pcopy failed");
448 } /* end else */
449
450 /* Determine which driver the user wants to open the file with. Try
451 * that driver. If it can't open it, then fail. */
452 if (!HDstrcmp(driver, drivernames[SEC2_IDX])) {
453 /* SEC2 driver */
454 if (H5Pset_fapl_sec2(new_fapl) < 0)
455 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Pset_fapl_sec2 failed");
456
457 if (drivernum)
458 *drivernum = SEC2_IDX;
459 }
460 else if (!HDstrcmp(driver, drivernames[FAMILY_IDX])) {
461 /* FAMILY Driver */
462
463 /* Set member size to be 0 to indicate the current first member size
464 * is the member size.
465 */
466 if (H5Pset_fapl_family(new_fapl, (hsize_t) 0, H5P_DEFAULT) < 0)
467 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Pset_fapl_family failed");
468
469 if (drivernum)
470 *drivernum = FAMILY_IDX;
471 }
472 else if (!HDstrcmp(driver, drivernames[SPLIT_IDX])) {
473 /* SPLIT Driver */
474 if (H5Pset_fapl_split(new_fapl, "-m.h5", H5P_DEFAULT, "-r.h5", H5P_DEFAULT) < 0)
475 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Pset_fapl_split failed");
476
477 if (drivernum)
478 *drivernum = SPLIT_IDX;
479 }
480 else if (!HDstrcmp(driver, drivernames[MULTI_IDX])) {
481 /* MULTI Driver */
482 if (H5Pset_fapl_multi(new_fapl, NULL, NULL, NULL, NULL, TRUE) < 0)
483 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Pset_fapl_multi failed");
484
485 if(drivernum)
486 *drivernum = MULTI_IDX;
487 }
488 #ifdef H5_HAVE_PARALLEL
489 else if(!HDstrcmp(driver, drivernames[MPIO_IDX])) {
490 int mpi_initialized, mpi_finalized;
491
492 /* MPI-I/O Driver */
493 /* check if MPI is available. */
494 MPI_Initialized(&mpi_initialized);
495 MPI_Finalized(&mpi_finalized);
496
497 if(mpi_initialized && !mpi_finalized) {
498 if(H5Pset_fapl_mpio(new_fapl, MPI_COMM_WORLD, MPI_INFO_NULL) < 0)
499 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Pset_fapl_mpio failed");
500 if(drivernum)
501 *drivernum = MPIO_IDX;
502 } /* end if */
503 }
504 #endif /* H5_HAVE_PARALLEL */
505 else
506 ret_value = -1;
507
508 done:
509 if((new_fapl != H5P_DEFAULT) && (ret_value < 0)) {
510 H5Pclose(new_fapl);
511 new_fapl = -1;
512 }
513
514 return(new_fapl);
515 }
516
517 /*-------------------------------------------------------------------------
518 * Function: h5tools_fopen
519 *
520 * Purpose: Loop through the various types of VFL drivers trying to open FNAME.
521 * If the HDF5 library is version 1.2 or less, then we have only the SEC2
522 * driver to try out. If the HDF5 library is greater than version 1.2,
523 * then we have the FAMILY, SPLIT, and MULTI drivers to play with.
524 *
525 * If DRIVER is non-NULL, then it will try to open the file with that
526 * driver first. We assume that the user knows what they are doing so, if
527 * we fail, then we won't try other file drivers.
528 *
529 * Return:
530 * On success, returns a file id for the opened file. If DRIVERNAME is
531 * non-null then the first DRIVERNAME_SIZE-1 characters of the driver
532 * name are copied into the DRIVERNAME array and null terminated.
533 *
534 * Otherwise, the function returns FAIL. If DRIVERNAME is non-null then
535 * the first byte is set to the null terminator.
536 *-------------------------------------------------------------------------
537 */
538 hid_t
h5tools_fopen(const char * fname,unsigned flags,hid_t fapl,const char * driver,char * drivername,size_t drivername_size)539 h5tools_fopen(const char *fname, unsigned flags, hid_t fapl, const char *driver,
540 char *drivername, size_t drivername_size)
541 {
542 unsigned drivernum;
543 hid_t fid = FAIL;
544 hid_t my_fapl = H5P_DEFAULT;
545
546 if (driver && *driver) {
547 /* Get the correct FAPL for the given driver */
548 if ((my_fapl = h5tools_get_fapl(fapl, driver, &drivernum)) < 0)
549 goto done;
550
551 /* allow error stack display if enable-error-stack has optional arg number */
552 if (enable_error_stack > 1) {
553 fid = H5Fopen(fname, flags, my_fapl);
554 }
555 else {
556 H5E_BEGIN_TRY {
557 fid = H5Fopen(fname, flags, my_fapl);
558 } H5E_END_TRY;
559 }
560
561 if (fid == FAIL)
562 goto done;
563
564 }
565 else {
566 /* Try to open the file using each of the drivers */
567 for (drivernum = 0; drivernum < NUM_DRIVERS; drivernum++) {
568 /* Get the correct FAPL for the given driver */
569 if((my_fapl = h5tools_get_fapl(fapl, drivernames[drivernum], NULL)) < 0)
570 goto done;
571
572 /* allow error stack display if enable-error-stack has optional arg number */
573 if (enable_error_stack > 1) {
574 fid = H5Fopen(fname, flags, my_fapl);
575 }
576 else {
577 H5E_BEGIN_TRY {
578 fid = H5Fopen(fname, flags, my_fapl);
579 } H5E_END_TRY;
580 }
581
582 if (fid != FAIL)
583 break;
584 else {
585 /* Close the FAPL */
586 H5Pclose(my_fapl);
587 my_fapl = H5P_DEFAULT;
588 } /* end else */
589 }
590 }
591
592 /* Save the driver name */
593 if (drivername && drivername_size) {
594 if (fid != FAIL) {
595 HDstrncpy(drivername, drivernames[drivernum], drivername_size);
596 drivername[drivername_size - 1] = '\0';
597 }
598 else {
599 /*no file opened*/
600 drivername[0] = '\0';
601 }
602 }
603
604 done:
605 if(my_fapl != H5P_DEFAULT)
606 H5Pclose(my_fapl);
607
608 return fid;
609 }
610
611 /*-------------------------------------------------------------------------
612 * Function: h5tools_count_ncols
613 *
614 * Purpose: Count the number of columns in a string. This is the number of
615 * characters in the string not counting line-control characters.
616 *
617 * Return: success - returns the width of the string.
618 * failure - 0.
619 *-------------------------------------------------------------------------
620 */
621 static size_t
h5tools_count_ncols(const char * s)622 h5tools_count_ncols(const char *s)
623 {
624 register size_t i;
625
626 for (i = 0; *s; s++)
627 if (*s >= ' ')
628 i++;
629
630 return i;
631 }
632
633 /*-------------------------------------------------------------------------
634 * Function: h5tools_detect_vlen
635 *
636 * Purpose: Recursive check for any variable length data in given type.
637 *
638 * Return: TRUE : type contains any variable length data
639 * FALSE : type doesn't contain any variable length data
640 * Negative value: failed
641 *-------------------------------------------------------------------------
642 */
643 htri_t
h5tools_detect_vlen(hid_t tid)644 h5tools_detect_vlen(hid_t tid)
645 {
646 htri_t ret = FALSE;
647
648 /* recursive detect any vlen data values in type (compound, array ...) */
649 ret = H5Tdetect_class(tid, H5T_VLEN);
650 if((ret == TRUE) || (ret < 0))
651 goto done;
652
653 /* recursive detect any vlen string in type (compound, array ...) */
654 ret = h5tools_detect_vlen_str(tid);
655 if((ret == TRUE) || (ret < 0))
656 goto done;
657
658 done:
659 return ret;
660 }
661
662 /*-------------------------------------------------------------------------
663 * Function: h5tools_detect_vlen_str
664 *
665 * Purpose: Recursive check for variable length string of a datatype.
666 *
667 * Return: TRUE : type contains any variable length string
668 * FALSE : type doesn't contain any variable length string
669 * Negative value: failed
670 *-------------------------------------------------------------------------
671 */
672 htri_t
h5tools_detect_vlen_str(hid_t tid)673 h5tools_detect_vlen_str(hid_t tid)
674 {
675 H5T_class_t tclass = -1;
676 htri_t ret = FALSE;
677
678 ret = H5Tis_variable_str(tid);
679 if((ret == TRUE) || (ret < 0))
680 goto done;
681
682 tclass = H5Tget_class(tid);
683 if(tclass == H5T_ARRAY || tclass == H5T_VLEN) {
684 hid_t btid = H5Tget_super(tid);
685
686 if(btid < 0) {
687 ret = (htri_t)btid;
688 goto done;
689 }
690 ret = h5tools_detect_vlen_str(btid);
691 if((ret == TRUE) || (ret < 0)) {
692 H5Tclose(btid);
693 goto done;
694 }
695 }
696 else if(tclass == H5T_COMPOUND) {
697 unsigned nmembs;
698 int snmembs = H5Tget_nmembers(tid);
699 unsigned u;
700
701 if(snmembs < 0) {
702 ret = FAIL;
703 goto done;
704 }
705 nmembs = (unsigned)snmembs;
706
707 for(u = 0; u < nmembs; u++) {
708 hid_t mtid = H5Tget_member_type(tid, u);
709
710 ret = h5tools_detect_vlen_str(mtid);
711 if((ret == TRUE) || (ret < 0)) {
712 H5Tclose(mtid);
713 goto done;
714 }
715 H5Tclose(mtid);
716 }
717 }
718
719 done:
720 return ret;
721 }
722
723 /*-------------------------------------------------------------------------
724 * Function: h5tools_simple_prefix
725 *
726 * Purpose: If /ctx->need_prefix/ is set then terminate the current line (if
727 * applicable), calculate the prefix string, and display it at the start
728 * of a line.
729 *
730 * Return: None
731 *-------------------------------------------------------------------------
732 */
733 void
h5tools_simple_prefix(FILE * stream,const h5tool_format_t * info,h5tools_context_t * ctx,hsize_t elmtno,int secnum)734 h5tools_simple_prefix(FILE *stream, const h5tool_format_t *info,
735 h5tools_context_t *ctx, hsize_t elmtno, int secnum)
736 {
737 h5tools_str_t prefix;
738 h5tools_str_t str; /*temporary for indentation */
739 size_t templength = 0;
740 unsigned u, indentlevel = 0;
741
742 if (stream == NULL)
743 return;
744
745 if (!ctx->need_prefix)
746 return;
747
748 HDmemset(&prefix, 0, sizeof(h5tools_str_t));
749 HDmemset(&str, 0, sizeof(h5tools_str_t));
750
751 /* Terminate previous line, if any */
752 if (ctx->cur_column) {
753 PUTSTREAM(OPT(info->line_suf, ""), stream);
754 HDputc('\n', stream);
755 PUTSTREAM(OPT(info->line_sep, ""), stream);
756 }
757
758 /* Calculate new prefix */
759 h5tools_str_prefix(&prefix, info, elmtno, ctx->ndims, ctx);
760
761 /* Write new prefix to output */
762 if (ctx->indent_level > 0)
763 indentlevel = ctx->indent_level;
764 else
765 /*
766 * This is because sometimes we don't print out all the header
767 * info for the data (like the tattr-2.ddl example). If that happens
768 * the ctx->indent_level is negative so we need to skip the above and
769 * just print out the default indent levels.
770 */
771 indentlevel = ctx->default_indent_level;
772
773 /* when printing array indices, print the indentation before the prefix
774 the prefix is printed one indentation level before */
775 if (info->pindex)
776 for (u = 0; u < indentlevel - 1; u++)
777 PUTSTREAM(h5tools_str_fmt(&str, (size_t)0, info->line_indent), stream);
778
779 if (elmtno == 0 && secnum == 0 && info->line_1st)
780 PUTSTREAM(h5tools_str_fmt(&prefix, (size_t)0, info->line_1st), stream);
781 else if (secnum && info->line_cont)
782 PUTSTREAM(h5tools_str_fmt(&prefix, (size_t)0, info->line_cont), stream);
783 else
784 PUTSTREAM(h5tools_str_fmt(&prefix, (size_t)0, info->line_pre), stream);
785
786 templength = h5tools_str_len(&prefix);
787
788 for (u = 0; u < indentlevel; u++)
789 /*we already made the indent for the array indices case */
790 if (!info->pindex) {
791 PUTSTREAM(h5tools_str_fmt(&prefix, (size_t)0, info->line_indent), stream);
792 templength += h5tools_str_len(&prefix);
793 }
794 else {
795 /*we cannot count the prefix for the array indices case */
796 templength += h5tools_str_len(&str);
797 }
798
799 ctx->cur_column = ctx->prev_prefix_len = templength;
800 ctx->cur_elmt = 0;
801 ctx->need_prefix = 0;
802
803 /* Free string */
804 h5tools_str_close(&prefix);
805 h5tools_str_close(&str);
806 }
807
808 /*-------------------------------------------------------------------------
809 * Function: h5tools_region_simple_prefix
810 *
811 * Purpose: If /ctx->need_prefix/ is set then terminate the current line (if
812 * applicable), calculate the prefix string, and display it at the start
813 * of a line. Calls region specific function.
814 *
815 * Return: None
816 *-------------------------------------------------------------------------
817 */
818 void
h5tools_region_simple_prefix(FILE * stream,const h5tool_format_t * info,h5tools_context_t * ctx,hsize_t elmtno,hsize_t * ptdata,int secnum)819 h5tools_region_simple_prefix(FILE *stream, const h5tool_format_t *info,
820 h5tools_context_t *ctx, hsize_t elmtno, hsize_t *ptdata, int secnum)
821 {
822 h5tools_str_t prefix;
823 h5tools_str_t str; /*temporary for indentation */
824 size_t templength = 0;
825 unsigned u, indentlevel = 0;
826
827 if (stream == NULL)
828 return;
829
830 if (!ctx->need_prefix)
831 return;
832
833 HDmemset(&prefix, 0, sizeof(h5tools_str_t));
834 HDmemset(&str, 0, sizeof(h5tools_str_t));
835
836 /* Terminate previous line, if any */
837 if (ctx->cur_column) {
838 PUTSTREAM(OPT(info->line_suf, ""), stream);
839 HDputc('\n', stream);
840 PUTSTREAM(OPT(info->line_sep, ""), stream);
841 }
842
843 /* Calculate new prefix */
844 h5tools_str_region_prefix(&prefix, info, elmtno, ptdata, ctx->ndims, ctx->p_max_idx, ctx);
845
846 /* Write new prefix to output */
847 if (ctx->indent_level > 0)
848 indentlevel = ctx->indent_level;
849 else
850 /*
851 * This is because sometimes we don't print out all the header
852 * info for the data (like the tattr-2.ddl example). If that happens
853 * the ctx->indent_level is negative so we need to skip the above and
854 * just print out the default indent levels.
855 */
856 indentlevel = ctx->default_indent_level;
857
858 /* when printing array indices, print the indentation before the prefix
859 the prefix is printed one indentation level before */
860 if (info->pindex)
861 for (u = 0; u < indentlevel - 1; u++)
862 PUTSTREAM(h5tools_str_fmt(&str, (size_t)0, info->line_indent), stream);
863
864 if (elmtno == 0 && secnum == 0 && info->line_1st)
865 PUTSTREAM(h5tools_str_fmt(&prefix, (size_t)0, info->line_1st), stream);
866 else if (secnum && info->line_cont)
867 PUTSTREAM(h5tools_str_fmt(&prefix, (size_t)0, info->line_cont), stream);
868 else
869 PUTSTREAM(h5tools_str_fmt(&prefix, (size_t)0, info->line_pre), stream);
870
871 templength = h5tools_str_len(&prefix);
872
873 for (u = 0; u < indentlevel; u++)
874 /*we already made the indent for the array indices case */
875 if (!info->pindex) {
876 PUTSTREAM(h5tools_str_fmt(&prefix, (size_t)0, info->line_indent), stream);
877 templength += h5tools_str_len(&prefix);
878 }
879 else {
880 /*we cannot count the prefix for the array indices case */
881 templength += h5tools_str_len(&str);
882 }
883
884 ctx->cur_column = ctx->prev_prefix_len = templength;
885 ctx->cur_elmt = 0;
886 ctx->need_prefix = 0;
887
888 /* Free string */
889 h5tools_str_close(&prefix);
890 h5tools_str_close(&str);
891 }
892
893 /*-------------------------------------------------------------------------
894 * Function: h5tools_render_element
895 *
896 * Purpose: Prints the string buffer to the output STREAM. The string is
897 * printed according to the format described in INFO. The CTX struct
898 * contains context information shared between calls to this function.
899 *
900 * Return: False if a dimension end is reached
901 * True otherwise
902 *
903 * In/Out:
904 * h5tools_context_t *ctx
905 * h5tools_str_t *buffer
906 * hsize_t *curr_pos
907 *
908 * Parameters Description:
909 * h5tools_str_t *buffer is the string into which to render
910 * hsize_t curr_pos is the total data element position
911 * size_t ncols
912 * hsize_t local_elmt_counter is the local element loop counter
913 * hsize_t elmt_count is the data element loop counter
914 *-------------------------------------------------------------------------
915 */
916 hbool_t
h5tools_render_element(FILE * stream,const h5tool_format_t * info,h5tools_context_t * ctx,h5tools_str_t * buffer,hsize_t * curr_pos,size_t ncols,hsize_t local_elmt_counter,hsize_t elmt_counter)917 h5tools_render_element(FILE *stream, const h5tool_format_t *info,
918 h5tools_context_t *ctx, h5tools_str_t *buffer, hsize_t *curr_pos,
919 size_t ncols, hsize_t local_elmt_counter, hsize_t elmt_counter)
920 {
921 hbool_t dimension_break = TRUE;
922 char *s = NULL;
923 char *section = NULL; /* a section of output */
924 int secnum; /* section sequence number */
925 int multiline; /* datum was multiline */
926
927 if (stream == NULL)
928 return dimension_break;
929
930 s = h5tools_str_fmt(buffer, (size_t)0, "%s");
931
932 /*
933 * If the element would split on multiple lines if printed at our
934 * current location...
935 */
936 if (info->line_multi_new == 1 &&
937 (ctx->cur_column + h5tools_count_ncols(s) +
938 HDstrlen(OPT(info->elmt_suf2, " ")) +
939 HDstrlen(OPT(info->line_suf, ""))) > ncols) {
940 if (ctx->prev_multiline) {
941 /*
942 * ... and the previous element also occupied more than one
943 * line, then start this element at the beginning of a line.
944 */
945 ctx->need_prefix = TRUE;
946 }
947 else if ((ctx->prev_prefix_len + h5tools_count_ncols(s) +
948 HDstrlen(OPT(info->elmt_suf2, " ")) +
949 HDstrlen(OPT(info->line_suf, ""))) <= ncols) {
950 /*
951 * ...but *could* fit on one line otherwise, then we
952 * should end the current line and start this element on its
953 * own line.
954 */
955 ctx->need_prefix = TRUE;
956 }
957 }
958
959 /*
960 * We need to break after each row of a dimension---> we should
961 * break at the end of the each last dimension well that is the
962 * way the dumper did it before
963 */
964 if (info->arr_linebreak && ctx->cur_elmt) {
965 if (ctx->size_last_dim && (ctx->cur_elmt % ctx->size_last_dim) == 0)
966 ctx->need_prefix = TRUE;
967
968 if (elmt_counter == ctx->size_last_dim) {
969 ctx->need_prefix = TRUE;
970 dimension_break = FALSE;
971 }
972 }
973
974 /*
975 * If the previous element occupied multiple lines and this element
976 * is too long to fit on a line then start this element at the
977 * beginning of the line.
978 */
979 if (info->line_multi_new == 1 &&
980 ctx->prev_multiline &&
981 (ctx->cur_column +
982 h5tools_count_ncols(s) +
983 HDstrlen(OPT(info->elmt_suf2, " ")) +
984 HDstrlen(OPT(info->line_suf, ""))) > ncols)
985 ctx->need_prefix = TRUE;
986
987 /*
988 * If too many elements have already been printed then we need to
989 * start a new line.
990 */
991 if (info->line_per_line > 0 && ctx->cur_elmt >= info->line_per_line)
992 ctx->need_prefix = TRUE;
993
994 /*
995 * Each OPTIONAL_LINE_BREAK embedded in the rendered string can cause
996 * the data to split across multiple lines. We display the sections
997 * one-at a time.
998 */
999 multiline = 0;
1000 for (secnum = 0, multiline = 0;
1001 (section = HDstrtok(secnum ? NULL : s, OPTIONAL_LINE_BREAK));
1002 secnum++) {
1003 /*
1004 * If the current section plus possible suffix and end-of-line
1005 * information would cause the output to wrap then we need to
1006 * start a new line.
1007 */
1008
1009 /*
1010 * check for displaying prefix for each section
1011 */
1012 if ( (ctx->cur_column + HDstrlen(section) +
1013 HDstrlen(OPT(info->elmt_suf2, " ")) +
1014 HDstrlen(OPT(info->line_suf, ""))) > ncols)
1015 ctx->need_prefix = 1;
1016
1017 /*
1018 * Print the prefix or separate the beginning of this element
1019 * from the previous element.
1020 */
1021 if (ctx->need_prefix) {
1022 if (secnum)
1023 multiline++;
1024
1025 /* pass to the prefix in h5tools_simple_prefix the total
1026 * position instead of the current stripmine position i;
1027 * this is necessary to print the array indices
1028 */
1029 *curr_pos = ctx->sm_pos + local_elmt_counter;
1030
1031 h5tools_simple_prefix(stream, info, ctx, *curr_pos, secnum);
1032 }
1033 else if ((local_elmt_counter || ctx->continuation) && secnum == 0) {
1034 PUTSTREAM(OPT(info->elmt_suf2, " "), stream);
1035 ctx->cur_column += HDstrlen(OPT(info->elmt_suf2, " "));
1036 }
1037
1038 /* Print the section */
1039 PUTSTREAM(section, stream);
1040 ctx->cur_column += HDstrlen(section);
1041 }
1042
1043 ctx->prev_multiline = multiline;
1044 return dimension_break;
1045 }
1046
1047 /*-------------------------------------------------------------------------
1048 * Function: h5tools_render_region_element
1049 *
1050 * Purpose: Prints the string buffer to the output STREAM. The string is
1051 * printed according to the format described in INFO. The CTX struct
1052 * contains context information shared between calls to this function.
1053 *
1054 * Return:
1055 * False if a dimension end is reached
1056 * True otherwise
1057 *
1058 * In/Out:
1059 * h5tools_context_t *ctx
1060 * h5tools_str_t *buffer
1061 * hsize_t *curr_pos
1062 *
1063 * Parameters Description:
1064 * h5tools_str_t *buffer is the string into which to render
1065 * hsize_t curr_pos is the total data element position
1066 * size_t ncols
1067 * hsize_t *ptdata
1068 * hsize_t local_elmt_counter is the local element loop counter
1069 * hsize_t elmt_count is the data element loop counter
1070 *-------------------------------------------------------------------------
1071 */
1072 hbool_t
h5tools_render_region_element(FILE * stream,const h5tool_format_t * info,h5tools_context_t * ctx,h5tools_str_t * buffer,hsize_t * curr_pos,size_t ncols,hsize_t * ptdata,hsize_t local_elmt_counter,hsize_t elmt_counter)1073 h5tools_render_region_element(FILE *stream, const h5tool_format_t *info,
1074 h5tools_context_t *ctx, h5tools_str_t *buffer, hsize_t *curr_pos,
1075 size_t ncols, hsize_t *ptdata, hsize_t local_elmt_counter, hsize_t elmt_counter)
1076 {
1077 hbool_t dimension_break = TRUE;
1078 char *s = NULL;
1079 char *section = NULL; /* a section of output */
1080 int secnum; /* section sequence number */
1081 int multiline; /* datum was multiline */
1082
1083 s = h5tools_str_fmt(buffer, (size_t)0, "%s");
1084
1085 /*
1086 * If the element would split on multiple lines if printed at our
1087 * current location...
1088 */
1089 if (info->line_multi_new == 1 &&
1090 (ctx->cur_column + h5tools_count_ncols(s) +
1091 HDstrlen(OPT(info->elmt_suf2, " ")) +
1092 HDstrlen(OPT(info->line_suf, ""))) > ncols) {
1093 if (ctx->prev_multiline) {
1094 /*
1095 * ... and the previous element also occupied more than one
1096 * line, then start this element at the beginning of a line.
1097 */
1098 ctx->need_prefix = TRUE;
1099 }
1100 else if ((ctx->prev_prefix_len + h5tools_count_ncols(s) +
1101 HDstrlen(OPT(info->elmt_suf2, " ")) +
1102 HDstrlen(OPT(info->line_suf, ""))) <= ncols) {
1103 /*
1104 * ...but *could* fit on one line otherwise, then we
1105 * should end the current line and start this element on its
1106 * own line.
1107 */
1108 ctx->need_prefix = TRUE;
1109 }
1110 }
1111
1112 /*
1113 * We need to break after each row of a dimension---> we should
1114 * break at the end of the each last dimension well that is the
1115 * way the dumper did it before
1116 */
1117 if (info->arr_linebreak && ctx->cur_elmt) {
1118 if (ctx->size_last_dim && (ctx->cur_elmt % ctx->size_last_dim) == 0)
1119 ctx->need_prefix = TRUE;
1120
1121 if (elmt_counter == ctx->size_last_dim) {
1122 ctx->need_prefix = TRUE;
1123 dimension_break = FALSE;
1124 }
1125 }
1126
1127 /*
1128 * If the previous element occupied multiple lines and this element
1129 * is too long to fit on a line then start this element at the
1130 * beginning of the line.
1131 */
1132 if (info->line_multi_new == 1 &&
1133 ctx->prev_multiline &&
1134 (ctx->cur_column +
1135 h5tools_count_ncols(s) +
1136 HDstrlen(OPT(info->elmt_suf2, " ")) +
1137 HDstrlen(OPT(info->line_suf, ""))) > ncols)
1138 ctx->need_prefix = TRUE;
1139
1140 /*
1141 * If too many elements have already been printed then we need to
1142 * start a new line.
1143 */
1144 if (info->line_per_line > 0 && ctx->cur_elmt >= info->line_per_line)
1145 ctx->need_prefix = TRUE;
1146
1147 /*
1148 * Each OPTIONAL_LINE_BREAK embedded in the rendered string can cause
1149 * the data to split across multiple lines. We display the sections
1150 * one-at a time.
1151 */
1152 multiline = 0;
1153 for (secnum = 0, multiline = 0; (section = HDstrtok(secnum ? NULL : s,
1154 OPTIONAL_LINE_BREAK)); secnum++) {
1155 /*
1156 * If the current section plus possible suffix and end-of-line
1157 * information would cause the output to wrap then we need to
1158 * start a new line.
1159 */
1160
1161 /*
1162 * Added the info->skip_first because the dumper does not want
1163 * this check to happen for the first line
1164 */
1165 if ((!info->skip_first || local_elmt_counter) &&
1166 (ctx->cur_column +
1167 HDstrlen(section) +
1168 HDstrlen(OPT(info->elmt_suf2, " ")) +
1169 HDstrlen(OPT(info->line_suf, ""))) > ncols)
1170 ctx->need_prefix = 1;
1171
1172 /*
1173 * Print the prefix or separate the beginning of this element
1174 * from the previous element.
1175 */
1176 if (ctx->need_prefix) {
1177 if (secnum)
1178 multiline++;
1179
1180 /* pass to the prefix in h5tools_simple_prefix the total
1181 * position instead of the current stripmine position i;
1182 * this is necessary to print the array indices
1183 */
1184 *curr_pos = ctx->sm_pos + local_elmt_counter;
1185
1186 h5tools_region_simple_prefix(stream, info, ctx, local_elmt_counter, ptdata, secnum);
1187 }
1188 else if ((local_elmt_counter || ctx->continuation) && secnum == 0) {
1189 PUTSTREAM(OPT(info->elmt_suf2, " "), stream);
1190 ctx->cur_column += HDstrlen(OPT(info->elmt_suf2, " "));
1191 }
1192
1193 /* Print the section */
1194 PUTSTREAM(section, stream);
1195 ctx->cur_column += HDstrlen(section);
1196 }
1197
1198 ctx->prev_multiline = multiline;
1199 return dimension_break;
1200 }
1201
1202 /*-------------------------------------------------------------------------
1203 * Function: init_acc_pos
1204 *
1205 * Purpose: initialize accumulator and matrix position
1206 *
1207 * Return: void
1208 *-------------------------------------------------------------------------
1209 */
1210 void
init_acc_pos(h5tools_context_t * ctx,hsize_t * dims)1211 init_acc_pos(h5tools_context_t *ctx, hsize_t *dims)
1212 {
1213 int i;
1214 unsigned j;
1215
1216 if(ctx->ndims > 0) {
1217 ctx->acc[ctx->ndims - 1] = 1;
1218 for (i = ((int)ctx->ndims - 2); i >= 0; i--)
1219 ctx->acc[i] = ctx->acc[i + 1] * dims[i + 1];
1220 for (j = 0; j < ctx->ndims; j++)
1221 ctx->pos[j] = 0;
1222 }
1223 }
1224
1225 /*-------------------------------------------------------------------------
1226 * Function: render_bin_output
1227 *
1228 * Purpose: Write one element of memory buffer to a binary file stream
1229 *
1230 * Return: Success: SUCCEED
1231 * Failure: FAIL
1232 *-------------------------------------------------------------------------
1233 */
1234 int
render_bin_output(FILE * stream,hid_t container,hid_t tid,void * _mem,hsize_t block_nelmts)1235 render_bin_output(FILE *stream, hid_t container, hid_t tid, void *_mem, hsize_t block_nelmts)
1236 {
1237 HERR_INIT(int, SUCCEED)
1238 unsigned char *mem = (unsigned char*)_mem;
1239 size_t size; /* datum size */
1240 hsize_t block_index;
1241 H5T_class_t type_class;
1242
1243 if((size = H5Tget_size(tid)) == 0)
1244 H5E_THROW(FAIL, H5E_tools_min_id_g, "H5Tget_size failed");
1245
1246 if((type_class = H5Tget_class(tid)) < 0)
1247 H5E_THROW(FAIL, H5E_tools_min_id_g, "H5Tget_class failed");
1248
1249 switch (type_class) {
1250 case H5T_INTEGER:
1251 case H5T_FLOAT:
1252 case H5T_ENUM:
1253 case H5T_BITFIELD:
1254 block_index = block_nelmts * size;
1255 while(block_index > 0) {
1256 size_t bytes_in = 0; /* # of bytes to write */
1257 size_t bytes_wrote = 0; /* # of bytes written */
1258
1259 if(block_index > sizeof(size_t))
1260 bytes_in = sizeof(size_t);
1261 else
1262 bytes_in = (size_t)block_index;
1263
1264 bytes_wrote = HDfwrite(mem, 1, bytes_in, stream);
1265
1266 if(bytes_wrote != bytes_in || (0 == bytes_wrote && HDferror(stream)))
1267 H5E_THROW(FAIL, H5E_tools_min_id_g, "fwrite failed");
1268
1269 block_index -= (hsize_t)bytes_wrote;
1270 mem = mem + bytes_wrote;
1271 }
1272 break;
1273 case H5T_STRING:
1274 {
1275 unsigned int i;
1276 H5T_str_t pad;
1277 char *s = NULL;
1278 unsigned char tempuchar;
1279
1280 pad = H5Tget_strpad(tid);
1281
1282 for (block_index = 0; block_index < block_nelmts; block_index++) {
1283 mem = ((unsigned char*)_mem) + block_index * size;
1284
1285 if (H5Tis_variable_str(tid)) {
1286 s = *(char**) mem;
1287 if (s != NULL)
1288 size = HDstrlen(s);
1289 else
1290 H5E_THROW(FAIL, H5E_tools_min_id_g, "NULL string");
1291 }
1292 else {
1293 s = (char *) mem;
1294 }
1295 for (i = 0; i < size && (s[i] || pad != H5T_STR_NULLTERM); i++) {
1296 HDmemcpy(&tempuchar, &s[i], sizeof(unsigned char));
1297 if (1 != HDfwrite(&tempuchar, sizeof(unsigned char), 1, stream))
1298 H5E_THROW(FAIL, H5E_tools_min_id_g, "fwrite failed");
1299 } /* i */
1300 } /* for (block_index = 0; block_index < block_nelmts; block_index++) */
1301 }
1302 break;
1303 case H5T_COMPOUND:
1304 {
1305 int snmembs;
1306 unsigned nmembs;
1307
1308 if((snmembs = H5Tget_nmembers(tid)) < 0)
1309 H5E_THROW(FAIL, H5E_tools_min_id_g, "H5Tget_nmembers of compound failed");
1310 nmembs = (unsigned)snmembs;
1311
1312 for (block_index = 0; block_index < block_nelmts; block_index++) {
1313 unsigned j;
1314
1315 mem = ((unsigned char*)_mem) + block_index * size;
1316 for (j = 0; j < nmembs; j++) {
1317 hid_t memb = -1;
1318 size_t offset;
1319
1320 offset = H5Tget_member_offset(tid, j);
1321 memb = H5Tget_member_type(tid, j);
1322
1323 if (render_bin_output(stream, container, memb, mem + offset, 1) < 0) {
1324 H5Tclose(memb);
1325 H5E_THROW(FAIL, H5E_tools_min_id_g, "render_bin_output of compound member failed");
1326 }
1327
1328 H5Tclose(memb);
1329 }
1330 }
1331 }
1332 break;
1333 case H5T_ARRAY:
1334 {
1335 int k, ndims;
1336 hsize_t dims[H5S_MAX_RANK], temp_nelmts, nelmts;
1337 hid_t memb = -1;
1338
1339 /* get the array's base datatype for each element */
1340 memb = H5Tget_super(tid);
1341 ndims = H5Tget_array_ndims(tid);
1342 H5Tget_array_dims2(tid, dims);
1343 if(ndims >= 1 && ndims <= H5S_MAX_RANK) {
1344 /* calculate the number of array elements */
1345 for (k = 0, nelmts = 1; k < ndims; k++) {
1346 temp_nelmts = nelmts;
1347 temp_nelmts *= dims[k];
1348 nelmts = (size_t) temp_nelmts;
1349 }
1350 }
1351 else {
1352 H5Tclose(memb);
1353 H5E_THROW(FAIL, H5E_tools_min_id_g, "calculate the number of array elements failed");
1354 }
1355
1356 for (block_index = 0; block_index < block_nelmts; block_index++) {
1357 mem = ((unsigned char*)_mem) + block_index * size;
1358 /* dump the array element */
1359 if (render_bin_output(stream, container, memb, mem, nelmts) < 0) {
1360 H5Tclose(memb);
1361 H5E_THROW(FAIL, H5E_tools_min_id_g, "render_bin_output failed");
1362 }
1363 }
1364 H5Tclose(memb);
1365 }
1366 break;
1367 case H5T_VLEN:
1368 {
1369 hsize_t nelmts;
1370 hid_t memb = -1;
1371
1372 /* get the VL sequences's base datatype for each element */
1373 memb = H5Tget_super(tid);
1374
1375 for (block_index = 0; block_index < block_nelmts; block_index++) {
1376 mem = ((unsigned char*)_mem) + block_index * size;
1377 /* Get the number of sequence elements */
1378 nelmts = ((hvl_t *) mem)->len;
1379
1380 /* dump the array element */
1381 if (render_bin_output(stream, container, memb, ((char *) (((hvl_t *) mem)->p)), nelmts) < 0) {
1382 H5Tclose(memb);
1383 H5E_THROW(FAIL, H5E_tools_min_id_g, "render_bin_output failed");
1384 }
1385 }
1386 H5Tclose(memb);
1387 }
1388 break;
1389 case H5T_REFERENCE:
1390 {
1391 if (size == H5R_DSET_REG_REF_BUF_SIZE) {
1392 /* if (H5Tequal(tid, H5T_STD_REF_DSETREG)) */
1393 if (region_output) {
1394 /* region data */
1395 hid_t region_id = -1;
1396 hid_t region_space = -1;
1397 H5S_sel_type region_type;
1398
1399 for (block_index = 0; block_index < block_nelmts; block_index++) {
1400 mem = ((unsigned char*)_mem) + block_index * size;
1401 region_id = H5Rdereference(container, H5R_DATASET_REGION, mem);
1402 if (region_id >= 0) {
1403 region_space = H5Rget_region(container, H5R_DATASET_REGION, mem);
1404 if (region_space >= 0) {
1405 region_type = H5Sget_select_type(region_space);
1406 if(region_type == H5S_SEL_POINTS)
1407 render_bin_output_region_points(region_space, region_id, stream, container);
1408 else
1409 render_bin_output_region_blocks(region_space, region_id, stream, container);
1410 H5Sclose(region_space);
1411 } /* end if (region_space >= 0) */
1412 H5Dclose(region_id);
1413 } /* end if (region_id >= 0) */
1414 }
1415 } /* end if (region_output... */
1416 }
1417 else if (size == H5R_OBJ_REF_BUF_SIZE) {
1418 /* if (H5Tequal(tid, H5T_STD_REF_OBJ)) */
1419 ;
1420 }
1421 }
1422 break;
1423
1424 case H5T_TIME:
1425 case H5T_OPAQUE:
1426 for (block_index = 0; block_index < block_nelmts; block_index++) {
1427 mem = ((unsigned char*)_mem) + block_index * size;
1428 if (size != HDfwrite(mem, sizeof(char), size, stream))
1429 H5E_THROW(FAIL, H5E_tools_min_id_g, "fwrite failed");
1430 } /* end for */
1431 break;
1432
1433 case H5T_NO_CLASS:
1434 case H5T_NCLASSES:
1435 default:
1436 /* Badness */
1437 H5E_THROW(FAIL, H5E_tools_min_id_g, "bad type class");
1438 break;
1439 } /* end switch */
1440
1441 CATCH
1442 return ret_value;
1443 }
1444
1445 /*-------------------------------------------------------------------------
1446 * Function: render_bin_output_region_data_blocks
1447 *
1448 * Purpose: Print the data values from a dataset referenced by region blocks.
1449 * This is a special case subfunction to print the data in a region reference of type blocks.
1450 *
1451 * Return: FAIL if there was an error
1452 * SUCCEED otherwise
1453 *
1454 *-------------------------------------------------------------------------
1455 */
1456 int
render_bin_output_region_data_blocks(hid_t region_id,FILE * stream,hid_t container,unsigned ndims,hid_t type_id,hsize_t nblocks,hsize_t * ptdata)1457 render_bin_output_region_data_blocks(hid_t region_id, FILE *stream,
1458 hid_t container, unsigned ndims, hid_t type_id, hsize_t nblocks, hsize_t *ptdata)
1459 {
1460 hsize_t *dims1 = NULL;
1461 hsize_t *start = NULL;
1462 hsize_t *count = NULL;
1463 hsize_t numelem;
1464 hsize_t total_size[H5S_MAX_RANK];
1465 unsigned jndx;
1466 size_t type_size;
1467 hid_t mem_space = -1;
1468 void *region_buf = NULL;
1469 hsize_t blkndx;
1470 hid_t sid1 = -1;
1471 int ret_value = SUCCEED;
1472
1473 /* Get the dataspace of the dataset */
1474 if((sid1 = H5Dget_space(region_id)) < 0)
1475 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Dget_space failed");
1476
1477 /* Allocate space for the dimension array */
1478 if((dims1 = (hsize_t *) HDmalloc(sizeof(hsize_t) * ndims)) == NULL)
1479 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "Could not allocate buffer for dims");
1480
1481 /* find the dimensions of each data space from the block coordinates */
1482 numelem = 1;
1483 for (jndx = 0; jndx < ndims; jndx++) {
1484 dims1[jndx] = ptdata[jndx + ndims] - ptdata[jndx] + 1;
1485 numelem = dims1[jndx] * numelem;
1486 }
1487
1488 /* Create dataspace for reading buffer */
1489 if((mem_space = H5Screate_simple((int)ndims, dims1, NULL)) < 0)
1490 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Screate_simple failed");
1491
1492 if((type_size = H5Tget_size(type_id)) == 0)
1493 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Tget_size failed");
1494
1495 if((region_buf = HDmalloc(type_size * (size_t)numelem)) == NULL)
1496 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "Could not allocate region buffer");
1497
1498 /* Select (x , x , ..., x ) x (y , y , ..., y ) hyperslab for reading memory dataset */
1499 /* 1 2 n 1 2 n */
1500 if((start = (hsize_t *) HDmalloc(sizeof(hsize_t) * ndims)) == NULL)
1501 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "Could not allocate buffer for start");
1502
1503 if((count = (hsize_t *) HDmalloc(sizeof(hsize_t) * ndims)) == NULL)
1504 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "Could not allocate buffer for count");
1505
1506 for (blkndx = 0; blkndx < nblocks; blkndx++) {
1507 for (jndx = 0; jndx < ndims; jndx++) {
1508 start[jndx] = ptdata[jndx + blkndx * ndims * 2];
1509 count[jndx] = dims1[jndx];
1510 }
1511
1512 if(H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, NULL, count, NULL) < 0)
1513 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Sselect_hyperslab failed");
1514
1515 if(H5Dread(region_id, type_id, mem_space, sid1, H5P_DEFAULT, region_buf) < 0)
1516 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Dread failed");
1517
1518 if(H5Sget_simple_extent_dims(mem_space, total_size, NULL) < 0)
1519 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Sget_simple_extent_dims failed");
1520
1521 if(render_bin_output(stream, container, type_id, (char*)region_buf, numelem) < 0)
1522 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "render_bin_output of data region failed");
1523 /* Render the region data element end */
1524 } /* end for (blkndx = 0; blkndx < nblocks; blkndx++) */
1525
1526 done:
1527 HDfree(start);
1528 HDfree(count);
1529 HDfree(region_buf);
1530 HDfree(dims1);
1531
1532 if(H5Sclose(mem_space) < 0)
1533 HERROR(H5E_tools_g, H5E_tools_min_id_g, "H5Sclose failed");
1534 if(H5Sclose(sid1) < 0)
1535 HERROR(H5E_tools_g, H5E_tools_min_id_g, "H5Sclose failed");
1536
1537 return ret_value;
1538 }
1539
1540 /*-------------------------------------------------------------------------
1541 * Function: render_bin_output_region_blocks
1542 *
1543 * Purpose: Print some values from a dataset referenced by region blocks.
1544 * This is a special case subfunction to dump a region reference using blocks.
1545 *
1546 * Return: False if ERROR
1547 * True otherwise
1548 *-------------------------------------------------------------------------
1549 */
1550 hbool_t
render_bin_output_region_blocks(hid_t region_space,hid_t region_id,FILE * stream,hid_t container)1551 render_bin_output_region_blocks(hid_t region_space, hid_t region_id,
1552 FILE *stream, hid_t container)
1553 {
1554 HERR_INIT(hbool_t, TRUE)
1555 hssize_t snblocks;
1556 hsize_t nblocks;
1557 hsize_t alloc_size;
1558 hsize_t *ptdata = NULL;
1559 int sndims;
1560 unsigned ndims;
1561 hid_t dtype = -1;
1562 hid_t type_id = -1;
1563
1564 if((snblocks = H5Sget_select_hyper_nblocks(region_space)) <= 0)
1565 H5E_THROW(FALSE, H5E_tools_min_id_g, "H5Sget_select_hyper_nblocks failed");
1566 nblocks = (hsize_t)snblocks;
1567
1568 /* Print block information */
1569 if((sndims = H5Sget_simple_extent_ndims(region_space)) < 0)
1570 H5E_THROW(FALSE, H5E_tools_min_id_g, "H5Sget_simple_extent_ndims failed");
1571 ndims = (unsigned)sndims;
1572
1573 alloc_size = nblocks * ndims * 2 * sizeof(ptdata[0]);
1574 if((ptdata = (hsize_t*) HDmalloc((size_t) alloc_size)) == NULL)
1575 HGOTO_ERROR(FALSE, H5E_tools_min_id_g, "Could not allocate buffer for ptdata");
1576
1577 if(H5Sget_select_hyper_blocklist(region_space, (hsize_t) 0, nblocks, ptdata) < 0)
1578 HGOTO_ERROR(FALSE, H5E_tools_min_id_g, "H5Rget_select_hyper_blocklist failed");
1579
1580 if((dtype = H5Dget_type(region_id)) < 0)
1581 HGOTO_ERROR(FALSE, H5E_tools_min_id_g, "H5Dget_type failed");
1582 if((type_id = H5Tget_native_type(dtype, H5T_DIR_DEFAULT)) < 0)
1583 HGOTO_ERROR(FALSE, H5E_tools_min_id_g, "H5Tget_native_type failed");
1584
1585 render_bin_output_region_data_blocks(region_id, stream, container, ndims,
1586 type_id, nblocks, ptdata);
1587
1588 done:
1589 HDfree(ptdata);
1590
1591 if(type_id > 0 && H5Tclose(type_id) < 0)
1592 HERROR(H5E_tools_g, H5E_tools_min_id_g, "H5Tclose failed");
1593
1594 if(dtype > 0 && H5Tclose(dtype) < 0)
1595 HERROR(H5E_tools_g, H5E_tools_min_id_g, "H5Tclose failed");
1596
1597 H5_LEAVE(TRUE)
1598
1599 CATCH
1600 return ret_value;
1601 }
1602
1603 /*-------------------------------------------------------------------------
1604 * Function: H5Tools Library
1605 * Purpose: Print the data values from a dataset referenced by region points.
1606 *
1607 * Description:
1608 * This is a special case subfunction to print the data in a region reference of type points.
1609 *
1610 * Return:
1611 * The function returns FAIL on error, otherwise SUCCEED
1612 *
1613 * Parameters Description:
1614 * h5tools_str_t *buffer is the string into which to render
1615 * size_t ncols
1616 * int ndims is the number of dimensions of the region element
1617 * hssize_t npoints is the number of points in the region
1618 *-------------------------------------------------------------------------
1619 */
1620 int
render_bin_output_region_data_points(hid_t region_space,hid_t region_id,FILE * stream,hid_t container,unsigned ndims,hid_t type_id,hsize_t npoints)1621 render_bin_output_region_data_points(hid_t region_space, hid_t region_id,
1622 FILE *stream, hid_t container,
1623 unsigned ndims, hid_t type_id, hsize_t npoints)
1624 {
1625 hsize_t *dims1 = NULL;
1626 size_t type_size;
1627 hid_t mem_space = -1;
1628 void *region_buf = NULL;
1629 int ret_value = SUCCEED;
1630
1631 if((type_size = H5Tget_size(type_id)) == 0)
1632 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Tget_size failed");
1633
1634 if((region_buf = HDmalloc(type_size * (size_t)npoints)) == NULL)
1635 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "Could not allocate buffer for region");
1636
1637 /* Allocate space for the dimension array */
1638 if((dims1 = (hsize_t *) HDmalloc(sizeof(hsize_t) * ndims)) == NULL)
1639 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "Could not allocate buffer for dims");
1640
1641 dims1[0] = npoints;
1642 if((mem_space = H5Screate_simple(1, dims1, NULL)) < 0)
1643 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Screate_simple failed");
1644
1645 if(H5Dread(region_id, type_id, mem_space, region_space, H5P_DEFAULT, region_buf) < 0)
1646 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Dread failed");
1647 if(H5Sget_simple_extent_dims(region_space, dims1, NULL) < 0)
1648 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Sget_simple_extent_dims failed");
1649
1650 if(render_bin_output(stream, container, type_id, (char*)region_buf, npoints) < 0)
1651 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "render_bin_output of data points failed");
1652
1653 done:
1654 HDfree(region_buf);
1655 HDfree(dims1);
1656
1657 if(H5Sclose(mem_space) < 0)
1658 HERROR(H5E_tools_g, H5E_tools_min_id_g, "H5Sclose failed");
1659
1660 return ret_value;
1661 }
1662
1663 /*-------------------------------------------------------------------------
1664 * Function: render_bin_output_region_points
1665 *
1666 * Purpose: Print some values from a dataset referenced by region points.
1667 * This is a special case function to dump a region reference using points.
1668 *
1669 * Return: False if the last dimension has been reached
1670 * True otherwise
1671 *-------------------------------------------------------------------------
1672 */
1673 hbool_t
render_bin_output_region_points(hid_t region_space,hid_t region_id,FILE * stream,hid_t container)1674 render_bin_output_region_points(hid_t region_space, hid_t region_id,
1675 FILE *stream, hid_t container)
1676 {
1677 HERR_INIT(hbool_t, TRUE)
1678 hssize_t snpoints;
1679 hsize_t npoints;
1680 int sndims;
1681 unsigned ndims;
1682 hid_t dtype = -1;
1683 hid_t type_id = -1;
1684
1685 if((snpoints = H5Sget_select_elem_npoints(region_space)) <= 0)
1686 H5E_THROW(FALSE, H5E_tools_min_id_g, "H5Sget_select_elem_npoints failed");
1687 npoints = (hsize_t)snpoints;
1688
1689 /* Allocate space for the dimension array */
1690 if((sndims = H5Sget_simple_extent_ndims(region_space)) < 0)
1691 H5E_THROW(FALSE, H5E_tools_min_id_g, "H5Sget_simple_extent_ndims failed");
1692 ndims = (unsigned)sndims;
1693
1694 if((dtype = H5Dget_type(region_id)) < 0)
1695 HGOTO_ERROR(FALSE, H5E_tools_min_id_g, "H5Dget_type failed");
1696
1697 if((type_id = H5Tget_native_type(dtype, H5T_DIR_DEFAULT)) < 0)
1698 HGOTO_ERROR(FALSE, H5E_tools_min_id_g, "H5Tget_native_type failed");
1699
1700 render_bin_output_region_data_points(region_space, region_id,
1701 stream, container, ndims, type_id, npoints);
1702
1703 done:
1704 if(type_id > 0 && H5Tclose(type_id) < 0)
1705 HERROR(H5E_tools_g, H5E_tools_min_id_g, "H5Tclose failed");
1706
1707 if(dtype > 0 && H5Tclose(dtype) < 0)
1708 HERROR(H5E_tools_g, H5E_tools_min_id_g, "H5Tclose failed");
1709
1710 H5_LEAVE(ret_value)
1711 CATCH
1712 return ret_value;
1713 }
1714
1715 /*-------------------------------------------------------------------------
1716 * Function: h5tools_is_zero
1717 *
1718 * Purpose: Determines if memory is initialized to all zero bytes.
1719 *
1720 * Return: TRUE if all bytes are zero
1721 * FALSE otherwise
1722 *-------------------------------------------------------------------------
1723 */
1724 hbool_t
h5tools_is_zero(const void * _mem,size_t size)1725 h5tools_is_zero(const void *_mem, size_t size)
1726 {
1727 const unsigned char *mem = (const unsigned char *) _mem;
1728
1729 while (size-- > 0)
1730 if (mem[size])
1731 return FALSE;
1732
1733 return TRUE;
1734 }
1735
1736 /*-------------------------------------------------------------------------
1737 * Function: h5tools_is_obj_same
1738 *
1739 * Purpose: Check if two given object IDs or link names point to the same object.
1740 *
1741 * Parameters:
1742 * hid_t loc_id1: location of the first object
1743 * char *name1: link name of the first object.
1744 * Use "." or NULL if loc_id1 is the object to be compared.
1745 * hid_t loc_id2: location of the second object
1746 * char *name1: link name of the first object.
1747 * Use "." or NULL if loc_id2 is the object to be compared.
1748 *
1749 * Return: TRUE if it is the same object
1750 * FALSE otherwise.
1751 *-------------------------------------------------------------------------
1752 */
1753 hbool_t
h5tools_is_obj_same(hid_t loc_id1,const char * name1,hid_t loc_id2,const char * name2)1754 h5tools_is_obj_same(hid_t loc_id1, const char *name1,
1755 hid_t loc_id2, const char *name2)
1756 {
1757 H5O_info_t oinfo1, oinfo2;
1758 hbool_t ret_val = 0;
1759
1760 if ( name1 && HDstrcmp(name1, "."))
1761 H5Oget_info_by_name(loc_id1, name1, &oinfo1, H5P_DEFAULT);
1762 else
1763 H5Oget_info(loc_id1, &oinfo1);
1764
1765 if ( name2 && HDstrcmp(name2, "."))
1766 H5Oget_info_by_name(loc_id2, name2, &oinfo2, H5P_DEFAULT);
1767 else
1768 H5Oget_info(loc_id2, &oinfo2);
1769
1770 if (oinfo1.fileno == oinfo2.fileno && oinfo1.addr==oinfo2.addr)
1771 ret_val = 1;
1772
1773 return ret_val;
1774 }
1775
1776