1 /* This is part of the netCDF package.
2    Copyright 2018 University Corporation for Atmospheric Research/Unidata
3    See COPYRIGHT file for conditions of use.
4 
5    Test HDF5 file code. These are not intended to be exhaustive tests,
6    but they use HDF5 the same way that netCDF-4 does, so if these
7    tests don't work, than netCDF-4 won't work either.
8 
9    This program deals with HDF5 compound types.
10 
11    $Id: tst_h_compounds2.c,v 1.17 2010/06/01 15:34:51 ed Exp $
12 */
13 
14 #include "h5_err_macros.h"
15 #include <hdf5.h>
16 
17 #define FILE_NAME "tst_h_compounds2.h5"
18 #define REF_FILE_IN "ref_tst_h_compounds2.h5"
19 #define STR_LEN 255
20 
21 int
main()22 main()
23 {
24    printf("\n*** Checking HDF5 compound types some more.\n");
25    printf("*** Checking HDF5 compound attribute which contains a simple compound type...");
26    {
27 #define DIM_CMP_LEN 1
28 #define ATT_NAME1 "The_Nutmeg_of_Consolation"
29 #define NUM_TYPES 2
30 #define INNER_TYPE_NAME "s1"
31 #define OUTER_TYPE_NAME "d"
32 
33       /* This struct will be embeddeded in another. */
34       struct s1
35       {
36             float x;
37             double y;
38       };
39       struct s2
40       {
41             struct s1 s1;
42       };
43       struct s2 data_out[DIM_CMP_LEN], data_in[DIM_CMP_LEN];
44       hid_t fileid, grpid, typeid_inner, typeid_outer, spaceid, attid;
45       hid_t obj_hdf_typeid[NUM_TYPES], obj_native_typeid[NUM_TYPES];
46       hid_t inner_type_native_typeid;
47       hid_t att_typeid, att_native_typeid;
48       hsize_t dims[1];
49       hsize_t num_obj, i_obj;
50       char obj_name[STR_LEN + 1];
51 #if H5_VERSION_GE(1,12,0)
52       H5O_info2_t obj_info;
53 #else
54       H5O_info_t obj_info;
55 #endif
56       hid_t fapl_id, fcpl_id;
57       htri_t equal;
58       char file_in[STR_LEN * 2];
59       char *dummy;
60       int i;
61 
62       /* REALLY initialize the data (even the gaps in the structs). This
63        * is only needed to pass valgrind. */
64       if (!(dummy = calloc(sizeof(struct s2), DIM_CMP_LEN))) ERR;
65       memcpy((void *)data_out, (void *)dummy, sizeof(struct s2) * DIM_CMP_LEN);
66       free(dummy);
67 
68       /* Create some phony data. */
69       for (i = 0; i < DIM_CMP_LEN; i++)
70       {
71          data_out[i].s1.x = 1.0;
72          data_out[i].s1.y = -2.0;
73       }
74 
75       /* Create file access and create property lists. */
76       if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) ERR;
77       if ((fcpl_id = H5Pcreate(H5P_FILE_CREATE)) < 0) ERR;
78       if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) ERR;
79       if (H5Pset_link_creation_order(fcpl_id, (H5P_CRT_ORDER_TRACKED |
80 					       H5P_CRT_ORDER_INDEXED)) < 0) ERR;
81       if (H5Pset_attr_creation_order(fcpl_id, (H5P_CRT_ORDER_TRACKED |
82 					       H5P_CRT_ORDER_INDEXED)) < 0) ERR;
83 
84       /* Create file and get root group. */
85       if ((fileid = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, fcpl_id, fapl_id)) < 0) ERR;
86       if ((grpid = H5Gopen(fileid, "/")) < 0) ERR;
87 
88       /* Create the inner compound type. */
89       if ((typeid_inner = H5Tcreate(H5T_COMPOUND, sizeof(struct s1))) < 0) ERR;
90       if (H5Tinsert(typeid_inner, "x", HOFFSET(struct s1, x), H5T_NATIVE_FLOAT) < 0) ERR;
91       if (H5Tinsert(typeid_inner, "y", HOFFSET(struct s1, y), H5T_NATIVE_DOUBLE) < 0) ERR;
92       if (H5Tcommit(grpid, INNER_TYPE_NAME, typeid_inner) < 0) ERR;
93 
94       /* Create a compound type containing a compound type. */
95       if ((typeid_outer = H5Tcreate(H5T_COMPOUND, sizeof(struct s2))) < 0) ERR;
96       if (H5Tinsert(typeid_outer, INNER_TYPE_NAME, HOFFSET(struct s2, s1), typeid_inner) < 0) ERR;
97       if (H5Tcommit(grpid, OUTER_TYPE_NAME, typeid_outer) < 0) ERR;
98 
99       /* Create a space. */
100       dims[0] = DIM_CMP_LEN;
101       if ((spaceid = H5Screate_simple(1, dims, dims)) < 0) ERR;
102 
103       /* Create an attribute of this compound type. */
104       if ((attid = H5Acreate2(grpid, ATT_NAME1, typeid_outer, spaceid, H5P_DEFAULT, H5P_DEFAULT)) < 0) ERR;
105 
106       /* Write some data to the attribute. */
107       if (H5Awrite(attid, typeid_outer, data_out) < 0) ERR;
108 
109       /* Release all resources. */
110       if (H5Aclose(attid) < 0 ||
111           H5Tclose(typeid_outer) < 0 ||
112           H5Tclose(typeid_inner) < 0 ||
113           H5Sclose(spaceid) < 0 ||
114           H5Gclose(grpid) < 0 ||
115           H5Fclose(fileid) < 0) ERR;
116 
117       /* Now open the file and get the type of the attribute. */
118       if ((fileid = H5Fopen(FILE_NAME, H5F_ACC_RDONLY, H5P_DEFAULT)) < 0) ERR;
119       if ((grpid = H5Gopen(fileid, "/")) < 0) ERR;
120       if ((attid = H5Aopen_by_name(grpid, ".", ATT_NAME1, H5P_DEFAULT, H5P_DEFAULT)) < 0) ERR;
121       if ((att_typeid = H5Aget_type(attid)) < 0) ERR;
122       if ((att_native_typeid = H5Tget_native_type(att_typeid, H5T_DIR_DEFAULT)) < 0) ERR;
123 
124       /* Find the HDF ID of the inner type. */
125       if ((inner_type_native_typeid = H5Tget_member_type(att_native_typeid, 0)) < 0) ERR;
126 
127       /* Check the data. */
128       if (H5Aread(attid, att_native_typeid, data_in) < 0) ERR;
129       for (i = 0; i < DIM_CMP_LEN; i++)
130          if (data_out[i].s1.x != data_in[i].s1.x ||
131              data_out[i].s1.y != data_in[i].s1.y) ERR;
132 
133       /* Now iterate through the objects in the file, finding the two
134        * defined compound types. */
135       if (H5Gget_num_objs(grpid, &num_obj) < 0) ERR;
136       for (i_obj = 0; i_obj < num_obj; i_obj++)
137       {
138 #if H5_VERSION_GE(1,12,0)
139 	 if (H5Oget_info_by_idx3(grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC,
140                                  i_obj, &obj_info, H5O_INFO_BASIC, H5P_DEFAULT) < 0) ERR;
141 #else
142 	 if (H5Oget_info_by_idx(grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC,
143 				i_obj, &obj_info, H5P_DEFAULT) < 0) ERR;
144 #endif
145 	 if (H5Lget_name_by_idx(grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC,
146 				i_obj, obj_name, STR_LEN + 1, H5P_DEFAULT) < 0) ERR;
147 
148 	 /* Deal with groups and datasets. */
149 	 if (obj_info.type == H5O_TYPE_NAMED_DATATYPE)
150 	 {
151 	    /* Learn about the user-defined type. */
152 	    if ((obj_hdf_typeid[i_obj] = H5Topen2(grpid, obj_name,
153 						  H5P_DEFAULT)) < 0) ERR;
154 	    if ((obj_native_typeid[i_obj] = H5Tget_native_type(obj_hdf_typeid[i_obj],
155 							       H5T_DIR_DEFAULT)) < 0) ERR;
156 
157 	    /* If this is the inner type, the obj_native_typeid
158 	     * should be equal to the inner_type_native_typeid. */
159 	    if (!strcmp(obj_name, INNER_TYPE_NAME))
160 	    {
161 	       if ((equal = H5Tequal(obj_native_typeid[i_obj],
162 				     inner_type_native_typeid)) < 0) ERR;
163 	       if (!equal) ERR;
164 	    }
165 	 }
166       }
167 
168       /* Release all resources. */
169       if (H5Aclose(attid) < 0 ||
170           H5Tclose(att_typeid) < 0 ||
171           H5Tclose(att_native_typeid) < 0 ||
172           H5Gclose(grpid) < 0 ||
173           H5Fclose(fileid) < 0) ERR;
174 
175       /* Now open the reference file, created on buddy, and check it
176        * all again. This is the cross-platform part! */
177       if (getenv("srcdir"))
178       {
179          strcpy(file_in, getenv("srcdir"));
180          strcat(file_in, "/");
181          strcat(file_in, REF_FILE_IN);
182       }
183       else
184          strcpy(file_in, REF_FILE_IN);
185 
186       if ((fileid = H5Fopen(file_in, H5F_ACC_RDONLY, H5P_DEFAULT)) < 0) ERR;
187       if ((grpid = H5Gopen(fileid, "/")) < 0) ERR;
188       if ((attid = H5Aopen_by_name(grpid, ".", ATT_NAME1, H5P_DEFAULT, H5P_DEFAULT)) < 0) ERR;
189       if ((att_typeid = H5Aget_type(attid)) < 0) ERR;
190       if ((att_native_typeid = H5Tget_native_type(att_typeid, H5T_DIR_DEFAULT)) < 0) ERR;
191 
192       /* Check the data. */
193       if (H5Aread(attid, att_native_typeid, data_in) < 0) ERR;
194       for (i = 0; i < DIM_CMP_LEN; i++)
195          if (data_out[i].s1.x != data_in[i].s1.x ||
196              data_out[i].s1.y != data_in[i].s1.y) ERR;
197 
198       /* Find the HDF ID of the inner type. */
199       if ((inner_type_native_typeid = H5Tget_member_type(att_native_typeid, 0)) < 0) ERR;
200 
201       /* Now iterate through the objects in the file, finding the two
202        * defined compound types. */
203       if (H5Gget_num_objs(grpid, &num_obj) < 0) ERR;
204       for (i_obj = 0; i_obj < num_obj; i_obj++)
205       {
206 #if H5_VERSION_GE(1,12,0)
207          if (H5Oget_info_by_idx3(grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, i_obj, &obj_info,
208                                  H5O_INFO_BASIC, H5P_DEFAULT) < 0) ERR;
209 #else
210 	 if (H5Oget_info_by_idx(grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, i_obj, &obj_info,
211 				H5P_DEFAULT) < 0) ERR;
212 #endif
213 	 if (H5Lget_name_by_idx(grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, i_obj, obj_name,
214 				STR_LEN + 1, H5P_DEFAULT) < 0) ERR;
215 
216 	 /* Deal with groups and datasets. */
217 	 if (obj_info.type == H5O_TYPE_NAMED_DATATYPE)
218 	 {
219 	    /* Learn about the user-defined type. */
220 	    if ((obj_hdf_typeid[i_obj] = H5Topen2(grpid, obj_name, H5P_DEFAULT)) < 0) ERR;
221 	    if ((obj_native_typeid[i_obj] = H5Tget_native_type(obj_hdf_typeid[i_obj],
222 							       H5T_DIR_DEFAULT)) < 0) ERR;
223 
224 	    /* If this is the inner type, the obj_native_typeid
225 	     * should be equal to the inner_type_native_typeid. */
226 	    if (!strcmp(obj_name, INNER_TYPE_NAME))
227 	    {
228 	       if ((equal = H5Tequal(obj_native_typeid[i_obj], inner_type_native_typeid)) < 0) ERR;
229 	       if (!equal) ERR;
230 	    }
231 	 }
232       }
233 
234       /* Release all resources. */
235       if (H5Aclose(attid) < 0 ||
236           H5Tclose(att_typeid) < 0 ||
237           H5Tclose(att_native_typeid) < 0 ||
238           H5Gclose(grpid) < 0 ||
239           H5Fclose(fileid) < 0) ERR;
240 
241    }
242    SUMMARIZE_ERR;
243    FINAL_RESULTS;
244 }
245