1 /* This is part of the netCDF package.  Copyright 2005 University
2    Corporation for Atmospheric Research/Unidata See COPYRIGHT file for
3    conditions of use.
4 
5    This program does HDF5 string stuff.
6 
7    Here's a HDF5 sample programs:
8    http://hdf.ncsa.uiuc.edu/training/other-ex5/sample-programs/strings.c
9 */
10 #include <string.h>
11 #include "h5_err_macros.h"
12 #include <hdf5.h>
13 
14 #define FILE_NAME "tst_h_strings.h5"
15 #define DIM1_LEN 3
16 #define ATT_NAME "Stooge_Statements"
17 #define GRP_NAME "Stooge_Antic_Metrics"
18 
19 int
main()20 main()
21 {
22    printf("\n*** Checking HDF5 string types.\n");
23    printf("*** Checking scalar string attribute...");
24    {
25       hid_t fileid, grpid, spaceid, typeid, attid;
26       hid_t class;
27       size_t type_size;
28       htri_t is_str;
29 
30       const char *data = "The art of war is of vital "
31 	 "importance to the State. It is a matter of life and death, a road either"
32 	 "to safety or to ruin.  Hence it is a subject of inquiry"
33 	 "which can on no account be neglected.";
34 
35       char *data_in = NULL;
36 
37       /* Open file. */
38       if ((fileid = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT,
39 			      H5P_DEFAULT)) < 0) ERR;
40       if ((grpid = H5Gcreate(fileid, GRP_NAME, 0)) < 0) ERR;
41 
42       /* Create string type. */
43       if ((typeid =  H5Tcopy(H5T_C_S1)) < 0) ERR;
44       if (H5Tset_size(typeid, H5T_VARIABLE) < 0) ERR;
45 
46       /* Write an attribute of this type. */
47       if ((spaceid = H5Screate(H5S_SCALAR)) < 0) ERR;
48       if ((attid = H5Acreate(grpid, ATT_NAME, typeid, spaceid,
49 			     H5P_DEFAULT)) < 0) ERR;
50       if (H5Awrite(attid, typeid, &data) < 0) ERR;
51 
52       /* Close up. */
53       if (H5Aclose(attid) < 0) ERR;
54       if (H5Tclose(typeid) < 0) ERR;
55       if (H5Sclose(spaceid) < 0) ERR;
56       if (H5Gclose(grpid) < 0) ERR;
57       if (H5Fclose(fileid) < 0) ERR;
58 
59       /* Now reopen the file and check it out. */
60       if ((fileid = H5Fopen(FILE_NAME, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) ERR;
61       if ((grpid = H5Gopen(fileid, GRP_NAME)) < 0) ERR;
62       if ((attid = H5Aopen_name(grpid, ATT_NAME)) < 0) ERR;
63       if ((typeid = H5Aget_type(attid)) < 0) ERR;
64       if ((spaceid = H5Aget_space(attid)) < 0) ERR;
65 
66       /* Given this type id, how would we know this is a string
67        * attribute? */
68       if ((class = H5Tget_class(typeid)) < 0) ERR;
69       if (class != H5T_STRING) ERR;
70       if (!(type_size = H5Tget_size(typeid))) ERR;
71       if (type_size != sizeof(char *)) ERR;
72       if ((is_str = H5Tis_variable_str(typeid)) < 0) ERR;
73       if (!is_str) ERR;
74 
75       /* Make sure this is a scalar. */
76       if (H5Sget_simple_extent_type(spaceid) != H5S_SCALAR) ERR;
77 
78       /* Read the attribute. */
79       if (H5Aread(attid, typeid, &data_in) < 0) ERR;
80 
81       /* Check the data. */
82       if (strcmp(data, data_in)) ERR;
83 
84       /* Free the memory returned by H5Aread */
85       free(data_in);
86 
87       /* Close HDF5 stuff. */
88       if (H5Aclose(attid) < 0) ERR;
89       if (H5Tclose(typeid) < 0) ERR;
90       if (H5Sclose(spaceid) < 0) ERR;
91       if (H5Gclose(grpid) < 0) ERR;
92       if (H5Fclose(fileid) < 0) ERR;
93    }
94    SUMMARIZE_ERR;
95    printf("*** Checking simple HDF5 string types...");
96    {
97       hid_t fileid, grpid, spaceid, typeid, attid;
98       hsize_t dims[1] = {DIM1_LEN};
99 /*      size_t type_size;
100 	htri_t is_str;*/
101       hid_t class;
102       char *data[DIM1_LEN] = {"Ohhh!", "Ahhh!", "Wub-wub-wub!"};
103       char **data_in;
104       int i;
105 
106       /* Open file. */
107       if ((fileid = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT,
108 			      H5P_DEFAULT)) < 0) ERR;
109       if ((grpid = H5Gcreate(fileid, GRP_NAME, 0)) < 0) ERR;
110 
111       /* Create string type. */
112       if ((typeid =  H5Tcopy(H5T_C_S1)) < 0) ERR;
113       if (H5Tset_size(typeid, H5T_VARIABLE) < 0) ERR;
114 
115       /* I thought the following should work instead of the H5Tcopy and
116        * H5Tset_size functions above, but it doesn't. */
117       /*if ((typeid = H5Tvlen_create(H5T_NATIVE_CHAR)) < 0) ERR;*/
118 
119       /* Write an attribute of this (string) type. */
120       if ((spaceid = H5Screate_simple(1, dims, NULL)) < 0) ERR;
121       if ((attid = H5Acreate(grpid, ATT_NAME, typeid, spaceid,
122 			     H5P_DEFAULT)) < 0) ERR;
123       if (H5Awrite(attid, typeid, data) < 0) ERR;
124 
125       if (H5Aclose(attid) < 0) ERR;
126       if (H5Tclose(typeid) < 0) ERR;
127       if (H5Gclose(grpid) < 0) ERR;
128       if (H5Fclose(fileid) < 0) ERR;
129 
130       /* Now reopen the file and check it out. */
131       if ((fileid = H5Fopen(FILE_NAME, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) ERR;
132       if ((grpid = H5Gopen(fileid, GRP_NAME)) < 0) ERR;
133       if ((attid = H5Aopen_name(grpid, ATT_NAME)) < 0) ERR;
134       if ((typeid = H5Aget_type(attid)) < 0) ERR;
135 
136       /* Given this type id, how would we know this is a string
137        * attribute? */
138       if ((class = H5Tget_class(typeid)) < 0) ERR;
139       if (class != H5T_STRING) ERR;
140 /*      if (!(type_size = H5Tget_size(typeid))) ERR;
141 	if ((is_str = H5Tis_variable_str(typeid)) < 0) ERR;*/
142 
143       /* How many strings are in the string array? */
144       if ((spaceid = H5Aget_space(attid)) < 0) ERR;
145       if (H5Sget_simple_extent_dims(spaceid, dims, NULL) < 0) ERR;
146       if (!(data_in = malloc(dims[0] * sizeof(char *)))) ERR;
147 
148       /* Now read the array of strings. The HDF5 library will allocate
149        * space for each string. */
150       if (H5Aread(attid, typeid, data_in) < 0) ERR;
151 
152       /* Compare the values to make sure it worked... */
153       for (i = 0; i < DIM1_LEN; i++)
154 	 if (strcmp(data[i], data_in[i])) ERR;
155 
156       /* Free the memory that HDF5 allocated. */
157       for (i = 0; i < DIM1_LEN; i++)
158 	 free(data_in[i]);
159 
160       /* Free the memory that we allocated. */
161       free(data_in);
162 
163       /* Close everything up. */
164       if (H5Aclose(attid) < 0) ERR;
165       if (H5Tclose(typeid) < 0) ERR;
166       if (H5Gclose(grpid) < 0) ERR;
167       if (H5Fclose(fileid) < 0) ERR;
168    }
169 
170    SUMMARIZE_ERR;
171    printf("*** Checking G&S compliance...");
172    {
173 #define S1 "When Frederick was a little lad"
174 #define S2 "He proved so brave and daring..."
175 
176       char **data;
177       char **data_in;
178       hsize_t dims_in[1], dims[1] = {2};
179       hid_t fileid, grpid, spaceid, typeid, attid;
180       hid_t class;
181       int i;
182 
183       /* Allocate space and copy strings. */
184       data = malloc(sizeof(char *) * 2);
185       data[0] = malloc(strlen(S1) + 1);
186       strcpy(data[0], S1);
187       data[1] = malloc(strlen(S2) + 1);
188       strcpy(data[1], S2);
189 
190       /* Open file. */
191       if ((fileid = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT,
192 			   H5P_DEFAULT)) < 0) ERR;
193       if ((grpid = H5Gcreate(fileid, GRP_NAME, 0)) < 0) ERR;
194 
195       /* Create string type. */
196       if ((typeid =  H5Tcopy(H5T_C_S1)) < 0) ERR;
197       if (H5Tset_size(typeid, H5T_VARIABLE) < 0) ERR;
198 
199       /* I thought the following should work instead of the H5Tcopy and
200        * H5Tset_size functions above, but it doesn't. */
201       /*if ((typeid = H5Tvlen_create(H5T_NATIVE_CHAR)) < 0) ERR;*/
202 
203       /* Write an attribute of this type. */
204       if ((spaceid = H5Screate_simple(1, dims, NULL)) < 0) ERR;
205       if ((attid = H5Acreate(grpid, ATT_NAME, typeid, spaceid,
206 			     H5P_DEFAULT)) < 0) ERR;
207       if (H5Awrite(attid, typeid, data) < 0) ERR;
208 
209       /* Close up. */
210       if (H5Aclose(attid) < 0) ERR;
211       if (H5Tclose(typeid) < 0) ERR;
212       if (H5Gclose(grpid) < 0) ERR;
213       if (H5Fclose(fileid) < 0) ERR;
214 
215       /* Now reopen the file and check it out. */
216       if ((fileid = H5Fopen(FILE_NAME, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) ERR;
217       if ((grpid = H5Gopen(fileid, GRP_NAME)) < 0) ERR;
218       if ((attid = H5Aopen_name(grpid, ATT_NAME)) < 0) ERR;
219       if ((typeid = H5Aget_type(attid)) < 0) ERR;
220 
221       /* Given this type id, how would we know this is a string
222        * attribute? */
223       if ((class = H5Tget_class(typeid)) < 0) ERR;
224       if (class != H5T_STRING) ERR;
225 
226       /* How many strings are in the array? */
227       if (H5Sget_simple_extent_dims(spaceid, dims_in, NULL) != 1) ERR;
228       if (dims_in[0] != dims[0]) ERR;
229 
230       /* Allocate enough pointers to read the data. The HDF5 library
231        * will allocate the space needed for each string. */
232       if (!(data_in = malloc(dims_in[0] * sizeof(char *)))) ERR;
233 
234       /* Read the data. */
235       if (H5Aread(attid, typeid, data_in) < 0) ERR;
236 
237       /* Check the data. */
238       for (i = 0; i < 2; i++)
239 	 if (strcmp(data[i], data_in[i])) ERR;
240 
241       /* Free our memory. */
242       for (i = 0; i < 2; i++)
243 	 free(data_in[i]);
244       free(data_in);
245       free(data[0]);
246       free(data[1]);
247       free(data);
248 
249       /* Close HDF5 stuff. */
250       if (H5Aclose(attid) < 0) ERR;
251       if (H5Tclose(typeid) < 0) ERR;
252       if (H5Gclose(grpid) < 0) ERR;
253       if (H5Fclose(fileid) < 0) ERR;
254    }
255 
256    SUMMARIZE_ERR;
257    printf("*** Checking empty strings...");
258    {
259       char **data;
260       char **data_in;
261       hsize_t dims_in[1], dims[1] = {2};
262       hid_t fileid, grpid, spaceid, typeid, attid;
263       hid_t class;
264       int i;
265 
266       /* Allocate space and copy strings. */
267       data = malloc(sizeof(char *) * 2);
268       data[0] = malloc(strlen(S1) + 1);
269       strcpy(data[0], "");
270       data[1] = malloc(strlen(S2) + 1);
271       strcpy(data[1], "");
272 
273       /* Open file. */
274       if ((fileid = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT,
275 			   H5P_DEFAULT)) < 0) ERR;
276       if ((grpid = H5Gcreate(fileid, GRP_NAME, 0)) < 0) ERR;
277 
278       /* Create string type. */
279       if ((typeid =  H5Tcopy(H5T_C_S1)) < 0) ERR;
280       if (H5Tset_size(typeid, H5T_VARIABLE) < 0) ERR;
281 
282       /* I thought the following should work instead of the H5Tcopy and
283        * H5Tset_size functions above, but it doesn't. */
284       /*if ((typeid = H5Tvlen_create(H5T_NATIVE_CHAR)) < 0) ERR;*/
285 
286       /* Write an attribute of this type. */
287       if ((spaceid = H5Screate_simple(1, dims, NULL)) < 0) ERR;
288       if ((attid = H5Acreate(grpid, ATT_NAME, typeid, spaceid,
289 			     H5P_DEFAULT)) < 0) ERR;
290       if (H5Awrite(attid, typeid, data) < 0) ERR;
291 
292       /* Close up. */
293       if (H5Aclose(attid) < 0) ERR;
294       if (H5Tclose(typeid) < 0) ERR;
295       if (H5Gclose(grpid) < 0) ERR;
296       if (H5Fclose(fileid) < 0) ERR;
297 
298       /* Now reopen the file and check it out. */
299       if ((fileid = H5Fopen(FILE_NAME, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) ERR;
300       if ((grpid = H5Gopen(fileid, GRP_NAME)) < 0) ERR;
301       if ((attid = H5Aopen_name(grpid, ATT_NAME)) < 0) ERR;
302       if ((typeid = H5Aget_type(attid)) < 0) ERR;
303 
304       /* Given this type id, how would we know this is a string
305        * attribute? */
306       if ((class = H5Tget_class(typeid)) < 0) ERR;
307       if (class != H5T_STRING) ERR;
308 
309       /* How many strings are in the array? */
310       if (H5Sget_simple_extent_dims(spaceid, dims_in, NULL) != 1) ERR;
311       if (dims_in[0] != dims[0]) ERR;
312 
313       /* Allocate enough pointers to read the data. The HDF5 library
314        * will allocate the space needed for each string. */
315       if (!(data_in = malloc(dims_in[0] * sizeof(char *)))) ERR;
316 
317       /* Read the data. */
318       if (H5Aread(attid, typeid, data_in) < 0) ERR;
319 
320       /* Check the data. */
321       for (i = 0; i < 2; i++)
322 	 if (strcmp(data[i], data_in[i])) ERR;
323 
324       /* Free our memory. */
325       for (i = 0; i < 2; i++)
326 	 free(data_in[i]);
327       free(data_in);
328       free(data[0]);
329       free(data[1]);
330       free(data);
331 
332       /* Close HDF5 stuff. */
333       if (H5Aclose(attid) < 0) ERR;
334       if (H5Tclose(typeid) < 0) ERR;
335       if (H5Gclose(grpid) < 0) ERR;
336       if (H5Fclose(fileid) < 0) ERR;
337    }
338    SUMMARIZE_ERR;
339    FINAL_RESULTS;
340 }
341