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