1 /**
2 * MOAB, a Mesh-Oriented datABase, is a software component for creating,
3 * storing and accessing finite element mesh data.
4 *
5 * Copyright 2004 Sandia Corporation. Under the terms of Contract
6 * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
7 * retains certain rights in this software.
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 */
15
16 #include <stdlib.h>
17 #include <string.h>
18 #include <assert.h>
19 #include <ctype.h>
20 #include <hdf5.h>
21 #include "util.h"
22 #include "status.h"
23 #include "names-and-paths.h"
24
25 #ifdef VALGRIND
26 # include <valgrind/memcheck.h>
27 #else
28 # define VALGRIND_CHECK_MEM_IS_DEFINED(A,B)
29 # define VALGRIND_MAKE_MEM_UNDEFINED(A,B)
30 #endif
31
mhdf_malloc(size_t size,mhdf_Status * status)32 void* mhdf_malloc( size_t size, mhdf_Status* status )
33 {
34 void* result;
35 result = malloc(size);
36 if (!result)
37 mhdf_setFail( status, "Allocation of %d bytes failed.\n", (int)size );
38 return result;
39 }
40
mhdf_realloc(void * ptr,size_t size,mhdf_Status * status)41 void* mhdf_realloc( void* ptr, size_t size, mhdf_Status* status )
42 {
43 void* result;
44 result = realloc(ptr, size);
45 if (!result)
46 mhdf_setFail( status, "Allocation of %d bytes failed.\n", (int)size );
47 return result;
48 }
49
mhdf_name_to_path(const char * name,char * path,size_t path_len)50 size_t mhdf_name_to_path( const char* name, char* path, size_t path_len )
51 {
52 size_t length = 1;
53 unsigned char *iter;
54
55 if (0==strcmp(name, "."))
56 {
57 if (path_len >= 4)
58 sprintf(path, "\\%02X", (int)*name);
59 return 4;
60 }
61
62 for (iter = (unsigned char*)name; *iter; ++iter)
63 {
64 if ( iscntrl(*iter) || *iter == '/' || *iter == '\\' || *iter > 127 )
65 length += 3;
66 else
67 length += 1;
68 }
69 if (path_len < length)
70 return length;
71
72
73 for (iter = (unsigned char*)name; *iter; ++iter)
74 {
75 if (iscntrl(*iter) || *iter == '/' || *iter == '\\' || *iter > 127)
76 {
77 sprintf(path, "\\%02X", (int)(*iter));
78 path += 3;
79 }
80 else
81 {
82 *(path++) = *iter;
83 }
84 }
85
86 *path = '\0';
87 return length;
88 }
89
mhdf_hex_char(int c)90 static int mhdf_hex_char( int c )
91 {
92 if (isdigit(c))
93 return c - '0';
94 else
95 return toupper(c) - ('A' - 10);
96 }
97
mhdf_path_to_name(const char * path,char * name)98 int mhdf_path_to_name( const char* path, char* name )
99 {
100 const char* iter;
101 char c1, c2;
102
103 for (iter = path; *iter; ++iter, ++name)
104 {
105 if (*iter == '\\')
106 {
107 c1 = *++iter;
108 c2 = *++iter;
109 if (!isxdigit(c1) || !isxdigit(c2))
110 return 0;
111
112 *name = (char)(16 * mhdf_hex_char(c1) + mhdf_hex_char(c2));
113 }
114 else
115 {
116 *name = *iter;
117 }
118 }
119
120 *name = '\0';
121 return 1;
122 }
123
mhdf_name_to_path_copy(const char * name,mhdf_Status * status)124 char* mhdf_name_to_path_copy( const char* name, mhdf_Status* status )
125 {
126 size_t size;
127 char* buffer;
128
129 size = mhdf_name_to_path( name, NULL, 0 );
130 buffer = (char*)mhdf_malloc( size, status );
131 if (!buffer) return NULL;
132
133 mhdf_name_to_path( name, buffer, size );
134 return buffer;
135 }
136
137
mhdf_name_to_path_cat(const char * prefix,const char * name,mhdf_Status * status)138 char* mhdf_name_to_path_cat( const char* prefix, const char* name, mhdf_Status* status )
139 {
140 size_t size, plen;
141 char* buffer;
142
143 plen = strlen( prefix );
144 size = mhdf_name_to_path( name, NULL, 0 ) + 1;
145 buffer = (char*)mhdf_malloc( size + plen, status );
146 if (!buffer) return NULL;
147
148 memcpy( buffer, prefix, plen );
149 mhdf_name_to_path( name, buffer + plen, size );
150 return buffer;
151 }
152
153
mhdf_elem_group_from_handle(FileHandle * file_ptr,const char * elem_handle,mhdf_Status * status)154 hid_t mhdf_elem_group_from_handle( FileHandle* file_ptr,
155 const char* elem_handle,
156 mhdf_Status* status )
157 {
158 char* path;
159 hid_t result;
160
161 path = mhdf_name_to_path_cat( ELEMENT_GROUP, elem_handle, status );
162 if (NULL == path)
163 return -1;
164
165 #if defined(H5Gopen_vers) && H5Gopen_vers > 1
166 result = H5Gopen2( file_ptr->hdf_handle, path, H5P_DEFAULT );
167 #else
168 result = H5Gopen( file_ptr->hdf_handle, path );
169 #endif
170 free( path );
171 if (result < 0)
172 mhdf_setFail( status, "Failed to open element group: \"%s\"", elem_handle );
173 return result;
174 }
175
mhdf_create_scalar_attrib(hid_t object,const char * name,hid_t type,const void * value,mhdf_Status * status)176 int mhdf_create_scalar_attrib( hid_t object,
177 const char* name,
178 hid_t type,
179 const void* value,
180 mhdf_Status* status )
181 {
182 hid_t dspace_id, attr_id;
183 herr_t rval;
184
185 dspace_id = H5Screate( H5S_SCALAR );
186 if (dspace_id < 0)
187 {
188 mhdf_setFail( status, "Internal error calling H5Screate_simple." );
189 return 0;
190 }
191
192 #if defined(H5Acreate_vers) && H5Acreate_vers > 1
193 attr_id = H5Acreate2( object, name, type, dspace_id, H5P_DEFAULT, H5P_DEFAULT );
194 #else
195 attr_id = H5Acreate( object, name, type, dspace_id, H5P_DEFAULT );
196 #endif
197 H5Sclose( dspace_id );
198 if (attr_id < 0)
199 {
200 mhdf_setFail( status, "Failed to create \"%s\" attrib.", name );
201 return 0;
202 }
203
204 VALGRIND_CHECK_MEM_IS_DEFINED( value, H5Tget_size(type) );
205 rval = H5Awrite( attr_id, type, value );
206 H5Aclose( attr_id );
207 if (rval < 0)
208 {
209 mhdf_setFail( status, "Failed to write \"%s\" attrib.", name );
210 return 0;
211 }
212
213 return 1;
214 }
215
216
mhdf_read_scalar_attrib(hid_t object,const char * name,hid_t type,void * value,mhdf_Status * status)217 int mhdf_read_scalar_attrib( hid_t object,
218 const char* name,
219 hid_t type,
220 void* value,
221 mhdf_Status* status )
222 {
223 hid_t attr_id, type_id;
224 herr_t rval;
225
226 attr_id = H5Aopen_name( object, name );
227 if (attr_id < 0)
228 {
229 mhdf_setFail( status, "Failed to create \"%s\" attrib.", name );
230 return 0;
231 }
232
233 if (type > 0)
234 {
235 type_id = type;
236 }
237 else
238 {
239 type_id = H5Aget_type( attr_id );
240 if (type_id < 0)
241 {
242 H5Aclose( attr_id );
243 return 0;
244 }
245 }
246
247 rval = H5Aread( attr_id, type_id, value );
248 H5Aclose( attr_id );
249 if (type < 1)
250 H5Tclose( type_id );
251 if (rval < 0)
252 {
253 mhdf_setFail( status, "Failed to read \"%s\" attrib.", name );
254 return 0;
255 }
256
257 return 1;
258 }
259
260 #if defined(H5Aiterate_vers) && H5Aiterate_vers > 1
find_attr_by_name(hid_t handle,const char * name,const H5A_info_t * info,void * mydata)261 static herr_t find_attr_by_name( hid_t handle, const char* name, const H5A_info_t* info, void* mydata ) {
262 /* empty statement to remove compiler warning */
263 if (info) {}
264 #else
265 static herr_t find_attr_by_name( hid_t handle, const char* name, void* mydata )
266 {
267 #endif
268 /* empty statement to remove compiler warning */
269 if (handle) {}
270 return !strcmp( name, (const char*)mydata ); }
271
272 int mhdf_find_attribute ( hid_t object,
273 const char* attrib_name,
274 unsigned int* index_out,
275 mhdf_Status* status )
276 {
277 herr_t rval;
278 #if defined(H5Aiterate_vers) && H5Aiterate_vers > 1
279 hsize_t idx = 0;
280 rval = H5Aiterate2( object, H5_INDEX_CRT_ORDER, H5_ITER_NATIVE, &idx, &find_attr_by_name, (void*)attrib_name );
281 *index_out = (unsigned int)idx;
282 #else
283 *index_out = 0;
284 rval = H5Aiterate( object, index_out, &find_attr_by_name, (void*)attrib_name );
285 #endif
286 if (rval < 0)
287 mhdf_setFail( status, "Internal error calling H5Aiterate." );
288 return (int)rval;
289 }
290
291
292 static herr_t find_link_by_name( hid_t handle, const char* name, void* mydata )
293 {
294 /* empty statement to remove compiler warning */
295 if (handle) {}
296 return !strcmp( name, (const char*)mydata ); }
297
298 int mhdf_is_in_group( hid_t group, const char* name, mhdf_Status* status )
299 {
300 int rval;
301 rval = H5Giterate( group, ".", NULL, &find_link_by_name, (void*)name );
302 if (rval < 0)
303 mhdf_setFail( status, "Internal error in H5Giterate." );
304 return rval;
305 }
306
307 static int
308 mhdf_readwrite( hid_t data_id, int read,
309 long offset, long count,
310 hid_t type, void* array,
311 hid_t io_prop,
312 mhdf_Status* status )
313 {
314 hid_t slab_id, mem_id;
315 hsize_t offsets[2], counts[2] = {1,1};
316 herr_t rval;
317 int dims;
318 /*#if (1000 * H5_VERS_MAJOR + H5_VERS_MINOR) < 1008*/
319 const hsize_t one = 1;
320 /*#endif*/
321
322 if (offset < 0 || count < 0)
323 {
324 mhdf_setFail( status, "Invalid input for %s: "
325 "offset = %ld, count = %ld\n",
326 read ? "read" : "write",
327 offset, count );
328 return 0;
329 }
330
331 slab_id = H5Dget_space( data_id );
332 if (slab_id < 0)
333 {
334 mhdf_setFail( status, "Internal error calling H5Dget_space.");
335 return 0;
336 }
337
338 dims = H5Sget_simple_extent_ndims( slab_id );
339 if (dims < 1 || dims > 2)
340 {
341 H5Sclose( slab_id );
342 mhdf_setFail( status, "Internal error: unexpected dataset rank: %d.", dims);
343 return 0;
344 }
345
346 dims = H5Sget_simple_extent_dims( slab_id, counts, NULL );
347 if (dims < 0)
348 {
349 H5Sclose( slab_id );
350 mhdf_setFail( status, "Internal error calling H5Sget_simple_extend_dims.");
351 return 0;
352 }
353
354 if ((unsigned long)(offset + count) > counts[0])
355 {
356 H5Sclose( slab_id );
357 mhdf_setFail( status,
358 "Requested %s of rows %ld to %ld of a %ld row table.\n",
359 read ? "read" : "write", offset, offset+count-1, (long)counts[dims-1]);
360 return 0;
361 }
362
363
364 counts[0] = (hsize_t)count;
365 offsets[0] = (hsize_t)offset;
366 offsets[1] = 0;
367 if (count)
368 rval = H5Sselect_hyperslab( slab_id, H5S_SELECT_SET, offsets, NULL, counts, NULL );
369 else
370 rval = H5Sselect_none( slab_id );
371 if (rval < 0)
372 {
373 H5Sclose( slab_id );
374 mhdf_setFail( status, "Internal error calling H5Sselect_hyperslab." );
375 return 0;
376 }
377
378 if (count)
379 mem_id = H5Screate_simple( dims, counts, NULL );
380 else {
381 /*#if H5_VERS_MAJOR > 1 || H5_VERS_MINOR >= 8
382 mem_id = H5Screate(H5S_NULL);
383 #else*/
384 mem_id = H5Screate_simple( 1, &one, NULL );
385 if (mem_id && 0 > H5Sselect_none( mem_id )) {
386 H5Sclose( mem_id );
387 mem_id = -1;
388 }
389 /*#endif*/
390 }
391
392 if (mem_id < 0)
393 {
394 H5Sclose( slab_id );
395 mhdf_setFail( status, "Internal error calling H5Screate_simple." );
396 return 0;
397 }
398
399
400 if (read)
401 rval = H5Dread( data_id, type, mem_id, slab_id, io_prop, array );
402 else {
403 VALGRIND_CHECK_MEM_IS_DEFINED( array, counts[0]*counts[1]*H5Tget_size(type) );
404 rval = H5Dwrite( data_id, type, mem_id, slab_id, io_prop, array );
405 }
406 H5Sclose( slab_id );
407 H5Sclose( mem_id );
408 if (rval < 0)
409 {
410 mhdf_setFail( status, "Internal error calling H5D%s.", read ? "read" : "write" );
411 return 0;
412 }
413
414 mhdf_setOkay( status );
415 return 1;
416 }
417
418
419 static int
420 mhdf_readwrite_column( hid_t data_id, int read,
421 int column,
422 long offset, long count,
423 hid_t type, void* array,
424 hid_t io_prop,
425 mhdf_Status* status )
426 {
427 hid_t slab_id, mem_id;
428 hsize_t offsets[2], counts[2];
429 herr_t rval;
430 int dims;
431 /*#if (1000 * H5_VERS_MAJOR + H5_VERS_MINOR) < 1008*/
432 const hsize_t one = 1;
433 /*#endif*/
434
435 if (column < 0 || offset < 0 || count < 0)
436 {
437 mhdf_setFail( status, "Invalid input for %s: "
438 "column = %d, offset = %ld, count = %ld\n",
439 read ? "read" : "write",
440 column, offset, count );
441 return 0;
442 }
443
444 slab_id = H5Dget_space( data_id );
445 if (slab_id < 0)
446 {
447 mhdf_setFail( status, "Internal error calling H5Dget_space.");
448 return 0;
449 }
450
451 dims = H5Sget_simple_extent_ndims( slab_id );
452 if (dims < 1 || dims > 2)
453 {
454 H5Sclose( slab_id );
455 mhdf_setFail( status, "Internal error: unexpected dataset rank: %d.", dims);
456 return 0;
457 }
458
459 dims = H5Sget_simple_extent_dims( slab_id, counts, NULL );
460 if (dims < 0)
461 {
462 H5Sclose( slab_id );
463 mhdf_setFail( status, "Internal error calling H5Sget_simple_extend_dims.");
464 return 0;
465 }
466
467 if ((unsigned long)(offset + count) > counts[0] ||
468 (unsigned long)column > counts[1])
469 {
470 H5Sclose( slab_id );
471 mhdf_setFail( status,
472 "Requested %s of (%ld,%d)->(%ld,%ld) of (%ld, %ld) table.\n",
473 read ? "read" : "write", offset, column, offset+count-1,
474 column, (long)counts[0], (long)counts[1]);
475 return 0;
476 }
477
478 counts[0] = (hsize_t)count;
479 offsets[0] = (hsize_t)offset;
480 counts[1] = 1;
481 offsets[1] = column;
482 if (count)
483 rval = H5Sselect_hyperslab( slab_id, H5S_SELECT_SET, offsets, NULL, counts, NULL );
484 else
485 rval = H5Sselect_none( slab_id );
486 if (rval < 0)
487 {
488 H5Sclose( slab_id );
489 mhdf_setFail( status, "Internal error calling H5Sselect_hyperslab." );
490 return 0;
491 }
492
493
494 if (count)
495 mem_id = H5Screate_simple( dims, counts, NULL );
496 else {
497 /*#if H5_VERS_MAJOR > 1 || H5_VERS_MINOR >= 8
498 mem_id = H5Screate(H5S_NULL);
499 #else*/
500 mem_id = H5Screate_simple( 1, &one, NULL );
501 if (mem_id && 0 > H5Sselect_none( mem_id )) {
502 H5Sclose( mem_id );
503 mem_id = -1;
504 }
505 /*#endif*/
506 }
507
508 if (mem_id < 0)
509 {
510 H5Sclose( slab_id );
511 mhdf_setFail( status, "Internal error calling H5Screate_simple." );
512 return 0;
513 }
514
515
516 if (read)
517 rval = H5Dread( data_id, type, mem_id, slab_id, io_prop, array );
518 else {
519 VALGRIND_CHECK_MEM_IS_DEFINED( array, count*H5Tget_size(type) );
520 rval = H5Dwrite( data_id, type, mem_id, slab_id, io_prop, array );
521 VALGRIND_MAKE_MEM_UNDEFINED( array, count*H5Tget_size(type) );
522 }
523 H5Sclose( slab_id );
524 H5Sclose( mem_id );
525 if (rval < 0)
526 {
527 mhdf_setFail( status, "Internal error calling H5D%s.", read ? "read" : "write" );
528 return 0;
529 }
530
531 mhdf_setOkay( status );
532 return 1;
533 }
534
535
536 int
537 mhdf_write_data( hid_t data_id,
538 long offset,
539 long count,
540 hid_t type_id,
541 const void* array,
542 hid_t prop,
543 mhdf_Status* status )
544 {
545 return mhdf_readwrite( data_id, 0, offset, count, type_id, (void*)array, prop, status );
546 }
547
548 int
549 mhdf_read_data( hid_t data_id,
550 long offset,
551 long count,
552 hid_t type_id,
553 void* array,
554 hid_t prop,
555 mhdf_Status* status )
556 {
557 return mhdf_readwrite( data_id, 1, offset, count, type_id, array, prop, status );
558 }
559
560 int
561 mhdf_read_column( hid_t data_id,
562 int column,
563 long offset,
564 long count,
565 hid_t type,
566 void* array,
567 hid_t prop,
568 mhdf_Status* status )
569 {
570 return mhdf_readwrite_column( data_id, 1, column, offset, count,
571 type, array, prop, status );
572 }
573
574 int
575 mhdf_write_column( hid_t data_id,
576 int column,
577 long offset,
578 long count,
579 hid_t type,
580 const void* array,
581 hid_t prop,
582 mhdf_Status* status )
583 {
584 return mhdf_readwrite_column( data_id, 0, column, offset, count,
585 type, (void*)array, prop, status );
586 }
587
588
589 hid_t
590 mhdf_create_table( hid_t group_id,
591 const char* path,
592 hid_t type,
593 int rank,
594 hsize_t* dims,
595 mhdf_Status* status )
596 {
597 return mhdf_create_table_with_prop( group_id, path, type, rank, dims, H5P_DEFAULT, status );
598 }
599
600 hid_t
601 mhdf_create_table_with_prop( hid_t group_id,
602 const char* path,
603 hid_t type,
604 int rank,
605 hsize_t* dims,
606 hid_t create_prop,
607 mhdf_Status* status )
608 {
609 hid_t space_id, table_id;
610
611 space_id = H5Screate_simple( rank, dims, NULL );
612 if (space_id < 0)
613 {
614 mhdf_setFail( status, "Internal error calling H5Screate_simple." );
615 return -1;
616 }
617
618 #if defined(H5Dcreate_vers) && H5Dcreate_vers > 1
619 table_id = H5Dcreate2( group_id, path, type, space_id, H5P_DEFAULT, create_prop, H5P_DEFAULT );
620 #else
621 table_id = H5Dcreate( group_id, path, type, space_id, create_prop );
622 #endif
623 H5Sclose(space_id);
624 if (table_id < 0)
625 {
626 mhdf_setFail( status, "HDF5 DataSet creation failed.");
627 return -1;
628 }
629
630 mhdf_setOkay( status );
631 return table_id;
632
633 }
634
635 hid_t
636 mhdf_open_table( hid_t group_id,
637 const char* path,
638 int columns,
639 hsize_t* rows_out,
640 mhdf_Status* status )
641 {
642 hid_t table_id, space_id;
643 hsize_t dims[2];
644 int rank;
645
646 #if defined(H5Dopen_vers) && H5Dopen_vers > 1
647 table_id = H5Dopen2( group_id, path, H5P_DEFAULT );
648 #else
649 table_id = H5Dopen( group_id, path );
650 #endif
651 if (table_id < 0)
652 {
653 mhdf_setFail( status, "HDF5 DataSet creation failed.");
654 return -1;
655 }
656
657 space_id = H5Dget_space( table_id );
658 if (space_id < 0)
659 {
660 mhdf_setFail( status, "Internal error in H5Dget_space.");
661 H5Dclose( table_id );
662 return -1;
663 }
664
665 rank = H5Sget_simple_extent_ndims( space_id );
666 if (rank != (columns ? 1 : 2))
667 {
668 mhdf_setFail( status, "Incorrect DataSpace for DataSet." );
669 H5Sclose( space_id );
670 H5Dclose( table_id );
671 return -1;
672 }
673
674 rank = H5Sget_simple_extent_dims( space_id, dims, NULL );
675 H5Sclose( space_id );
676 if (rank < 0)
677 {
678 mhdf_setFail( status, "Internal error calling H5Sget_simple_extent_dims.");
679 H5Dclose( table_id );
680 return -1;
681 }
682
683 *rows_out = dims[0];
684 mhdf_setOkay( status );
685 return table_id;
686 }
687
688 hid_t
689 mhdf_open_table2( hid_t group_id,
690 const char* path,
691 int rank,
692 hsize_t* dims_out,
693 long* start_id_out,
694 mhdf_Status* status )
695 {
696 hid_t table_id, space_id;
697
698 #if defined(H5Dopen_vers) && H5Dopen_vers > 1
699 table_id = H5Dopen2( group_id, path, H5P_DEFAULT );
700 #else
701 table_id = H5Dopen( group_id, path );
702 #endif
703 if (table_id < 0)
704 {
705 mhdf_setFail( status, "HDF5 DataSet creation failed.");
706 return -1;
707 }
708
709 space_id = H5Dget_space( table_id );
710 if (space_id < 0)
711 {
712 mhdf_setFail( status, "Internal error in H5Dget_space.");
713 H5Dclose( table_id );
714 return -1;
715 }
716
717 if (H5Sget_simple_extent_ndims( space_id ) != rank)
718 {
719 mhdf_setFail( status, "Incorrect DataSpace for DataSet." );
720 H5Sclose( space_id );
721 H5Dclose( table_id );
722 return -1;
723 }
724
725 rank = H5Sget_simple_extent_dims( space_id, dims_out, NULL );
726 H5Sclose( space_id );
727 if (rank < 0)
728 {
729 mhdf_setFail( status, "Internal error calling H5Sget_simple_extent_dims.");
730 H5Dclose( table_id );
731 return -1;
732 }
733
734 if (!mhdf_read_scalar_attrib( table_id, START_ID_ATTRIB, H5T_NATIVE_LONG, start_id_out, status ))
735 {
736 mhdf_setFail( status, "File format error. Failed to retreive ID offset.");
737 H5Dclose( table_id );
738 return -1;
739 }
740
741 mhdf_setOkay( status );
742 return table_id;
743 }
744
745 hid_t
746 mhdf_open_table_simple( hid_t group_id, const char* path, mhdf_Status* status )
747 {
748 hid_t table_id;
749
750 #if defined(H5Dopen_vers) && H5Dopen_vers > 1
751 table_id = H5Dopen2( group_id, path, H5P_DEFAULT );
752 #else
753 table_id = H5Dopen( group_id, path );
754 #endif
755 if (table_id < 0)
756 {
757 mhdf_setFail( status, "HDF5 DataSet creation failed.");
758 }
759 else
760 {
761 mhdf_setOkay( status );
762 }
763
764 return table_id;
765 }
766
767 static int qs_comp_int ( const void* ptr1, const void* ptr2 )
768 {
769 const int* left = (const int*)ptr1;
770 const int* right = (const int*)ptr2;
771 return *left < *right ? -1 : *left > *right ? 1 : 0;
772 }
773
774 int mhdf_compact_to_ranges( int* length, int* ids, int ordered )
775 {
776 int new_length = 0;
777 int* iter, *end;
778 int prev, count;
779 int need_copy = 0;
780 int *copy_ptr = 0, *w_iter;
781 size_t blen;
782
783 if (!ordered)
784 qsort( ids, *length, sizeof(int), &qs_comp_int );
785
786 iter = ids;
787 end = ids + *length;
788 while( iter != end )
789 {
790 prev = *(iter++);
791 while( iter < end && *(iter++) == ++prev );
792 new_length += 2;
793 if (new_length > (iter - ids))
794 need_copy = 1;
795 }
796
797 if (new_length > *length)
798 return 0;
799
800 if (need_copy)
801 {
802 blen = sizeof(int) * *length;
803 copy_ptr = (int*)malloc( blen );
804 memcpy( copy_ptr, ids, blen );
805 iter = copy_ptr;
806 }
807 else
808 {
809 iter = ids;
810 }
811
812 end = iter + *length;
813 w_iter = ids;
814 while( iter != end )
815 {
816 prev = *(iter++);
817 count = 1;
818 while( iter < end && *(iter++) == ++prev );
819 *(w_iter++) = prev - count;
820 *(w_iter++) = count;
821 }
822
823 *length = new_length;
824 if (need_copy)
825 free( copy_ptr );
826 return 1;
827 }
828
829 hid_t
830 get_elem_type_enum( FileHandle* file_ptr, mhdf_Status* status )
831 {
832 hid_t result;
833 #if defined(H5Topen_vers) && H5Topen_vers > 1
834 result = H5Topen2( file_ptr->hdf_handle, TYPE_ENUM_PATH, H5P_DEFAULT );
835 #else
836 result = H5Topen( file_ptr->hdf_handle, TYPE_ENUM_PATH );
837 #endif
838 if (result < 0)
839 mhdf_setFail( status, "Element type enum does not exist in file. Invalid file." );
840 return result;
841 }
842
843 int
844 mhdf_write_max_id( FileHandle* file_ptr, mhdf_Status* status )
845 {
846 hid_t group_id, attr_id, space_id;
847 herr_t rval;
848
849 #if defined(H5Gopen_vers) && H5Gopen_vers > 1
850 group_id = H5Gopen2( file_ptr->hdf_handle, ROOT_GROUP, H5P_DEFAULT );
851 #else
852 group_id = H5Gopen( file_ptr->hdf_handle, ROOT_GROUP );
853 #endif
854 if (group_id < 0)
855 {
856 mhdf_setFail( status, "Internal error -- file invalid." );
857 return 0;
858 }
859
860 attr_id = H5Aopen_name( group_id, MAX_ID_ATTRIB );
861 if (attr_id < 0)
862 {
863 space_id = H5Screate( H5S_SCALAR );
864 #if defined(H5Acreate_vers) && H5Acreate_vers > 1
865 attr_id = H5Acreate2( group_id,
866 MAX_ID_ATTRIB,
867 H5T_NATIVE_ULONG,
868 space_id,
869 H5P_DEFAULT,
870 H5P_DEFAULT );
871 #else
872 attr_id = H5Acreate( group_id,
873 MAX_ID_ATTRIB,
874 H5T_NATIVE_ULONG,
875 space_id,
876 H5P_DEFAULT );
877 #endif
878 H5Sclose( space_id );
879 }
880 H5Gclose( group_id );
881 if (attr_id < 0)
882 {
883 mhdf_setFail( status, "Failed to create attribute \"%s\" on \"%s\"", MAX_ID_ATTRIB, ROOT_GROUP );
884 return 0;
885 }
886
887
888 rval = H5Awrite( attr_id, H5T_NATIVE_ULONG, &file_ptr->max_id );
889 H5Aclose( attr_id );
890 if (rval < 0)
891 {
892 mhdf_setFail( status, "Failed to write \"%s\" attrib.", MAX_ID_ATTRIB );
893 return 0;
894 }
895
896 return 1;
897 }
898
899
900
901 static int mhdf_api_handle_count = 0;
902
903 static int num_open( )
904 {
905 hid_t list[64];
906 int nf, rval, i, count = 0;
907
908 nf = H5Fget_obj_ids( H5F_OBJ_ALL, H5F_OBJ_FILE, sizeof(list)/sizeof(hid_t), list );
909 if (nf <= 0 || nf > 64)
910 return 0;
911
912 for (i = 0; i < nf; i++)
913 {
914 rval = H5Fget_obj_count( list[i], H5F_OBJ_ALL );
915 if (rval > 0)
916 count += rval;
917 }
918
919 return count;
920 }
921
922
923 void mhdf_api_begin_internal( )
924 {
925 /* HDF5 docs are incorrect. Passing H5F_OBJ_ALL as the first
926 arg to H5Fget_obj_count returns the total number of open
927 handles, not just those in files (i.e. temporary types and such.)
928 mhdf_api_handle_count = H5Fget_obj_count( H5F_OBJ_ALL, H5F_OBJ_ALL );
929 Need to loop to get actual file handles:
930 */
931 mhdf_api_handle_count = num_open();
932 }
933
934 void mhdf_api_end_internal( int expected_diff,
935 const char* filename,
936 int linenumber )
937 {
938 if (mhdf_api_handle_count + expected_diff != num_open( ))
939 {
940 fprintf( stderr, "Unclosed handles at end of mhdf API call.\n" );
941 fprintf( stderr, "Entered with %d, expected %d change, got %d.\n",
942 mhdf_api_handle_count, expected_diff, num_open( ) );
943 fprintf( stderr, "%s:%d\n", filename, linenumber );
944 abort();
945 }
946
947 mhdf_api_handle_count = 0;
948 }
949
950
951