001/***************************************************************************** 002 * Copyright by The HDF Group. * 003 * Copyright by the Board of Trustees of the University of Illinois. * 004 * All rights reserved. * 005 * * 006 * This file is part of the HDF Java Products distribution. * 007 * The full copyright notice, including terms governing use, modification, * 008 * and redistribution, is contained in the COPYING file, which can be found * 009 * at the root of the source code distribution tree, * 010 * or in https://www.hdfgroup.org/licenses. * 011 * If you do not have access to either file, you may request a copy from * 012 * help@hdfgroup.org. * 013 ****************************************************************************/ 014 015package hdf.object.h5; 016 017import java.io.File; 018import java.lang.reflect.Array; 019import java.nio.ByteBuffer; 020import java.util.ArrayList; 021import java.util.Hashtable; 022import java.util.Iterator; 023import java.util.LinkedList; 024import java.util.List; 025import java.util.Queue; 026import java.util.Vector; 027 028import hdf.object.Attribute; 029import hdf.object.Dataset; 030import hdf.object.Datatype; 031import hdf.object.FileFormat; 032import hdf.object.Group; 033import hdf.object.HObject; 034import hdf.object.ScalarDS; 035import hdf.object.h5.H5Attribute; 036import hdf.object.h5.H5CompoundAttr; 037import hdf.object.h5.H5Datatype; 038import hdf.object.h5.H5ReferenceType; 039import hdf.object.h5.H5ReferenceType.H5ReferenceData; 040import hdf.object.h5.H5ScalarAttr; 041 042import hdf.hdf5lib.H5; 043import hdf.hdf5lib.HDF5Constants; 044import hdf.hdf5lib.HDFNativeData; 045import hdf.hdf5lib.exceptions.HDF5Exception; 046import hdf.hdf5lib.structs.H5G_info_t; 047import hdf.hdf5lib.structs.H5L_info_t; 048import hdf.hdf5lib.structs.H5O_info_t; 049import hdf.hdf5lib.structs.H5O_token_t; 050 051import org.slf4j.Logger; 052import org.slf4j.LoggerFactory; 053 054/** 055 * H5File is an implementation of the FileFormat class for HDF5 files. 056 * 057 * The HDF5 file structure is made up of HObjects stored in a tree-like fashion. Each tree node represents an 058 * HDF5 object: a Group, Dataset, or Named Datatype. Starting from the root of the tree, <i>rootObject</i>, 059 * the tree can be traversed to find a specific object. 060 * 061 * The following example shows the implementation of finding an object for a given path in FileFormat. User 062 * applications can directly call the static method FileFormat.findObject(file, objPath) to get the object. 063 * 064 * <pre> 065 * HObject findObject(FileFormat file, String path) { 066 * if (file == null || path == null) 067 * return null; 068 * if (!path.endsWith("/")) 069 * path = path + "/"; 070 * HObject theRoot = file.getRootObject(); 071 * if (theRoot == null) 072 * return null; 073 * else if (path.equals("/")) 074 * return theRoot; 075 * 076 * Iterator local_it = ((Group) theRoot) 077 * .breadthFirstMemberList().iterator(); 078 * HObject theObj = null; 079 * while (local_it.hasNext()) { 080 * theObj = local_it.next(); 081 * String fullPath = theObj.getFullName() + "/"; 082 * if (path.equals(fullPath) && theObj.getPath() != null ) { 083 * break; 084 * } 085 * return theObj; 086 * } 087 * </pre> 088 * 089 * @author Peter X. Cao 090 * @version 2.4 9/4/2007 091 */ 092public class H5File extends FileFormat { 093 private static final long serialVersionUID = 6247335559471526045L; 094 095 private static final Logger log = LoggerFactory.getLogger(H5File.class); 096 097 /** 098 * the file access flag. Valid values are 099 * HDF5Constants.H5F_ACC_RDONLY, 100 * HDF5Constants.H5F_ACC_SWMR_READ (with H5F_ACC_RDONLY) 101 * HDF5Constants.H5F_ACC_RDWR 102 * HDF5Constants.H5F_ACC_CREAT 103 */ 104 private int flag; 105 106 /** 107 * The index type. Valid values are HDF5Constants.H5_INDEX_NAME, HDF5Constants.H5_INDEX_CRT_ORDER. 108 */ 109 private int indexType = HDF5Constants.H5_INDEX_NAME; 110 111 /** 112 * The index order. Valid values are HDF5Constants.H5_ITER_INC, HDF5Constants.H5_ITER_DEC. 113 */ 114 private int indexOrder = HDF5Constants.H5_ITER_INC; 115 116 /** 117 * The root object of the file hierarchy. 118 */ 119 private HObject rootObject; 120 121 /** 122 * How many characters maximum in an attribute name? 123 */ 124 private static final int attrNameLen = 256; 125 126 /** 127 * The library version bounds 128 */ 129 private int[] libver; 130 /** The library latest version value */ 131 public static final int LIBVER_LATEST = HDF5Constants.H5F_LIBVER_LATEST; 132 /** The library earliest version value */ 133 public static final int LIBVER_EARLIEST = HDF5Constants.H5F_LIBVER_EARLIEST; 134 /** The library v1.8 version value */ 135 public static final int LIBVER_V18 = HDF5Constants.H5F_LIBVER_V18; 136 /** The library v1.10 version value */ 137 public static final int LIBVER_V110 = HDF5Constants.H5F_LIBVER_V110; 138 /** The library v1.12 version value */ 139 public static final int LIBVER_V112 = HDF5Constants.H5F_LIBVER_V112; 140 /** The library v1.14 version value */ 141 public static final int LIBVER_V114 = HDF5Constants.H5F_LIBVER_V114; 142 143 /** 144 * Indicate that this file is open for reading in a 145 * single-writer/multi-reader (SWMR) scenario. Note that 146 * the process(es) opening the file for SWMR reading must 147 * also open the file with the #H5F_ACC_RDONLY flag. 148 */ 149 public static final int SWMR = MULTIREAD; 150 151 /** 152 * Enum to indicate the type of I/O to perform inside of the common I/O 153 * function. 154 */ 155 public static enum IO_TYPE { 156 /** read IO type */ 157 READ, 158 /** write IO type */ 159 WRITE 160 } 161 ; 162 163 /*************************************************************************** 164 * Constructor 165 **************************************************************************/ 166 /** 167 * Constructs an H5File instance with an empty file name and read-only access. 168 */ 169 public H5File() { this("", READ); } 170 171 /** 172 * Constructs an H5File instance with specified file name and read/write access. 173 * 174 * This constructor does not open the file for access, nor does it confirm that the file can be opened 175 * read/write. 176 * 177 * @param fileName 178 * A valid file name, with a relative or absolute path. 179 * 180 * @throws NullPointerException 181 * If the <code>fileName</code> argument is <code>null</code>. 182 */ 183 public H5File(String fileName) { this(fileName, WRITE); } 184 185 /** 186 * Constructs an H5File instance with specified file name and access. 187 * 188 * The access parameter values and corresponding behaviors: 189 * <ul> 190 * <li>READ: Read-only access; open() will fail file doesn't exist.</li> 191 * <li>SWMR: Read-only access; open() will fail file doesn't exist.</li> 192 * <li>WRITE: Read/Write access; open() will fail if file doesn't exist or if file can't be opened with 193 * read/write access.</li> <li>CREATE: Read/Write access; create a new file or truncate an existing one; 194 * open() will fail if file can't be created or if file exists but can't be opened read/write.</li> 195 * </ul> 196 * 197 * This constructor does not open the file for access, nor does it confirm that the file can later be 198 * opened read/write or created. 199 * 200 * The flag returned by {@link #isReadOnly()} is set to true if the access parameter value is READ, even 201 * though the file isn't yet open. 202 * 203 * @param fileName 204 * A valid file name, with a relative or absolute path. 205 * @param access 206 * The file access flag, which determines behavior when file is opened. Acceptable values are 207 * <code> READ, WRITE, </code> and <code>CREATE</code>. 208 * 209 * @throws NullPointerException 210 * If the <code>fileName</code> argument is <code>null</code>. 211 */ 212 public H5File(String fileName, int access) 213 { 214 // Call FileFormat ctor to set absolute path name 215 super(fileName); 216 libver = new int[2]; 217 libver[0] = HDF5Constants.H5F_LIBVER_EARLIEST; 218 libver[1] = HDF5Constants.H5F_LIBVER_LATEST; 219 220 if ((access & FILE_CREATE_OPEN) == FILE_CREATE_OPEN) { 221 File f = new File(fileName); 222 if (f.exists()) 223 access = WRITE; 224 else 225 access = CREATE; 226 } 227 228 // set metadata for the instance 229 rootObject = null; 230 this.fid = -1; 231 isReadOnly = (READ == (access & READ)) || (MULTIREAD == (access & MULTIREAD)); 232 233 // At this point we just set up the flags for what happens later. 234 // We just pass unexpected access values on... subclasses may have 235 // their own values. 236 if (MULTIREAD == (access & MULTIREAD)) 237 flag = HDF5Constants.H5F_ACC_RDONLY | HDF5Constants.H5F_ACC_SWMR_READ; 238 else if (READ == (access & READ)) 239 flag = HDF5Constants.H5F_ACC_RDONLY; 240 else if (access == WRITE) 241 flag = HDF5Constants.H5F_ACC_RDWR; 242 else if (access == CREATE) 243 flag = HDF5Constants.H5F_ACC_CREAT; 244 else 245 flag = access; 246 } 247 248 /*************************************************************************** 249 * Class methods 250 **************************************************************************/ 251 252 /** 253 * Copies the attributes of one object to another object. 254 * 255 * This method copies all the attributes from one object (source object) to another (destination object). 256 * If an attribute already exists in the destination object, the attribute will not be copied. Attribute 257 * names exceeding 256 characters will be truncated in the destination object. 258 * 259 * The object can be an H5Group, an H5Dataset, or a named H5Datatype. This method is in the H5File class 260 * because there is no H5Object class and it is specific to HDF5 objects. 261 * 262 * The copy can fail for a number of reasons, including an invalid source or destination object, but no 263 * exceptions are thrown. The actual copy is carried out by the method: {@link #copyAttributes(long, 264 * long)} 265 * 266 * @param src 267 * The source object. 268 * @param dst 269 * The destination object. 270 * 271 * @see #copyAttributes(long, long) 272 */ 273 public static final void copyAttributes(HObject src, HObject dst) 274 { 275 if ((src != null) && (dst != null)) { 276 long srcID = src.open(); 277 long dstID = dst.open(); 278 279 if ((srcID >= 0) && (dstID >= 0)) 280 copyAttributes(srcID, dstID); 281 282 if (srcID >= 0) 283 src.close(srcID); 284 285 if (dstID >= 0) 286 dst.close(dstID); 287 } 288 } 289 290 /** 291 * Copies the attributes of one object to another object. 292 * 293 * This method copies all the attributes from one object (source object) to another (destination object). 294 * If an attribute already exists in the destination object, the attribute will not be copied. Attribute 295 * names exceeding 256 characters will be truncated in the destination object. 296 * 297 * The object can be an H5Group, an H5Dataset, or a named H5Datatype. This method is in the H5File class 298 * because there is no H5Object class and it is specific to HDF5 objects. 299 * 300 * The copy can fail for a number of reasons, including an invalid source or destination object 301 * identifier, but no exceptions are thrown. 302 * 303 * @param src_id 304 * The identifier of the source object. 305 * @param dst_id 306 * The identifier of the destination object. 307 */ 308 public static final void copyAttributes(long src_id, long dst_id) 309 { 310 log.trace("copyAttributes(): start: src_id={} dst_id={}", src_id, dst_id); 311 long aid_src = -1; 312 long aid_dst = -1; 313 long asid = -1; 314 long atid = -1; 315 String aName = null; 316 H5O_info_t obj_info = null; 317 318 try { 319 obj_info = H5.H5Oget_info(src_id); 320 } 321 catch (Exception ex) { 322 obj_info.num_attrs = -1; 323 } 324 325 if (obj_info.num_attrs < 0) { 326 log.debug("copyAttributes(): no attributes"); 327 return; 328 } 329 330 for (int i = 0; i < obj_info.num_attrs; i++) { 331 try { 332 aid_src = H5.H5Aopen_by_idx(src_id, ".", HDF5Constants.H5_INDEX_CRT_ORDER, 333 HDF5Constants.H5_ITER_INC, i, HDF5Constants.H5P_DEFAULT, 334 HDF5Constants.H5P_DEFAULT); 335 aName = H5.H5Aget_name(aid_src); 336 atid = H5.H5Aget_type(aid_src); 337 asid = H5.H5Aget_space(aid_src); 338 339 aid_dst = H5.H5Acreate(dst_id, aName, atid, asid, HDF5Constants.H5P_DEFAULT, 340 HDF5Constants.H5P_DEFAULT); 341 342 // use native data copy 343 H5.H5Acopy(aid_src, aid_dst); 344 } 345 catch (Exception ex) { 346 log.debug("copyAttributes(): Attribute[{}] failure: ", i, ex); 347 } 348 349 try { 350 H5.H5Sclose(asid); 351 } 352 catch (Exception ex) { 353 log.debug("copyAttributes(): Attribute[{}] H5Sclose(asid {}) failure: ", i, asid, ex); 354 } 355 try { 356 H5.H5Tclose(atid); 357 } 358 catch (Exception ex) { 359 log.debug("copyAttributes(): Attribute[{}] H5Tclose(atid {}) failure: ", i, atid, ex); 360 } 361 try { 362 H5.H5Aclose(aid_src); 363 } 364 catch (Exception ex) { 365 log.debug("copyAttributes(): Attribute[{}] H5Aclose(aid_src {}) failure: ", i, aid_src, ex); 366 } 367 try { 368 H5.H5Aclose(aid_dst); 369 } 370 catch (Exception ex) { 371 log.debug("copyAttributes(): Attribute[{}] H5Aclose(aid_dst {}) failure: ", i, aid_dst, ex); 372 } 373 374 } // (int i=0; i<num_attr; i++) 375 } 376 377 /** 378 * Returns a list of attributes for the specified object. 379 * 380 * This method returns a list containing the attributes associated with the 381 * identified object. If there are no associated attributes, an empty list will 382 * be returned. 383 * 384 * Attribute names exceeding 256 characters will be truncated in the returned 385 * list. 386 * 387 * @param obj 388 * The HObject whose attributes are to be returned. 389 * 390 * @return The list of the object's attributes. 391 * 392 * @throws HDF5Exception 393 * If an underlying HDF library routine is unable to perform a step 394 * necessary to retrieve the attributes. A variety of failures throw 395 * this exception. 396 * 397 * @see #getAttribute(HObject,int,int) 398 */ 399 public static final List<Attribute> getAttribute(HObject obj) throws HDF5Exception 400 { 401 return H5File.getAttribute(obj, HDF5Constants.H5_INDEX_NAME, HDF5Constants.H5_ITER_INC); 402 } 403 404 /** 405 * Returns a list of attributes for the specified object, in creation or 406 * alphabetical order. 407 * 408 * This method returns a list containing the attributes associated with the 409 * identified object. If there are no associated attributes, an empty list will 410 * be returned. The list of attributes returned can be in increasing or 411 * decreasing, creation or alphabetical order. 412 * 413 * Attribute names exceeding 256 characters will be truncated in the returned 414 * list. 415 * 416 * @param obj 417 * The HObject whose attributes are to be returned. 418 * @param idx_type 419 * The type of index. Valid values are: 420 * <ul> 421 * <li>H5_INDEX_NAME: An alpha-numeric index by attribute name 422 * <li>H5_INDEX_CRT_ORDER: An index by creation order 423 * </ul> 424 * @param order 425 * The index traversal order. Valid values are: 426 * <ul> 427 * <li>H5_ITER_INC: A top-down iteration incrementing the index 428 * position at each step. 429 * <li>H5_ITER_DEC: A bottom-up iteration decrementing the index 430 * position at each step. 431 * </ul> 432 * 433 * @return The list of the object's attributes. 434 * 435 * @throws HDF5Exception 436 * If an underlying HDF library routine is unable to perform a step 437 * necessary to retrieve the attributes. A variety of failures throw 438 * this exception. 439 */ 440 441 public static final List<Attribute> getAttribute(HObject obj, int idx_type, int order) 442 throws HDF5Exception 443 { 444 log.trace("getAttribute(): start: obj={} idx_type={} order={}", obj, idx_type, order); 445 List<Attribute> attributeList = null; 446 long objID = -1; 447 long aid = -1; 448 long sid = -1; 449 long tid = -1; 450 H5O_info_t obj_info = null; 451 452 objID = obj.open(); 453 if (objID >= 0) { 454 try { 455 try { 456 log.trace("getAttribute(): get obj_info"); 457 obj_info = H5.H5Oget_info(objID); 458 } 459 catch (Exception ex) { 460 log.debug("getAttribute(): H5Oget_info(objID {}) failure: ", objID, ex); 461 } 462 if (obj_info.num_attrs <= 0) { 463 log.trace("getAttribute(): no attributes"); 464 return (attributeList = new Vector<>()); 465 } 466 467 int n = (int)obj_info.num_attrs; 468 attributeList = new Vector<>(n); 469 log.trace("getAttribute(): num_attrs={}", n); 470 471 for (int i = 0; i < n; i++) { 472 long lsize = 1; 473 log.trace("getAttribute(): attribute[{}]", i); 474 475 try { 476 aid = H5.H5Aopen_by_idx(objID, ".", idx_type, order, i, HDF5Constants.H5P_DEFAULT, 477 HDF5Constants.H5P_DEFAULT); 478 sid = H5.H5Aget_space(aid); 479 log.trace("getAttribute(): Attribute[{}] aid={} sid={}", i, aid, sid); 480 481 long dims[] = null; 482 int rank = H5.H5Sget_simple_extent_ndims(sid); 483 484 log.trace("getAttribute(): Attribute[{}] isScalar={}", i, (rank == 0)); 485 486 if (rank > 0) { 487 dims = new long[rank]; 488 H5.H5Sget_simple_extent_dims(sid, dims, null); 489 log.trace("getAttribute(): Attribute[{}] rank={}, dims={}", i, rank, dims); 490 for (int j = 0; j < dims.length; j++) { 491 lsize *= dims[j]; 492 } 493 } 494 495 String nameA = H5.H5Aget_name(aid); 496 log.trace("getAttribute(): Attribute[{}] is {} with lsize={}", i, nameA, lsize); 497 498 long tmptid = -1; 499 try { 500 tmptid = H5.H5Aget_type(aid); 501 tid = H5.H5Tget_native_type(tmptid); 502 log.trace("getAttribute(): Attribute[{}] tid={} native tmptid={} from aid={}", i, 503 tid, tmptid, aid); 504 } 505 finally { 506 try { 507 H5.H5Tclose(tmptid); 508 } 509 catch (Exception ex) { 510 log.debug("getAttribute(): Attribute[{}] H5Tclose(tmptid {}) failure: ", i, 511 tmptid, ex); 512 } 513 } 514 515 H5Datatype attrType = null; 516 try { 517 int nativeClass = H5.H5Tget_class(tid); 518 if (nativeClass == HDF5Constants.H5T_REFERENCE) 519 attrType = new H5ReferenceType(obj.getFileFormat(), lsize, tid); 520 else 521 attrType = new H5Datatype(obj.getFileFormat(), tid); 522 523 log.trace("getAttribute(): Attribute[{}] Datatype={}", i, 524 attrType.getDescription()); 525 log.trace( 526 "getAttribute(): Attribute[{}] has size={} isCompound={} is_variable_str={} isVLEN={}", 527 i, lsize, attrType.isCompound(), attrType.isVarStr(), attrType.isVLEN()); 528 } 529 catch (Exception ex) { 530 log.debug("getAttribute(): failed to create datatype for Attribute[{}]: ", i, ex); 531 attrType = null; 532 } 533 534 Attribute attr = null; 535 if (attrType.isCompound()) 536 attr = (Attribute) new H5CompoundAttr(obj, nameA, attrType, dims); 537 else 538 attr = (Attribute) new H5ScalarAttr(obj, nameA, attrType, dims); 539 attributeList.add(attr); 540 541 // retrieve the attribute value 542 if (lsize <= 0) { 543 log.debug("getAttribute(): Attribute[{}] lsize <= 0", i); 544 continue; 545 } 546 547 if (lsize < Integer.MIN_VALUE || lsize > Integer.MAX_VALUE) { 548 log.debug( 549 "getAttribute(): Attribute[{}] lsize outside valid Java int range; unsafe cast", 550 i); 551 continue; 552 } 553 554 try { 555 // attr.AttributeCommonIO(aid, H5File.IO_TYPE.READ, null); 556 Object attrData = attr.getAttributeData(); 557 log.trace("getAttribute(): attrType.isRef()={}", attrType.isRef()); 558 if (attrType.isRef()) { 559 if (attr.getAttributeRank() > 2) 560 ((H5ReferenceType)attrType).setRefSize(attr.getAttributePlane()); 561 ((H5ReferenceType)attrType).setData(attrData); 562 } 563 } 564 catch (Exception ex) { 565 log.debug("getAttribute(): failed to read attribute: ", ex); 566 } 567 } 568 catch (HDF5Exception ex) { 569 log.debug("getAttribute(): Attribute[{}] inspection failure: ", i, ex); 570 } 571 finally { 572 try { 573 H5.H5Tclose(tid); 574 } 575 catch (Exception ex) { 576 log.debug("getAttribute(): Attribute[{}] H5Tclose(tid {}) failure: ", i, tid, ex); 577 } 578 try { 579 H5.H5Sclose(sid); 580 } 581 catch (Exception ex) { 582 log.debug("getAttribute(): Attribute[{}] H5Sclose(aid {}) failure: ", i, sid, ex); 583 } 584 try { 585 H5.H5Aclose(aid); 586 } 587 catch (Exception ex) { 588 log.debug("getAttribute(): Attribute[{}] H5Aclose(aid {}) failure: ", i, aid, ex); 589 } 590 } 591 } // (int i=0; i<obj_info.num_attrs; i++) 592 for (int i = 0; i < n; i++) { 593 Attribute attr = (Attribute)attributeList.get(i); 594 H5Datatype atype = (H5Datatype)attr.getAttributeDatatype(); 595 H5Datatype aBasetype = (H5Datatype)atype.getDatatypeBase(); 596 boolean BDTisRef = false; 597 if (aBasetype != null) 598 BDTisRef = aBasetype.isRef(); 599 if (atype.isRef() || BDTisRef) { 600 H5ReferenceType rtype = null; 601 if (BDTisRef) 602 rtype = (H5ReferenceType)aBasetype; 603 else 604 rtype = (H5ReferenceType)atype; 605 try { 606 List<H5ReferenceData> refdata = (List)rtype.getData(); 607 for (int r = 0; r < (int)rtype.getRefSize(); r++) { 608 H5ReferenceData rf = refdata.get(r); 609 log.trace("getAttribute(): refdata {}", rf.ref_array); 610 } 611 } 612 catch (Exception ex) { 613 log.trace("Error retrieving H5ReferenceData of object ", ex); 614 } 615 } 616 } 617 } 618 finally { 619 obj.close(objID); 620 } 621 } 622 623 return attributeList; 624 } 625 626 /** 627 * Creates attributes for an HDF5 image dataset. 628 * 629 * This method creates attributes for two common types of HDF5 images. It provides a way of adding 630 * multiple attributes to an HDF5 image dataset with a single call. The {@link #writeAttribute(HObject, 631 * Attribute, boolean)} method may be used to write image attributes that are not handled by this method. 632 * 633 * For more information about HDF5 image attributes, read <a 634 * href="https://hdfgroup.github.io/hdf5/_i_m_g.html">HDF5 Image and Palette Specification</a> 635 * 636 * This method can be called to create attributes for 24-bit true color and indexed images. The 637 * <code>selectionFlag</code> parameter controls whether this will be an indexed or true color image. If 638 * <code>selectionFlag</code> is <code>-1</code>, this will be an indexed image. If the value is 639 * <code>ScalarDS.INTERLACE_PIXEL</code> or <code>ScalarDS.INTERLACE_PLANE</code>, it will be a 24-bit 640 * true color image with the indicated interlace mode. 641 * 642 * <ul> 643 * The created attribute descriptions, names, and values are: 644 * <li>The image identifier: name="CLASS", value="IMAGE" 645 * <li>The version of image: name="IMAGE_VERSION", value="1.2" 646 * <li>The range of data values: name="IMAGE_MINMAXRANGE", value=[0, 255] 647 * <li>The type of the image: name="IMAGE_SUBCLASS", value="IMAGE_TRUECOLOR" or "IMAGE_INDEXED" 648 * <li>For IMAGE_TRUECOLOR, the interlace mode: name="INTERLACE_MODE", value="INTERLACE_PIXEL" or 649 * "INTERLACE_PLANE" <li>For IMAGE_INDEXED, the palettes to use in viewing the image: name="PALETTE", 650 * value= 1-d array of references to the palette datasets, with initial value of {-1} 651 * </ul> 652 * 653 * This method is in the H5File class rather than H5ScalarDS because images are typically thought of at 654 * the File Format implementation level. 655 * 656 * @param dataset The image dataset the attributes are added to. 657 * @param selectionFlag Selects the image type and, for 24-bit true color images, the interlace mode. 658 * Valid values 659 * are: 660 * <ul> 661 * <li>-1: Indexed Image. 662 * <li>ScalarDS.INTERLACE_PIXEL: True Color Image. The component values for a pixel 663 * are stored contiguously. <li>ScalarDS.INTERLACE_PLANE: True Color Image. Each component is stored in a 664 * separate plane. 665 * </ul> 666 * 667 * @throws Exception If there is a problem creating the attributes, or if the selectionFlag is invalid. 668 */ 669 private static final void createImageAttributes(Dataset dataset, int selectionFlag) throws Exception 670 { 671 log.trace("createImageAttributes(): start: dataset={}", dataset.toString()); 672 String subclass = null; 673 String interlaceMode = null; 674 675 if (selectionFlag == ScalarDS.INTERLACE_PIXEL) { 676 log.trace("createImageAttributes(): subclass IMAGE_TRUECOLOR selectionFlag INTERLACE_PIXEL"); 677 subclass = "IMAGE_TRUECOLOR"; 678 interlaceMode = "INTERLACE_PIXEL"; 679 } 680 else if (selectionFlag == ScalarDS.INTERLACE_PLANE) { 681 log.trace("createImageAttributes(): subclass IMAGE_TRUECOLOR selectionFlag INTERLACE_PLANE"); 682 subclass = "IMAGE_TRUECOLOR"; 683 interlaceMode = "INTERLACE_PLANE"; 684 } 685 else if (selectionFlag == -1) { 686 log.trace("createImageAttributes(): subclass IMAGE_INDEXED"); 687 subclass = "IMAGE_INDEXED"; 688 } 689 else { 690 log.debug("createImageAttributes(): invalid selectionFlag"); 691 throw new HDF5Exception("The selectionFlag is invalid."); 692 } 693 694 String attrName = "CLASS"; 695 String[] classValue = {"IMAGE"}; 696 Datatype attrType = new H5Datatype(Datatype.CLASS_STRING, classValue[0].length() + 1, Datatype.NATIVE, 697 Datatype.NATIVE); 698 Attribute attr = (Attribute) new H5ScalarAttr(dataset, attrName, attrType, null); 699 attr.writeAttribute(classValue); 700 701 attrName = "IMAGE_VERSION"; 702 String[] versionValue = {"1.2"}; 703 attrType = new H5Datatype(Datatype.CLASS_STRING, versionValue[0].length() + 1, Datatype.NATIVE, 704 Datatype.NATIVE); 705 attr = (Attribute) new H5ScalarAttr(dataset, attrName, attrType, null); 706 attr.writeAttribute(versionValue); 707 708 long[] attrDims = {2}; 709 attrName = "IMAGE_MINMAXRANGE"; 710 byte[] attrValueInt = {0, (byte)255}; 711 attrType = new H5Datatype(Datatype.CLASS_CHAR, 1, Datatype.NATIVE, Datatype.SIGN_NONE); 712 attr = (Attribute) new H5ScalarAttr(dataset, attrName, attrType, attrDims); 713 attr.writeAttribute(attrValueInt); 714 715 attrName = "IMAGE_SUBCLASS"; 716 String[] subclassValue = {subclass}; 717 attrType = new H5Datatype(Datatype.CLASS_STRING, subclassValue[0].length() + 1, Datatype.NATIVE, 718 Datatype.NATIVE); 719 attr = (Attribute) new H5ScalarAttr(dataset, attrName, attrType, null); 720 attr.writeAttribute(subclassValue); 721 722 if ((selectionFlag == ScalarDS.INTERLACE_PIXEL) || (selectionFlag == ScalarDS.INTERLACE_PLANE)) { 723 attrName = "INTERLACE_MODE"; 724 String[] interlaceValue = {interlaceMode}; 725 attrType = new H5Datatype(Datatype.CLASS_STRING, interlaceValue[0].length() + 1, Datatype.NATIVE, 726 Datatype.NATIVE); 727 attr = (Attribute) new H5ScalarAttr(dataset, attrName, attrType, null); 728 attr.writeAttribute(interlaceValue); 729 } 730 else { 731 attrName = "PALETTE"; 732 String palRef = "."; // set ref to null 733 attrType = new H5Datatype(Datatype.CLASS_REFERENCE, 1, Datatype.NATIVE, Datatype.SIGN_NONE); 734 attr = (Attribute) new H5ScalarAttr(dataset, attrName, attrType, null); 735 attr.writeAttribute(palRef); 736 } 737 } 738 739 /** 740 * Updates values of scalar dataset object references in copied file. 741 * 742 * This method has very specific functionality as documented below, and the user is advised to pay close 743 * attention when dealing with files that contain references. 744 * 745 * When a copy is made from one HDF file to another, object references and dataset region references are 746 * copied, but the references in the destination file are not updated by the copy and are therefore 747 * invalid. 748 * 749 * When an entire file is copied, this method updates the values of the object references and dataset 750 * region references that are in scalar datasets in the destination file so that they point to the correct 751 * object(s) in the destination file. The method does not update references that occur in objects other 752 * than scalar datasets. 753 * 754 * In the current release, the updating of object references is not handled completely as it was not 755 * required by the projects that funded development. There is no support for updates when the copy does 756 * not include the entire file. Nor is there support for updating objects other than scalar datasets in 757 * full-file copies. This functionality will be extended as funding becomes available or, possibly, when 758 * the underlying HDF library supports the reference updates itself. 759 * 760 * @param srcFile 761 * The file that was copied. 762 * @param dstFile 763 * The destination file where the object references will be updated. 764 * 765 * @throws Exception 766 * If there is a problem in the update process. 767 */ 768 public static final void updateReferenceDataset(H5File srcFile, H5File dstFile) throws Exception 769 { 770 if ((srcFile == null) || (dstFile == null)) { 771 log.debug("updateReferenceDataset(): srcFile or dstFile is null"); 772 return; 773 } 774 775 HObject srcRoot = srcFile.getRootObject(); 776 HObject newRoot = dstFile.getRootObject(); 777 778 Iterator<HObject> srcIt = getMembersBreadthFirst(srcRoot).iterator(); 779 Iterator<HObject> newIt = getMembersBreadthFirst(newRoot).iterator(); 780 781 long did = -1; 782 // build one-to-one table of between objects in 783 // the source file and new file 784 long tid = -1; 785 HObject srcObj, newObj; 786 Hashtable<String, long[]> oidMap = new Hashtable<>(); 787 List<ScalarDS> refDatasets = new Vector<>(); 788 while (newIt.hasNext() && srcIt.hasNext()) { 789 srcObj = srcIt.next(); 790 newObj = newIt.next(); 791 oidMap.put(String.valueOf((srcObj.getOID())[0]), newObj.getOID()); 792 did = -1; 793 tid = -1; 794 795 // for Scalar DataSets in destination, if there is an object 796 // reference in the dataset, add it to the refDatasets list for 797 // later updating. 798 if (newObj instanceof ScalarDS) { 799 ScalarDS sd = (ScalarDS)newObj; 800 did = sd.open(); 801 if (did >= 0) { 802 try { 803 tid = H5.H5Dget_type(did); 804 if (H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF)) { 805 refDatasets.add(sd); 806 } 807 } 808 catch (Exception ex) { 809 log.debug("updateReferenceDataset(): ScalarDS reference failure: ", ex); 810 } 811 finally { 812 try { 813 H5.H5Tclose(tid); 814 } 815 catch (Exception ex) { 816 log.debug( 817 "updateReferenceDataset(): ScalarDS reference H5Tclose(tid {}) failure: ", 818 tid, ex); 819 } 820 } 821 } 822 sd.close(did); 823 } // (newObj instanceof ScalarDS) 824 } 825 826 // Update the references in the scalar datasets in the dest file. 827 H5ScalarDS d = null; 828 long sid = -1; 829 int size = 0; 830 int rank = 0; 831 int space_type = -1; 832 int n = refDatasets.size(); 833 for (int i = 0; i < n; i++) { 834 log.trace( 835 "updateReferenceDataset(): Update the references in the scalar datasets in the dest file"); 836 d = (H5ScalarDS)refDatasets.get(i); 837 byte[] buf = null; 838 long[] refs = null; 839 840 try { 841 did = d.open(); 842 if (did >= 0) { 843 tid = H5.H5Dget_type(did); 844 sid = H5.H5Dget_space(did); 845 rank = H5.H5Sget_simple_extent_ndims(sid); 846 space_type = H5.H5Sget_simple_extent_type(sid); 847 size = 1; 848 if (rank > 0) { 849 long[] dims = new long[rank]; 850 H5.H5Sget_simple_extent_dims(sid, dims, null); 851 log.trace("updateReferenceDataset(): rank={}, dims={}, space_type={}", rank, dims, 852 space_type); 853 for (int j = 0; j < rank; j++) { 854 size *= (int)dims[j]; 855 } 856 dims = null; 857 } 858 859 buf = new byte[size * 8]; 860 H5.H5Dread(did, tid, HDF5Constants.H5S_ALL, HDF5Constants.H5S_ALL, 861 HDF5Constants.H5P_DEFAULT, buf); 862 863 // update the ref values 864 refs = HDFNativeData.byteToLong(buf); 865 size = refs.length; 866 for (int j = 0; j < size; j++) { 867 long[] theOID = oidMap.get(String.valueOf(refs[j])); 868 if (theOID != null) { 869 refs[j] = theOID[0]; 870 } 871 } 872 873 // write back to file 874 H5.H5Dwrite(did, tid, HDF5Constants.H5S_ALL, HDF5Constants.H5S_ALL, 875 HDF5Constants.H5P_DEFAULT, refs); 876 } 877 else { 878 log.debug("updateReferenceDataset(): dest file dataset failed to open"); 879 } 880 } 881 catch (Exception ex) { 882 log.debug("updateReferenceDataset(): Reference[{}] failure: ", i, ex); 883 continue; 884 } 885 finally { 886 try { 887 H5.H5Tclose(tid); 888 } 889 catch (Exception ex) { 890 log.debug("updateReferenceDataset(): H5ScalarDS reference[{}] H5Tclose(tid {}) failure: ", 891 i, tid, ex); 892 } 893 try { 894 H5.H5Sclose(sid); 895 } 896 catch (Exception ex) { 897 log.debug("updateReferenceDataset(): H5ScalarDS reference[{}] H5Sclose(sid {}) failure: ", 898 i, sid, ex); 899 } 900 try { 901 H5.H5Dclose(did); 902 } 903 catch (Exception ex) { 904 log.debug("updateReferenceDataset(): H5ScalarDS reference[{}] H5Dclose(did {}) failure: ", 905 i, did, ex); 906 } 907 } 908 909 refs = null; 910 buf = null; 911 } // (int i=0; i<n; i++) 912 } 913 914 /*************************************************************************** 915 * Implementation Class methods. These methods are related to the implementing H5File class, but not to a 916 *particular instance of the class. Since we can't override class methods (they can only be shadowed in 917 *Java), these are instance methods. 918 **************************************************************************/ 919 920 /** 921 * Returns the version of the HDF5 library. 922 * 923 * @see hdf.object.FileFormat#getLibversion() 924 */ 925 @Override 926 public String getLibversion() 927 { 928 int[] vers = new int[3]; 929 String ver = "HDF5 "; 930 931 try { 932 H5.H5get_libversion(vers); 933 } 934 catch (Exception ex) { 935 ex.printStackTrace(); 936 } 937 938 ver += vers[0] + "." + vers[1] + "." + vers[2]; 939 log.debug("getLibversion(): libversion is {}", ver); 940 941 return ver; 942 } 943 944 /** 945 * Checks if the specified FileFormat instance has the HDF5 format. 946 * 947 * @see hdf.object.FileFormat#isThisType(hdf.object.FileFormat) 948 */ 949 @Override 950 public boolean isThisType(FileFormat theFile) 951 { 952 return (theFile instanceof H5File); 953 } 954 955 /** 956 * Checks if the specified file has the HDF5 format. 957 * 958 * @see hdf.object.FileFormat#isThisType(java.lang.String) 959 */ 960 @Override 961 public boolean isThisType(String filename) 962 { 963 boolean isH5 = false; 964 965 try { 966 isH5 = H5.H5Fis_hdf5(filename); 967 } 968 catch (HDF5Exception ex) { 969 isH5 = false; 970 } 971 972 return isH5; 973 } 974 975 /** 976 * Creates an HDF5 file with the specified name and returns a new H5File instance associated with the 977 * file. 978 * 979 * @throws Exception 980 * If the file cannot be created or if createFlag has unexpected value. 981 * 982 * @see hdf.object.FileFormat#createFile(java.lang.String, int) 983 * @see #H5File(String, int) 984 */ 985 @Override 986 public FileFormat createFile(String filename, int createFlag) throws Exception 987 { 988 log.trace("createFile(): start: filename={} createFlag={}", filename, createFlag); 989 // Flag if we need to create or truncate the file. 990 Boolean doCreateFile = true; 991 992 // Won't create or truncate if CREATE_OPEN specified and file exists 993 if ((createFlag & FILE_CREATE_OPEN) == FILE_CREATE_OPEN) { 994 File f = new File(filename); 995 if (f.exists()) { 996 doCreateFile = false; 997 } 998 } 999 log.trace("createFile(): doCreateFile={}", doCreateFile); 1000 1001 if (doCreateFile) { 1002 long fapl = H5.H5Pcreate(HDF5Constants.H5P_FILE_ACCESS); 1003 1004 if ((createFlag & FILE_CREATE_EARLY_LIB) == FILE_CREATE_EARLY_LIB) { 1005 int[] newlibver = getLibBounds(); 1006 H5.H5Pset_libver_bounds(fapl, newlibver[0], newlibver[1]); 1007 } 1008 1009 long fileid = 1010 H5.H5Fcreate(filename, HDF5Constants.H5F_ACC_TRUNC, HDF5Constants.H5P_DEFAULT, fapl); 1011 try { 1012 H5.H5Pclose(fapl); 1013 H5.H5Fclose(fileid); 1014 } 1015 catch (HDF5Exception ex) { 1016 log.debug("H5 file, {} failure: ", filename, ex); 1017 } 1018 } 1019 1020 return new H5File(filename, WRITE); 1021 } 1022 1023 /** 1024 * Creates an H5File instance with specified file name and access. 1025 * 1026 * @see hdf.object.FileFormat#createInstance(java.lang.String, int) 1027 * @see #H5File(String, int) 1028 * 1029 * @throws Exception 1030 * If there is a failure. 1031 */ 1032 @Override 1033 public FileFormat createInstance(String filename, int access) throws Exception 1034 { 1035 log.trace("createInstance() for {} with {}", filename, access); 1036 return new H5File(filename, access); 1037 } 1038 1039 /*************************************************************************** 1040 * Instance Methods 1041 * 1042 * These methods are related to the H5File class and to particular instances of objects with this class 1043 *type. 1044 **************************************************************************/ 1045 1046 /** 1047 * Opens file and returns a file identifier. 1048 * 1049 * @see hdf.object.FileFormat#open() 1050 */ 1051 @Override 1052 public long open() throws Exception 1053 { 1054 return open(true); 1055 } 1056 1057 /** 1058 * Opens file and returns a file identifier. 1059 * 1060 * @see hdf.object.FileFormat#open(int...) 1061 */ 1062 @Override 1063 public long open(int... indexList) throws Exception 1064 { 1065 setIndexType(indexList[0]); 1066 setIndexOrder(indexList[1]); 1067 return open(true); 1068 } 1069 1070 /** 1071 * Sets the bounds of new library versions. 1072 * 1073 * @param lowStr 1074 * The earliest version of the library. 1075 * @param highStr 1076 * The latest version of the library. 1077 * 1078 * @throws Exception 1079 * If there is an error at the HDF5 library level. 1080 */ 1081 @Override 1082 public void setNewLibBounds(String lowStr, String highStr) throws Exception 1083 { 1084 int low = -1; 1085 int high = -1; 1086 1087 if (lowStr == null) 1088 low = HDF5Constants.H5F_LIBVER_EARLIEST; 1089 else if (lowStr.equals("Earliest")) 1090 low = HDF5Constants.H5F_LIBVER_EARLIEST; 1091 else if (lowStr.equals("V18")) 1092 low = HDF5Constants.H5F_LIBVER_V18; 1093 else if (lowStr.equals("V110")) 1094 low = HDF5Constants.H5F_LIBVER_V110; 1095 else if (lowStr.equals("V112")) 1096 low = HDF5Constants.H5F_LIBVER_V112; 1097 else if (lowStr.equals("V114")) 1098 low = HDF5Constants.H5F_LIBVER_V114; 1099 else if (lowStr.equals("Latest")) 1100 low = HDF5Constants.H5F_LIBVER_LATEST; 1101 else 1102 low = HDF5Constants.H5F_LIBVER_EARLIEST; 1103 1104 if (highStr == null) 1105 high = HDF5Constants.H5F_LIBVER_LATEST; 1106 else if (highStr.equals("V18")) 1107 high = HDF5Constants.H5F_LIBVER_V18; 1108 else if (highStr.equals("V110")) 1109 high = HDF5Constants.H5F_LIBVER_V110; 1110 else if (highStr.equals("V112")) 1111 high = HDF5Constants.H5F_LIBVER_V112; 1112 else if (highStr.equals("V114")) 1113 high = HDF5Constants.H5F_LIBVER_V114; 1114 else if (highStr.equals("Latest")) 1115 high = HDF5Constants.H5F_LIBVER_LATEST; 1116 else 1117 high = HDF5Constants.H5F_LIBVER_LATEST; 1118 libver[0] = low; 1119 libver[1] = high; 1120 } 1121 1122 /** 1123 * Sets the bounds of library versions. 1124 * 1125 * @param lowStr 1126 * The earliest version of the library. 1127 * @param highStr 1128 * The latest version of the library. 1129 * 1130 * @throws Exception 1131 * If there is an error at the HDF5 library level. 1132 */ 1133 @Override 1134 public void setLibBounds(String lowStr, String highStr) throws Exception 1135 { 1136 long fapl = HDF5Constants.H5P_DEFAULT; 1137 1138 if (fid < 0) 1139 return; 1140 1141 fapl = H5.H5Fget_access_plist(fid); 1142 1143 try { 1144 int low = -1; 1145 int high = -1; 1146 1147 if (lowStr == null) 1148 low = HDF5Constants.H5F_LIBVER_EARLIEST; 1149 else if (lowStr.equals("Earliest")) 1150 low = HDF5Constants.H5F_LIBVER_EARLIEST; 1151 else if (lowStr.equals("V18")) 1152 low = HDF5Constants.H5F_LIBVER_V18; 1153 else if (lowStr.equals("V110")) 1154 low = HDF5Constants.H5F_LIBVER_V110; 1155 else if (lowStr.equals("V112")) 1156 low = HDF5Constants.H5F_LIBVER_V112; 1157 else if (lowStr.equals("V114")) 1158 low = HDF5Constants.H5F_LIBVER_V114; 1159 else if (lowStr.equals("Latest")) 1160 low = HDF5Constants.H5F_LIBVER_LATEST; 1161 else 1162 low = HDF5Constants.H5F_LIBVER_EARLIEST; 1163 1164 if (highStr == null) 1165 high = HDF5Constants.H5F_LIBVER_LATEST; 1166 else if (highStr.equals("V18")) 1167 high = HDF5Constants.H5F_LIBVER_V18; 1168 else if (highStr.equals("V110")) 1169 high = HDF5Constants.H5F_LIBVER_V110; 1170 else if (highStr.equals("V112")) 1171 high = HDF5Constants.H5F_LIBVER_V112; 1172 else if (highStr.equals("V114")) 1173 high = HDF5Constants.H5F_LIBVER_V114; 1174 else if (highStr.equals("Latest")) 1175 high = HDF5Constants.H5F_LIBVER_LATEST; 1176 else 1177 high = HDF5Constants.H5F_LIBVER_LATEST; 1178 1179 H5.H5Pset_libver_bounds(fapl, low, high); 1180 H5.H5Pget_libver_bounds(fapl, libver); 1181 } 1182 finally { 1183 try { 1184 H5.H5Pclose(fapl); 1185 } 1186 catch (Exception e) { 1187 log.debug("setLibBounds(): libver bounds H5Pclose(fapl {}) failure: ", fapl, e); 1188 } 1189 } 1190 } 1191 1192 /** 1193 * Gets the bounds of library versions. 1194 * 1195 * @return libver The earliest and latest version of the library. 1196 * 1197 * @throws Exception 1198 * If there is an error at the HDF5 library level. 1199 */ 1200 @Override 1201 public int[] getLibBounds() throws Exception 1202 { 1203 if (libver.length == 0) 1204 initLibBounds(); 1205 return libver; 1206 } 1207 1208 /** 1209 * Initialize the bounds of library versions 1210 * 1211 * @throws Exception 1212 * The exceptions thrown vary depending on the implementing class. 1213 */ 1214 @Override 1215 public void initLibBounds() throws Exception 1216 { 1217 if (fid >= 0) { 1218 /* Get the file's file access property list */ 1219 long fapl = H5.H5Fget_access_plist(fid); 1220 /* Get library format */ 1221 H5.H5Pget_libver_bounds(fapl, libver); 1222 /* Close FAPL */ 1223 H5.H5Pclose(fapl); 1224 } 1225 } 1226 1227 /** 1228 * Gets the bounds of library versions as text. 1229 * 1230 * @return libversion The earliest and latest version of the library. 1231 */ 1232 @Override 1233 public String getLibBoundsDescription() 1234 { 1235 String libversion = ""; 1236 1237 if (libver[0] == HDF5Constants.H5F_LIBVER_EARLIEST) 1238 libversion = "Earliest and "; 1239 else if (libver[0] == HDF5Constants.H5F_LIBVER_V18) 1240 libversion = "V18 and "; 1241 else if (libver[0] == HDF5Constants.H5F_LIBVER_V110) 1242 libversion = "V110 and "; 1243 else if (libver[0] == HDF5Constants.H5F_LIBVER_V112) 1244 libversion = "V112 and "; 1245 else if (libver[0] == HDF5Constants.H5F_LIBVER_V114) 1246 libversion = "V114 and "; 1247 else if (libver[0] == HDF5Constants.H5F_LIBVER_LATEST) 1248 libversion = "Latest and "; 1249 1250 if (libver[1] == HDF5Constants.H5F_LIBVER_EARLIEST) 1251 libversion += "Earliest"; 1252 else if (libver[1] == HDF5Constants.H5F_LIBVER_V18) 1253 libversion += "V18"; 1254 else if (libver[1] == HDF5Constants.H5F_LIBVER_V110) 1255 libversion += "V110"; 1256 else if (libver[1] == HDF5Constants.H5F_LIBVER_V112) 1257 libversion += "V112"; 1258 else if (libver[1] == HDF5Constants.H5F_LIBVER_V114) 1259 libversion += "V114"; 1260 else if (libver[1] == HDF5Constants.H5F_LIBVER_LATEST) 1261 libversion += "Latest"; 1262 return libversion; 1263 } 1264 1265 /** 1266 * Closes file associated with this H5File instance. 1267 * 1268 * @see hdf.object.FileFormat#close() 1269 * 1270 * @throws HDF5Exception 1271 * If there is an error at the HDF5 library level. 1272 */ 1273 @Override 1274 public void close() throws HDF5Exception 1275 { 1276 if (fid < 0) { 1277 log.debug("close(): file {} is not open", fullFileName); 1278 return; 1279 } 1280 // The current working directory may be changed at Dataset.read() 1281 // by System.setProperty("user.dir", newdir) to make it work for external 1282 // datasets. We need to set it back to the original current working 1283 // directory (when hdf-java application started) before the file 1284 // is closed/opened. Otherwise, relative path, e.g. "./test.h5" may 1285 // not work 1286 String rootPath = System.getProperty("hdfview.workdir"); 1287 if (rootPath == null) { 1288 rootPath = System.getProperty("user.dir"); 1289 } 1290 System.setProperty("user.dir", rootPath); // H5.H5Dchdir_ext(rootPath); 1291 1292 // clean up unused objects 1293 if (rootObject != null) { 1294 HObject theObj = null; 1295 Iterator<HObject> it = getMembersBreadthFirst(rootObject).iterator(); 1296 while (it.hasNext()) { 1297 theObj = it.next(); 1298 1299 if (theObj instanceof Dataset) { 1300 log.trace("close(): clear Dataset {}", ((Dataset)theObj).toString()); 1301 ((Dataset)theObj).clear(); 1302 } 1303 else if (theObj instanceof Group) { 1304 log.trace("close(): clear Group {}", ((Group)theObj).toString()); 1305 ((Group)theObj).clear(); 1306 } 1307 } 1308 } 1309 1310 // Close all open objects associated with this file. 1311 try { 1312 int type = -1; 1313 long[] objids; 1314 long n = H5.H5Fget_obj_count(fid, HDF5Constants.H5F_OBJ_ALL); 1315 log.trace("close(): open objects={}", n); 1316 1317 if (n > 0) { 1318 if (n < Integer.MIN_VALUE || n > Integer.MAX_VALUE) 1319 throw new Exception("Invalid int size"); 1320 1321 objids = new long[(int)n]; 1322 H5.H5Fget_obj_ids(fid, HDF5Constants.H5F_OBJ_ALL, n, objids); 1323 1324 for (int i = 0; i < (int)n; i++) { 1325 log.trace("close(): object[{}] id={}", i, objids[i]); 1326 type = H5.H5Iget_type(objids[i]); 1327 1328 if (HDF5Constants.H5I_DATASET == type) { 1329 try { 1330 H5.H5Dclose(objids[i]); 1331 } 1332 catch (Exception ex2) { 1333 log.debug("close(): Object[{}] H5Dclose(objids[{}] {}) failure: ", i, i, 1334 objids[i], ex2); 1335 } 1336 } 1337 else if (HDF5Constants.H5I_GROUP == type) { 1338 try { 1339 H5.H5Gclose(objids[i]); 1340 } 1341 catch (Exception ex2) { 1342 log.debug("close(): Object[{}] H5Gclose(objids[{}] {}) failure: ", i, i, 1343 objids[i], ex2); 1344 } 1345 } 1346 else if (HDF5Constants.H5I_DATATYPE == type) { 1347 try { 1348 H5.H5Tclose(objids[i]); 1349 } 1350 catch (Exception ex2) { 1351 log.debug("close(): Object[{}] H5Tclose(objids[{}] {}) failure: ", i, i, 1352 objids[i], ex2); 1353 } 1354 } 1355 else if (HDF5Constants.H5I_ATTR == type) { 1356 try { 1357 H5.H5Aclose(objids[i]); 1358 } 1359 catch (Exception ex2) { 1360 log.debug("close(): Object[{}] H5Aclose(objids[{}] {}) failure: ", i, i, 1361 objids[i], ex2); 1362 } 1363 } 1364 else if (HDF5Constants.H5I_FILE == type) { 1365 int file_ref = H5.H5Iget_ref(objids[i]); 1366 log.debug("close(): Object[{}] objids[{}] is type File with ref count of {}", i, i, 1367 file_ref); 1368 } 1369 else { 1370 log.debug("close(): Object[{}] objids[{}] is type {}", i, i, type); 1371 } 1372 } // (int i=0; i<n; i++) 1373 } // ( n>0) 1374 } 1375 catch (Exception ex) { 1376 log.debug("close(): failure: ", ex); 1377 } 1378 1379 try { 1380 H5.H5Fflush(fid, HDF5Constants.H5F_SCOPE_GLOBAL); 1381 } 1382 catch (Exception ex) { 1383 log.debug("close(): H5Fflush(fid {}) failure: ", fid, ex); 1384 } 1385 1386 try { 1387 H5.H5Fclose(fid); 1388 } 1389 catch (Exception ex) { 1390 log.debug("close(): H5Fclose(fid {}) failure: ", fid, ex); 1391 } 1392 1393 // Set fid to -1 but don't reset rootObject 1394 fid = -1; 1395 } 1396 1397 /** 1398 * Returns the root object of the open HDF5 File. 1399 * 1400 * @see hdf.object.FileFormat#getRootObject() 1401 */ 1402 @Override 1403 public HObject getRootObject() 1404 { 1405 return rootObject; 1406 } 1407 1408 /* 1409 * (non-Javadoc) 1410 * 1411 * @see hdf.object.FileFormat#get(java.lang.String) 1412 */ 1413 @Override 1414 public HObject get(String path) throws Exception 1415 { 1416 log.trace("get({}): start", path); 1417 HObject obj = null; 1418 1419 if ((path == null) || (path.length() <= 0)) { 1420 log.debug("get(): path is null or invalid path length"); 1421 System.err.println("(path == null) || (path.length() <= 0)"); 1422 return null; 1423 } 1424 1425 // replace the wrong slash and get rid of "//" 1426 path = path.replace('\\', '/'); 1427 path = "/" + path; 1428 path = path.replaceAll("//", "/"); 1429 1430 // the whole file tree is loaded. find the object in the tree 1431 if (rootObject != null) { 1432 obj = findObject(this, path); 1433 } 1434 1435 // found object in memory 1436 if (obj != null) { 1437 log.trace("get(): Found object in memory"); 1438 return obj; 1439 } 1440 1441 // open only the requested object 1442 String name = null; 1443 String pPath = null; 1444 if (path.equals("/")) { 1445 name = "/"; // the root 1446 } 1447 else { 1448 // separate the parent path and the object name 1449 if (path.endsWith("/")) { 1450 path = path.substring(0, path.length() - 1); 1451 } 1452 1453 int idx = path.lastIndexOf('/'); 1454 name = path.substring(idx + 1); 1455 if (idx == 0) { 1456 pPath = "/"; 1457 } 1458 else { 1459 pPath = path.substring(0, idx); 1460 } 1461 } 1462 1463 // do not open the full tree structure, only the file handler 1464 long fid_before_open = fid; 1465 fid = open(false); 1466 if (fid < 0) { 1467 log.debug("get(): Invalid FID"); 1468 System.err.println("Could not open file handler"); 1469 return null; 1470 } 1471 1472 try { 1473 H5O_info_t info; 1474 int objType; 1475 long objid = H5.H5Oopen(fid, path, HDF5Constants.H5P_DEFAULT); 1476 1477 if (objid >= 0) { 1478 info = H5.H5Oget_info(objid); 1479 objType = info.type; 1480 if (objType == HDF5Constants.H5O_TYPE_DATASET) { 1481 long did = -1; 1482 try { 1483 did = H5.H5Dopen(fid, path, HDF5Constants.H5P_DEFAULT); 1484 obj = getDataset(did, name, pPath); 1485 } 1486 finally { 1487 try { 1488 H5.H5Dclose(did); 1489 } 1490 catch (Exception ex) { 1491 log.debug("get(): {} H5Dclose(did {}) failure: ", path, did, ex); 1492 } 1493 } 1494 } 1495 else if (objType == HDF5Constants.H5O_TYPE_GROUP) { 1496 long gid = -1; 1497 try { 1498 gid = H5.H5Gopen(fid, path, HDF5Constants.H5P_DEFAULT); 1499 H5Group pGroup = null; 1500 if (pPath != null) { 1501 pGroup = new H5Group(this, null, pPath, null); 1502 obj = getGroup(gid, name, pGroup); 1503 pGroup.addToMemberList(obj); 1504 } 1505 else { 1506 obj = getGroup(gid, name, pGroup); 1507 } 1508 } 1509 finally { 1510 try { 1511 H5.H5Gclose(gid); 1512 } 1513 catch (Exception ex) { 1514 log.debug("get(): {} H5Gclose(gid {}) failure: ", path, gid, ex); 1515 } 1516 } 1517 } 1518 else if (objType == HDF5Constants.H5O_TYPE_NAMED_DATATYPE) { 1519 obj = new H5Datatype(this, name, pPath); 1520 } 1521 } 1522 try { 1523 H5.H5Oclose(objid); 1524 } 1525 catch (Exception ex) { 1526 log.debug("get(): H5Oclose(objid {}) failure: ", objid, ex); 1527 ex.printStackTrace(); 1528 } 1529 } 1530 catch (Exception ex) { 1531 log.debug("get(): Exception finding obj {}", path, ex); 1532 obj = null; 1533 } 1534 finally { 1535 if ((fid_before_open <= 0) && (obj == null)) { 1536 // close the fid that is not attached to any object 1537 try { 1538 H5.H5Fclose(fid); 1539 } 1540 catch (Exception ex) { 1541 log.debug("get(): {} H5Fclose(fid {}) failure: ", path, fid, ex); 1542 } 1543 fid = fid_before_open; 1544 } 1545 } 1546 1547 return obj; 1548 } 1549 1550 /** 1551 * Creates a named datatype in a file. 1552 * 1553 * The following code creates a named datatype in a file. 1554 * 1555 * <pre> 1556 * H5File file = (H5File) h5file.createInstance("test_hdf5.h5", FileFormat.WRITE); 1557 * Datatype dtype = file.createDatatype( 1558 * Datatype.CLASS_INTEGER, 1559 * 4, 1560 * Datatype.NATIVE, 1561 * Datatype.NATIVE, 1562 * basetype); 1563 * H5Datatype h5dtype = file.createNamedDatatype( 1564 * dtype, 1565 * null, 1566 * "Native Integer"); 1567 * </pre> 1568 * 1569 * @param tnative 1570 * native datatype previously created 1571 * @param name 1572 * name of the datatype to create, e.g. "Native Integer". 1573 * @return The new datatype if successful; otherwise returns null. 1574 * @throws Exception 1575 * The exceptions thrown vary depending on the implementing class. 1576 */ 1577 @Override 1578 public Datatype createNamedDatatype(Datatype tnative, String name) throws Exception 1579 { 1580 log.trace("createNamedDatatype(): start: name={}", name); 1581 1582 H5Datatype dtype = null; 1583 1584 if (name != null) { 1585 long tid = -1; 1586 log.trace("createNamedDatatype(): name={}", name); 1587 try { 1588 tnative.setFullname(name, null); 1589 } 1590 catch (Exception ex) { 1591 log.debug("createNamedDatatype():setName(): {} failure: {}", name, ex.getMessage()); 1592 } 1593 try { 1594 if ((tid = tnative.createNative()) < 0) { 1595 log.debug("createNamedDatatype(): createNative() failure"); 1596 throw new Exception("createNative() failed"); 1597 } 1598 log.trace("createNamedDatatype(): createNative gets id={}", tid); 1599 1600 H5.H5Tcommit(fid, name, tid, HDF5Constants.H5P_DEFAULT, HDF5Constants.H5P_DEFAULT, 1601 HDF5Constants.H5P_DEFAULT); 1602 1603 int nativeClass = H5.H5Tget_class(tid); 1604 if (nativeClass == HDF5Constants.H5T_REFERENCE) 1605 dtype = new H5ReferenceType(this, name, null); 1606 else 1607 dtype = new H5Datatype(this, name, null); 1608 } 1609 finally { 1610 H5.H5Tclose(tid); 1611 } 1612 } 1613 else { 1614 dtype = (H5Datatype)tnative; 1615 } 1616 1617 return dtype; 1618 } 1619 1620 /*************************************************************************** 1621 * Methods related to Datatypes and HObjects in HDF5 Files. Strictly speaking, these methods aren't 1622 *related to H5File and the actions could be carried out through the H5Group, H5Datatype and H5*DS 1623 *classes. But, in some cases they allow a null input and expect the generated object to be of HDF5 type. 1624 *So, we put them in the H5File class so that we create the proper type of HObject... H5Group for example. 1625 * 1626 * Here again, if there could be Implementation Class methods we'd use those. But, since we can't override 1627 *class methods (they can only be shadowed in Java), these are instance methods. 1628 * 1629 **************************************************************************/ 1630 1631 /* 1632 * (non-Javadoc) 1633 * 1634 * @see hdf.object.FileFormat#createDatatype(int, int, int, int) 1635 */ 1636 @Override 1637 public Datatype createDatatype(int tclass, int tsize, int torder, int tsign) throws Exception 1638 { 1639 return new H5Datatype(tclass, tsize, torder, tsign); 1640 } 1641 1642 /* 1643 * (non-Javadoc) 1644 * 1645 * @see hdf.object.FileFormat#createDatatype(int, int, int, int, Datatype) 1646 */ 1647 @Override 1648 public Datatype createDatatype(int tclass, int tsize, int torder, int tsign, Datatype tbase) 1649 throws Exception 1650 { 1651 return new H5Datatype(tclass, tsize, torder, tsign, tbase); 1652 } 1653 1654 /* 1655 * (non-Javadoc) 1656 * 1657 * @see hdf.object.FileFormat#createScalarDS(java.lang.String, hdf.object.Group, hdf.object.Datatype, 1658 * long[], long[], long[], int, java.lang.Object) 1659 */ 1660 @Override 1661 public Dataset createScalarDS(String name, Group pgroup, Datatype type, long[] dims, long[] maxdims, 1662 long[] chunks, int gzip, Object fillValue, Object data) throws Exception 1663 { 1664 log.trace("createScalarDS(): name={}", name); 1665 // create new dataset at the root group by default 1666 if (pgroup == null) 1667 pgroup = (Group)get("/"); 1668 1669 return H5ScalarDS.create(name, pgroup, type, dims, maxdims, chunks, gzip, fillValue, data); 1670 } 1671 1672 /* 1673 * (non-Javadoc) 1674 * 1675 * @see hdf.object.FileFormat#createCompoundDS(java.lang.String, hdf.object.Group, long[], long[], long[], 1676 * int, java.lang.String[], hdf.object.Datatype[], int[], java.lang.Object) 1677 */ 1678 @Override 1679 public Dataset createCompoundDS(String name, Group pgroup, long[] dims, long[] maxdims, long[] chunks, 1680 int gzip, String[] memberNames, Datatype[] memberDatatypes, 1681 int[] memberSizes, Object data) throws Exception 1682 { 1683 log.trace("createCompoundDS(): start: name={}", name); 1684 int nMembers = memberNames.length; 1685 int memberRanks[] = new int[nMembers]; 1686 long memberDims[][] = new long[nMembers][1]; 1687 Dataset ds = null; 1688 1689 for (int i = 0; i < nMembers; i++) { 1690 memberRanks[i] = 1; 1691 if (memberSizes == null) 1692 memberDims[i][0] = 1; 1693 else 1694 memberDims[i][0] = memberSizes[i]; 1695 } 1696 1697 // create new dataset at the root group by default 1698 if (pgroup == null) 1699 pgroup = (Group)get("/"); 1700 ds = H5CompoundDS.create(name, pgroup, dims, maxdims, chunks, gzip, memberNames, memberDatatypes, 1701 memberRanks, memberDims, data); 1702 1703 return ds; 1704 } 1705 1706 /* 1707 * (non-Javadoc) 1708 * 1709 * @see hdf.object.FileFormat#createImage(java.lang.String, hdf.object.Group, hdf.object.Datatype, 1710 * long[], long[], long[], int, int, int, java.lang.Object) 1711 */ 1712 @Override 1713 public Dataset createImage(String name, Group pgroup, Datatype type, long[] dims, long[] maxdims, 1714 long[] chunks, int gzip, int ncomp, int interlace, Object data) 1715 throws Exception 1716 { 1717 log.trace("createImage(): start: name={}", name); 1718 // create at the root group by default 1719 if (pgroup == null) 1720 pgroup = (Group)get("/"); 1721 1722 H5ScalarDS dataset = 1723 (H5ScalarDS)H5ScalarDS.create(name, pgroup, type, dims, maxdims, chunks, gzip, data); 1724 1725 try { 1726 H5File.createImageAttributes(dataset, interlace); 1727 dataset.setIsImage(true); 1728 } 1729 catch (Exception ex) { 1730 log.debug("createImage(): {} createImageAttributtes failure: ", name, ex); 1731 } 1732 1733 return dataset; 1734 } 1735 1736 /*** 1737 * Creates a new group with specified name in existing group. 1738 * 1739 * @see hdf.object.FileFormat#createGroup(java.lang.String, hdf.object.Group) 1740 */ 1741 @Override 1742 public Group createGroup(String name, Group pgroup) throws Exception 1743 { 1744 return this.createGroup(name, pgroup, HDF5Constants.H5P_DEFAULT); 1745 } 1746 1747 /*** 1748 * Creates a new group with specified name in existing group and with the group creation properties list, 1749 * gplist. 1750 * 1751 * @see hdf.object.h5.H5Group#create(java.lang.String, hdf.object.Group, long...) 1752 * 1753 */ 1754 @Override 1755 public Group createGroup(String name, Group pgroup, long... gplist) throws Exception 1756 { 1757 // create new group at the root 1758 if (pgroup == null) 1759 pgroup = (Group)this.get("/"); 1760 1761 return H5Group.create(name, pgroup, gplist); 1762 } 1763 1764 /*** 1765 * Creates the group creation property list identifier, gcpl. This identifier is used when creating 1766 * Groups. 1767 * 1768 * @see hdf.object.FileFormat#createGcpl(int, int, int) 1769 * 1770 */ 1771 @Override 1772 public long createGcpl(int creationorder, int maxcompact, int mindense) throws Exception 1773 { 1774 long gcpl = -1; 1775 try { 1776 gcpl = H5.H5Pcreate(HDF5Constants.H5P_GROUP_CREATE); 1777 if (gcpl >= 0) { 1778 // Set link creation order. 1779 if (creationorder == Group.CRT_ORDER_TRACKED) { 1780 log.trace("createGcpl(): creation order ORDER_TRACKED"); 1781 H5.H5Pset_link_creation_order(gcpl, HDF5Constants.H5P_CRT_ORDER_TRACKED); 1782 } 1783 else if (creationorder == Group.CRT_ORDER_INDEXED) { 1784 log.trace("createGcpl(): creation order ORDER_INDEXED"); 1785 H5.H5Pset_link_creation_order(gcpl, HDF5Constants.H5P_CRT_ORDER_TRACKED + 1786 HDF5Constants.H5P_CRT_ORDER_INDEXED); 1787 } 1788 // Set link storage. 1789 H5.H5Pset_link_phase_change(gcpl, maxcompact, mindense); 1790 } 1791 } 1792 catch (Exception ex) { 1793 log.debug("createGcpl(): failure: ", ex); 1794 ex.printStackTrace(); 1795 } 1796 1797 return gcpl; 1798 } 1799 1800 /* 1801 * (non-Javadoc) 1802 * 1803 * @see hdf.object.FileFormat#createLink(hdf.object.Group, java.lang.String, hdf.object.HObject) 1804 */ 1805 @Override 1806 public HObject createLink(Group parentGroup, String name, Object currentObj) throws Exception 1807 { 1808 if (currentObj instanceof HObject) 1809 return this.createLink(parentGroup, name, (HObject)currentObj, Group.LINK_TYPE_HARD); 1810 else if (currentObj instanceof String) 1811 return this.createLink(parentGroup, name, (String)currentObj, Group.LINK_TYPE_HARD); 1812 1813 return null; 1814 } 1815 1816 /** 1817 * Creates a link to an object in the open file. 1818 * 1819 * If parentGroup is null, the new link is created in the root group. 1820 * 1821 * @param parentGroup 1822 * The group where the link is created. 1823 * @param name 1824 * The name of the link. 1825 * @param currentObj 1826 * The existing object the new link will reference. 1827 * @param lType 1828 * The type of link to be created. It can be a hard link, a soft link or an external link. 1829 * 1830 * @return The object pointed to by the new link if successful; otherwise returns null. 1831 * 1832 * @throws Exception 1833 * The exceptions thrown vary depending on the implementing class. 1834 */ 1835 @Override 1836 public HObject createLink(Group parentGroup, String name, HObject currentObj, int lType) throws Exception 1837 { 1838 log.trace("createLink(): start: name={}", name); 1839 HObject obj = null; 1840 int type = 0; 1841 String current_full_name = null; 1842 String new_full_name = null; 1843 String parent_path = null; 1844 1845 if (currentObj == null) { 1846 log.debug("createLink(): Link target is null"); 1847 throw new HDF5Exception("The object pointed to by the link cannot be null."); 1848 } 1849 if ((parentGroup == null) || parentGroup.isRoot()) 1850 parent_path = HObject.SEPARATOR; 1851 else 1852 parent_path = 1853 parentGroup.getPath() + HObject.SEPARATOR + parentGroup.getName() + HObject.SEPARATOR; 1854 1855 new_full_name = parent_path + name; 1856 1857 if (lType == Group.LINK_TYPE_HARD) { 1858 type = HDF5Constants.H5L_TYPE_HARD; 1859 log.trace("createLink(): type H5L_TYPE_HARD"); 1860 } 1861 else if (lType == Group.LINK_TYPE_SOFT) { 1862 type = HDF5Constants.H5L_TYPE_SOFT; 1863 log.trace("createLink(): type H5L_TYPE_SOFT"); 1864 } 1865 else if (lType == Group.LINK_TYPE_EXTERNAL) { 1866 type = HDF5Constants.H5L_TYPE_EXTERNAL; 1867 log.trace("createLink(): type H5L_TYPE_EXTERNAL"); 1868 } 1869 1870 if (H5.H5Lexists(fid, new_full_name, HDF5Constants.H5P_DEFAULT)) { 1871 H5.H5Ldelete(fid, new_full_name, HDF5Constants.H5P_DEFAULT); 1872 } 1873 1874 if (type == HDF5Constants.H5L_TYPE_HARD) { 1875 if ((currentObj instanceof Group) && ((Group)currentObj).isRoot()) { 1876 log.debug("createLink(): cannot create link to root group"); 1877 throw new HDF5Exception("Cannot make a link to the root group."); 1878 } 1879 current_full_name = currentObj.getPath() + HObject.SEPARATOR + currentObj.getName(); 1880 1881 H5.H5Lcreate_hard(fid, current_full_name, fid, new_full_name, HDF5Constants.H5P_DEFAULT, 1882 HDF5Constants.H5P_DEFAULT); 1883 } 1884 1885 else if (type == HDF5Constants.H5L_TYPE_SOFT) { 1886 log.trace("createLink(): H5Lcreate_soft: {} in {} as {}", currentObj.getFullName(), fid, 1887 new_full_name); 1888 H5.H5Lcreate_soft(currentObj.getFullName(), fid, new_full_name, HDF5Constants.H5P_DEFAULT, 1889 HDF5Constants.H5P_DEFAULT); 1890 } 1891 1892 else if (type == HDF5Constants.H5L_TYPE_EXTERNAL) { 1893 log.trace("createLink(): H5Lcreate_external: File={} {} in {} as {}", currentObj.getFile(), 1894 currentObj.getFullName(), fid, new_full_name); 1895 H5.H5Lcreate_external(currentObj.getFile(), currentObj.getFullName(), fid, new_full_name, 1896 HDF5Constants.H5P_DEFAULT, HDF5Constants.H5P_DEFAULT); 1897 } 1898 1899 if (currentObj instanceof Group) { 1900 log.trace("createLink(): Link target is type H5Group"); 1901 obj = new H5Group(this, name, parent_path, parentGroup); 1902 } 1903 else if (currentObj instanceof H5ReferenceType) { 1904 log.trace("createLink(): Link target is type H5Datatype"); 1905 obj = new H5ReferenceType(this, name, parent_path); 1906 } 1907 else if (currentObj instanceof H5Datatype) { 1908 log.trace("createLink(): Link target is type H5Datatype"); 1909 obj = new H5Datatype(this, name, parent_path); 1910 } 1911 else if (currentObj instanceof H5CompoundDS) { 1912 log.trace("createLink(): Link target is type H5CompoundDS"); 1913 obj = new H5CompoundDS(this, name, parent_path); 1914 } 1915 else if (currentObj instanceof H5ScalarDS) { 1916 log.trace("createLink(): Link target is type H5ScalarDS"); 1917 obj = new H5ScalarDS(this, name, parent_path); 1918 } 1919 else 1920 log.trace("createLink(): Link target is type unknown"); 1921 1922 return obj; 1923 } 1924 1925 /** 1926 * Creates a soft or external link to object in a file that does not exist at the time the link is 1927 * created. 1928 * 1929 * @param parentGroup 1930 * The group where the link is created. 1931 * @param name 1932 * The name of the link. 1933 * @param currentObj 1934 * The name of the object the new link will reference. The object doesn't have to exist. 1935 * @param lType 1936 * The type of link to be created. 1937 * 1938 * @return The H5Link object pointed to by the new link if successful; otherwise returns null. 1939 * 1940 * @throws Exception 1941 * The exceptions thrown vary depending on the implementing class. 1942 */ 1943 @Override 1944 public HObject createLink(Group parentGroup, String name, String currentObj, int lType) throws Exception 1945 { 1946 log.trace("createLink(): start: name={}", name); 1947 HObject obj = null; 1948 int type = 0; 1949 String new_full_name = null; 1950 String parent_path = null; 1951 1952 if (currentObj == null) { 1953 log.debug("createLink(): Link target is null"); 1954 throw new HDF5Exception("The object pointed to by the link cannot be null."); 1955 } 1956 if ((parentGroup == null) || parentGroup.isRoot()) 1957 parent_path = HObject.SEPARATOR; 1958 else 1959 parent_path = 1960 parentGroup.getPath() + HObject.SEPARATOR + parentGroup.getName() + HObject.SEPARATOR; 1961 1962 new_full_name = parent_path + name; 1963 1964 if (lType == Group.LINK_TYPE_HARD) { 1965 type = HDF5Constants.H5L_TYPE_HARD; 1966 log.trace("createLink(): type H5L_TYPE_HARD"); 1967 } 1968 else if (lType == Group.LINK_TYPE_SOFT) { 1969 type = HDF5Constants.H5L_TYPE_SOFT; 1970 log.trace("createLink(): type H5L_TYPE_SOFT"); 1971 } 1972 else if (lType == Group.LINK_TYPE_EXTERNAL) { 1973 type = HDF5Constants.H5L_TYPE_EXTERNAL; 1974 log.trace("createLink(): type H5L_TYPE_EXTERNAL"); 1975 } 1976 1977 if (H5.H5Lexists(fid, new_full_name, HDF5Constants.H5P_DEFAULT)) { 1978 H5.H5Ldelete(fid, new_full_name, HDF5Constants.H5P_DEFAULT); 1979 } 1980 1981 if (type == HDF5Constants.H5L_TYPE_SOFT) { 1982 H5.H5Lcreate_soft(currentObj, fid, new_full_name, HDF5Constants.H5P_DEFAULT, 1983 HDF5Constants.H5P_DEFAULT); 1984 } 1985 1986 else if (type == HDF5Constants.H5L_TYPE_EXTERNAL) { 1987 String fileName = null; 1988 String objectName = null; 1989 1990 // separate the object name and the file name 1991 fileName = currentObj.substring(0, currentObj.lastIndexOf(FileFormat.FILE_OBJ_SEP)); 1992 objectName = currentObj.substring(currentObj.indexOf(FileFormat.FILE_OBJ_SEP)); 1993 objectName = objectName.substring(3); 1994 1995 H5.H5Lcreate_external(fileName, objectName, fid, new_full_name, HDF5Constants.H5P_DEFAULT, 1996 HDF5Constants.H5P_DEFAULT); 1997 } 1998 1999 if (name.startsWith(HObject.SEPARATOR)) { 2000 name = name.substring(1); 2001 } 2002 obj = new H5Link(this, name, parent_path); 2003 2004 return obj; 2005 } 2006 2007 /** 2008 * reload the sub-tree structure from file. 2009 * 2010 * reloadTree(Group g) is useful when the structure of the group in file is changed while the group 2011 * structure in memory is not changed. 2012 * 2013 * @param g 2014 * the group where the structure is to be reloaded in memory 2015 */ 2016 public void reloadTree(Group g) 2017 { 2018 if (fid < 0 || rootObject == null || g == null) { 2019 log.debug("reloadTree(): Invalid fid or null object"); 2020 return; 2021 } 2022 2023 depth_first(g, Integer.MIN_VALUE); 2024 } 2025 2026 /* 2027 * (non-Javadoc) NOTE: Object references are copied but not updated by this method. 2028 * 2029 * @see hdf.object.FileFormat#copy(hdf.object.HObject, hdf.object.Group, java.lang.String) 2030 */ 2031 @Override 2032 public HObject copy(HObject srcObj, Group dstGroup, String dstName) throws Exception 2033 { 2034 log.trace("copy(): start: srcObj={} dstGroup={} dstName={}", srcObj, dstGroup, dstName); 2035 if ((srcObj == null) || (dstGroup == null)) { 2036 log.debug("copy(): srcObj or dstGroup is null"); 2037 return null; 2038 } 2039 2040 if (dstName == null) 2041 dstName = srcObj.getName(); 2042 2043 List<HObject> members = dstGroup.getMemberList(); 2044 int n = members.size(); 2045 for (int i = 0; i < n; i++) { 2046 HObject obj = members.get(i); 2047 String name = obj.getName(); 2048 while (name.equals(dstName)) 2049 dstName += "~copy"; 2050 } 2051 2052 HObject newObj = null; 2053 if (srcObj instanceof Dataset) { 2054 log.trace("copy(): srcObj instanceof Dataset"); 2055 newObj = copyDataset((Dataset)srcObj, (H5Group)dstGroup, dstName); 2056 } 2057 else if (srcObj instanceof H5Group) { 2058 log.trace("copy(): srcObj instanceof H5Group"); 2059 newObj = copyGroup((H5Group)srcObj, (H5Group)dstGroup, dstName); 2060 } 2061 else if (srcObj instanceof H5Datatype) { 2062 log.trace("copy(): srcObj instanceof H5Datatype"); 2063 newObj = copyDatatype((H5Datatype)srcObj, (H5Group)dstGroup, dstName); 2064 } 2065 2066 return newObj; 2067 } 2068 2069 /* 2070 * (non-Javadoc) 2071 * 2072 * @see hdf.object.FileFormat#delete(hdf.object.HObject) 2073 */ 2074 @Override 2075 public void delete(HObject obj)throws Exception 2076 { 2077 if ((obj == null) || (fid < 0)) { 2078 log.debug("delete(): Invalid FID or object is null"); 2079 return; 2080 } 2081 2082 String name = obj.getPath() + obj.getName(); 2083 2084 H5.H5Ldelete(fid, name, HDF5Constants.H5P_DEFAULT); 2085 } 2086 2087 /* 2088 * (non-Javadoc) 2089 * 2090 * @see hdf.object.FileFormat#writeAttribute(hdf.object.HObject, hdf.object.Attribute, boolean) 2091 */ 2092 @Override 2093 public void writeAttribute(HObject obj, Attribute attr, boolean attrExisted) throws HDF5Exception 2094 { 2095 String obj_name = obj.getFullName(); 2096 String name = attr.getAttributeName(); 2097 long tid = -1; 2098 long sid = -1; 2099 long aid = -1; 2100 log.trace("writeAttribute(): name is {}", name); 2101 2102 long objID = obj.open(); 2103 if (objID < 0) { 2104 log.debug("writeAttribute(): Invalid Object ID"); 2105 return; 2106 } 2107 2108 if ((tid = attr.getAttributeDatatype().createNative()) >= 0) { 2109 log.trace("writeAttribute(): tid {} from toNative :{}", tid, 2110 attr.getAttributeDatatype().getDescription()); 2111 try { 2112 if (attr.isAttributeNULL()) 2113 sid = H5.H5Screate(HDF5Constants.H5S_NULL); 2114 else if (attr.isAttributeScalar()) 2115 sid = H5.H5Screate(HDF5Constants.H5S_SCALAR); 2116 else 2117 sid = H5.H5Screate_simple(attr.getAttributeRank(), attr.getAttributeDims(), null); 2118 2119 if (attrExisted) 2120 aid = H5.H5Aopen_by_name(objID, obj_name, name, HDF5Constants.H5P_DEFAULT, 2121 HDF5Constants.H5P_DEFAULT); 2122 else 2123 aid = H5.H5Acreate(objID, name, tid, sid, HDF5Constants.H5P_DEFAULT, 2124 HDF5Constants.H5P_DEFAULT); 2125 log.trace("writeAttribute(): aid {} opened/created", aid); 2126 2127 if (!attr.isAttributeNULL()) { 2128 // update value of the attribute 2129 Object attrValue; 2130 try { 2131 attrValue = attr.getAttributeData(); 2132 } 2133 catch (Exception ex) { 2134 attrValue = null; 2135 log.trace("writeAttribute(): getAttributeData() failure:", ex); 2136 } 2137 2138 // log.trace("writeAttribute(): attrValue={}", attrValue); 2139 if (attrValue != null) { 2140 try { 2141 ((H5Attribute)attr).AttributeCommonIO(aid, H5File.IO_TYPE.WRITE, attrValue); 2142 } 2143 catch (Exception ex) { 2144 log.debug("writeAttribute(): failed to write attribute: ", ex); 2145 } 2146 } // (attrValue != null) 2147 } 2148 } 2149 finally { 2150 try { 2151 H5.H5Tclose(tid); 2152 } 2153 catch (Exception ex) { 2154 log.debug("writeAttribute(): H5Tclose(tid {}) failure: ", tid, ex); 2155 } 2156 try { 2157 H5.H5Sclose(sid); 2158 } 2159 catch (Exception ex) { 2160 log.debug("writeAttribute(): H5Sclose(sid {}) failure: ", sid, ex); 2161 } 2162 try { 2163 H5.H5Aclose(aid); 2164 } 2165 catch (Exception ex) { 2166 log.debug("writeAttribute(): H5Aclose(aid {}) failure: ", aid, ex); 2167 } 2168 } 2169 } 2170 else { 2171 log.debug("writeAttribute(): toNative failure"); 2172 } 2173 2174 obj.close(objID); 2175 } 2176 2177 /*************************************************************************** 2178 * Implementations for methods specific to H5File 2179 **************************************************************************/ 2180 2181 /** 2182 * Opens a file with specific file access property list. 2183 * 2184 * This function does the same as "long open()" except the you can also pass an HDF5 file access property 2185 * to file open. For example, 2186 * 2187 * <pre> 2188 * // All open objects remaining in the file are closed then file is closed 2189 * long plist = H5.H5Pcreate(HDF5Constants.H5P_FILE_ACCESS); 2190 * H5.H5Pset_fclose_degree(plist, HDF5Constants.H5F_CLOSE_STRONG); 2191 * long fid = open(plist); 2192 * </pre> 2193 * 2194 * @param plist 2195 * a file access property list identifier. 2196 * 2197 * @return the file identifier if successful; otherwise returns negative value. 2198 * 2199 * @throws Exception 2200 * If there is a failure. 2201 */ 2202 public long open(long plist) throws Exception { return open(true, plist); } 2203 2204 /*************************************************************************** 2205 * Private methods. 2206 **************************************************************************/ 2207 2208 /** 2209 * Opens access to this file. 2210 * 2211 * @param loadFullHierarchy 2212 * if true, load the full hierarchy into memory; otherwise just opens the file identifier. 2213 * 2214 * @return the file identifier if successful; otherwise returns negative value. 2215 * 2216 * @throws Exception 2217 * If there is a failure. 2218 */ 2219 private long open(boolean loadFullHierarchy) throws Exception 2220 { 2221 long the_fid = -1; 2222 2223 long plist = HDF5Constants.H5P_DEFAULT; 2224 2225 // BUG: HDF5Constants.H5F_CLOSE_STRONG does not flush cache 2226 /** 2227 * try { //All open objects remaining in the file are closed // then file is closed plist = 2228 * H5.H5Pcreate (HDF5Constants.H5P_FILE_ACCESS); H5.H5Pset_fclose_degree ( plist, 2229 * HDF5Constants.H5F_CLOSE_STRONG); } catch (Exception ex) {} the_fid = open(loadFullHierarchy, 2230 * plist); try { H5.H5Pclose(plist); } catch (Exception ex) {} 2231 */ 2232 2233 log.trace("open(): loadFull={}", loadFullHierarchy); 2234 the_fid = open(loadFullHierarchy, plist); 2235 2236 return the_fid; 2237 } 2238 2239 /** 2240 * Opens access to this file. 2241 * 2242 * @param loadFullHierarchy 2243 * if true, load the full hierarchy into memory; otherwise just opens the file identifier. 2244 * 2245 * @return the file identifier if successful; otherwise returns negative value. 2246 * 2247 * @throws Exception 2248 * If there is a failure. 2249 */ 2250 private long open(boolean loadFullHierarchy, long plist) throws Exception 2251 { 2252 log.trace("open(loadFullHierarchy = {}, plist = {}): start", loadFullHierarchy, plist); 2253 if (fid > 0) { 2254 log.trace("open(): FID already opened"); 2255 return fid; // file is opened already 2256 } 2257 2258 // The cwd may be changed at Dataset.read() by System.setProperty("user.dir", newdir) 2259 // to make it work for external datasets. We need to set it back 2260 // before the file is closed/opened. 2261 String rootPath = System.getProperty("hdfview.workdir"); 2262 if (rootPath == null) { 2263 rootPath = System.getProperty("user.dir"); 2264 } 2265 System.setProperty("user.dir", rootPath); 2266 2267 log.trace("open(): flag={}", flag); 2268 // check for valid file access permission 2269 if (flag < 0) { 2270 log.debug("open(): Invalid access identifier -- " + flag); 2271 throw new HDF5Exception("Invalid access identifer -- " + flag); 2272 } 2273 else if (HDF5Constants.H5F_ACC_CREAT == flag) { 2274 // create a new file 2275 log.trace("open(): create file"); 2276 fid = H5.H5Fcreate(fullFileName, HDF5Constants.H5F_ACC_TRUNC, HDF5Constants.H5P_DEFAULT, 2277 HDF5Constants.H5P_DEFAULT); 2278 H5.H5Fflush(fid, HDF5Constants.H5F_SCOPE_LOCAL); 2279 H5.H5Fclose(fid); 2280 flag = HDF5Constants.H5F_ACC_RDWR; 2281 } 2282 else if (!exists()) { 2283 log.debug("open(): File {} does not exist", fullFileName); 2284 throw new HDF5Exception("File does not exist -- " + fullFileName); 2285 } 2286 else if (((flag == HDF5Constants.H5F_ACC_RDWR) || (flag == HDF5Constants.H5F_ACC_CREAT)) && 2287 !canWrite()) { 2288 log.debug("open(): Cannot write file {}", fullFileName); 2289 throw new HDF5Exception("Cannot write file, try opening as read-only -- " + fullFileName); 2290 } 2291 else if ((flag == HDF5Constants.H5F_ACC_RDONLY) && !canRead()) { 2292 log.debug("open(): Cannot read file {}", fullFileName); 2293 throw new HDF5Exception("Cannot read file -- " + fullFileName); 2294 } 2295 2296 try { 2297 fid = H5.H5Fopen(fullFileName, flag, plist); 2298 } 2299 catch (Exception ex) { 2300 try { 2301 log.debug("open(): open failed, attempting to open file read-only", ex); 2302 fid = H5.H5Fopen(fullFileName, HDF5Constants.H5F_ACC_RDONLY, HDF5Constants.H5P_DEFAULT); 2303 isReadOnly = true; 2304 } 2305 catch (Exception ex2) { 2306 // Attempt to open the file as a split file or family file 2307 try { 2308 File tmpf = new File(fullFileName); 2309 String tmpname = tmpf.getName(); 2310 int idx = tmpname.lastIndexOf('.'); 2311 2312 if (tmpname.contains("-m")) { 2313 log.debug("open(): open read-only failed, attempting to open split file"); 2314 2315 while (idx > 0) { 2316 char c = tmpname.charAt(idx - 1); 2317 if (c != '-') 2318 idx--; 2319 else 2320 break; 2321 } 2322 2323 if (idx > 0) { 2324 tmpname = tmpname.substring(0, idx - 1); 2325 log.trace("open(): attempting to open split file with name {}", tmpname); 2326 long pid = H5.H5Pcreate(HDF5Constants.H5P_FILE_ACCESS); 2327 H5.H5Pset_fapl_split(pid, "-m.h5", HDF5Constants.H5P_DEFAULT, "-r.h5", 2328 HDF5Constants.H5P_DEFAULT); 2329 fid = H5.H5Fopen(tmpf.getParent() + File.separator + tmpname, flag, pid); 2330 H5.H5Pclose(pid); 2331 } 2332 } 2333 else { 2334 log.debug("open(): open read-only failed, checking for file family"); 2335 // try to see if it is a file family, always open a family file 2336 // from the first one since other files will not be recognized 2337 // as an HDF5 file 2338 int cnt = idx; 2339 while (idx > 0) { 2340 char c = tmpname.charAt(idx - 1); 2341 if (Character.isDigit(c)) 2342 idx--; 2343 else 2344 break; 2345 } 2346 2347 if (idx > 0) { 2348 cnt -= idx; 2349 tmpname = tmpname.substring(0, idx) + "%0" + cnt + "d" + 2350 tmpname.substring(tmpname.lastIndexOf('.')); 2351 log.trace("open(): attempting to open file family with name {}", tmpname); 2352 long pid = H5.H5Pcreate(HDF5Constants.H5P_FILE_ACCESS); 2353 H5.H5Pset_fapl_family(pid, 0, HDF5Constants.H5P_DEFAULT); 2354 fid = H5.H5Fopen(tmpf.getParent() + File.separator + tmpname, flag, pid); 2355 H5.H5Pclose(pid); 2356 } 2357 } 2358 } 2359 catch (Exception ex3) { 2360 log.debug("open(): open failed: ", ex3); 2361 } 2362 } 2363 } 2364 2365 initLibBounds(); 2366 2367 if ((fid >= 0) && loadFullHierarchy) { 2368 long n = H5.H5Fget_obj_count(fid, HDF5Constants.H5F_OBJ_ALL); 2369 log.trace("open(): open objects={}", n); 2370 // load the hierarchy of the file 2371 loadIntoMemory(); 2372 } 2373 2374 log.trace("open(loadFullHierarchy = {}, plist = {}): finish", loadFullHierarchy, plist); 2375 return fid; 2376 } 2377 2378 /** 2379 * Loads the file structure into memory. 2380 */ 2381 private void loadIntoMemory() 2382 { 2383 if (fid < 0) { 2384 log.debug("loadIntoMemory(): Invalid FID"); 2385 return; 2386 } 2387 2388 /* 2389 * TODO: Root group's name should be changed to 'this.getName()' and all 2390 * previous accesses of this field should now use getPath() instead of getName() 2391 * to get the root group. The root group actually does have a path of "/". The 2392 * depth_first method will have to be changed to setup other object paths 2393 * appropriately, as it currently assumes the root path to be null. 2394 */ 2395 rootObject = new H5Group(this, "/", null, null); 2396 log.trace("loadIntoMemory(): depth_first on root"); 2397 depth_first(rootObject, 0); 2398 } 2399 2400 /** 2401 * Retrieves the file structure by depth-first order, recursively. The current implementation retrieves 2402 * groups and datasets only. It does not include named datatypes and soft links. 2403 * 2404 * It also detects and stops loops. A loop is detected if there exists an object with the same object ID 2405 * by tracing a path back up to the root. 2406 * 2407 * @param parentObject 2408 * the parent object. 2409 */ 2410 @SuppressWarnings("deprecation") 2411 private int depth_first(HObject parentObject, int nTotal) 2412 { 2413 log.trace("depth_first({}): start", parentObject); 2414 2415 int nelems; 2416 String fullPath = null; 2417 String ppath = null; 2418 long gid = -1; 2419 2420 H5Group pgroup = (H5Group)parentObject; 2421 ppath = pgroup.getPath(); 2422 2423 if (ppath == null) 2424 fullPath = HObject.SEPARATOR; 2425 else 2426 fullPath = ppath + pgroup.getName() + HObject.SEPARATOR; 2427 2428 nelems = 0; 2429 try { 2430 gid = pgroup.open(); 2431 H5G_info_t info = H5.H5Gget_info(gid); 2432 nelems = (int)info.nlinks; 2433 } 2434 catch (HDF5Exception ex) { 2435 nelems = -1; 2436 log.debug("depth_first({}): H5Gget_info(gid {}) failure: ", parentObject, gid, ex); 2437 } 2438 2439 if (nelems <= 0) { 2440 pgroup.close(gid); 2441 log.debug("depth_first({}): nelems <= 0", parentObject); 2442 return nTotal; 2443 } 2444 2445 // since each call of H5.H5Gget_objname_by_idx() takes about one second. 2446 // 1,000,000 calls take 12 days. Instead of calling it in a loop, 2447 // we use only one call to get all the information, which takes about 2448 // two seconds 2449 int[] objTypes = new int[nelems]; 2450 long[] fNos = new long[nelems]; 2451 hdf.hdf5lib.structs.H5O_token_t[] objTokens = new hdf.hdf5lib.structs.H5O_token_t[nelems]; 2452 String[] objNames = new String[nelems]; 2453 2454 try { 2455 H5.H5Gget_obj_info_full(fid, fullPath, objNames, objTypes, null, fNos, objTokens, indexType, 2456 indexOrder); 2457 } 2458 catch (HDF5Exception ex) { 2459 log.debug("depth_first({}): failure: ", parentObject, ex); 2460 ex.printStackTrace(); 2461 return nTotal; 2462 } 2463 2464 int nStart = getStartMembers(); 2465 int nMax = getMaxMembers(); 2466 2467 String obj_name; 2468 int obj_type; 2469 2470 // Iterate through the file to see members of the group 2471 for (int i = 0; i < nelems; i++) { 2472 obj_name = objNames[i]; 2473 obj_type = objTypes[i]; 2474 log.trace("depth_first({}): obj_name={}, obj_type={}", parentObject, obj_name, obj_type); 2475 log.trace("depth_first({}): objTokens[{}]={}", parentObject, i, objTokens[i].data); 2476 long[] objtok = HDFNativeData.byteToLong(objTokens[i].data); 2477 log.trace("depth_first({}): objtok[0]={}, objtok[1]={}, fNos[{}]={}", parentObject, objtok[0], 2478 objtok[1], i, fNos[i]); 2479 2480 if (obj_name == null) { 2481 log.trace("depth_first({}): continue after null obj_name", parentObject); 2482 continue; 2483 } 2484 2485 nTotal++; 2486 2487 if (nMax > 0) { 2488 if ((nTotal - nStart) >= nMax) 2489 break; // loaded enough objects 2490 } 2491 2492 boolean skipLoad = false; 2493 if ((nTotal > 0) && (nTotal < nStart)) 2494 skipLoad = true; 2495 2496 // create a new objects 2497 long[] oid = null; 2498 if (obj_type == HDF5Constants.H5O_TYPE_GROUP) { 2499 H5Group g = new H5Group(this, obj_name, fullPath, pgroup); 2500 oid = g.getOID(); 2501 2502 pgroup.addToMemberList(g); 2503 2504 // detect and stop loops 2505 // a loop is detected if there exists object with the same 2506 // object ID by tracing path back up to the root. 2507 boolean hasLoop = false; 2508 H5Group tmpObj = (H5Group)parentObject; 2509 2510 while (tmpObj != null) { 2511 if (tmpObj.equalsOID(oid) && (tmpObj.getPath() != null)) { 2512 hasLoop = true; 2513 break; 2514 } 2515 else { 2516 tmpObj = (H5Group)tmpObj.getParent(); 2517 } 2518 } 2519 2520 // recursively go through the next group 2521 // stops if it has loop. 2522 if (!hasLoop) { 2523 nTotal = depth_first(g, nTotal); 2524 } 2525 } 2526 else if (skipLoad) { 2527 continue; 2528 } 2529 else if (obj_type == HDF5Constants.H5O_TYPE_DATASET) { 2530 long did = -1; 2531 long tid = -1; 2532 int tclass = -1; 2533 try { 2534 did = H5.H5Dopen(fid, fullPath + obj_name, HDF5Constants.H5P_DEFAULT); 2535 if (did >= 0) { 2536 tid = H5.H5Dget_type(did); 2537 2538 tclass = H5.H5Tget_class(tid); 2539 if ((tclass == HDF5Constants.H5T_ARRAY) || (tclass == HDF5Constants.H5T_VLEN)) { 2540 // for ARRAY, the type is determined by the base type 2541 long btid = H5.H5Tget_super(tid); 2542 2543 tclass = H5.H5Tget_class(btid); 2544 2545 try { 2546 H5.H5Tclose(btid); 2547 } 2548 catch (Exception ex) { 2549 log.debug("depth_first({})[{}] dataset {} H5Tclose(btid {}) failure: ", 2550 parentObject, i, obj_name, btid, ex); 2551 } 2552 } 2553 } 2554 else { 2555 log.debug("depth_first({})[{}] {} dataset open failure", parentObject, i, obj_name); 2556 } 2557 } 2558 catch (Exception ex) { 2559 log.debug("depth_first({})[{}] {} dataset access failure: ", parentObject, i, obj_name, 2560 ex); 2561 } 2562 finally { 2563 try { 2564 H5.H5Tclose(tid); 2565 } 2566 catch (Exception ex) { 2567 log.debug("depth_first({})[{}] daatset {} H5Tclose(tid {}) failure: ", parentObject, 2568 i, obj_name, tid, ex); 2569 } 2570 try { 2571 H5.H5Dclose(did); 2572 } 2573 catch (Exception ex) { 2574 log.debug("depth_first({})[{}] dataset {} H5Dclose(did {}) failure: ", parentObject, 2575 i, obj_name, did, ex); 2576 } 2577 } 2578 Dataset d = null; 2579 if (tclass == HDF5Constants.H5T_COMPOUND) { 2580 // create a new compound dataset 2581 d = new H5CompoundDS(this, obj_name, fullPath); 2582 } 2583 else { 2584 // create a new scalar dataset 2585 d = new H5ScalarDS(this, obj_name, fullPath); 2586 } 2587 oid = d.getOID(); 2588 2589 pgroup.addToMemberList(d); 2590 } 2591 else if (obj_type == HDF5Constants.H5O_TYPE_NAMED_DATATYPE) { 2592 Datatype t = new H5Datatype(parentObject.getFileFormat(), obj_name, fullPath); 2593 log.trace("depth_first({}): H5O_TYPE_NAMED_DATATYPE name={}", parentObject, t.getFullName()); 2594 oid = t.getOID(); 2595 2596 pgroup.addToMemberList(t); 2597 } 2598 else if (obj_type == HDF5Constants.H5O_TYPE_UNKNOWN) { 2599 H5Link link = new H5Link(this, obj_name, fullPath); 2600 oid = link.getOID(); 2601 2602 pgroup.addToMemberList(link); 2603 continue; // do the next one, if the object is not identified. 2604 } 2605 } // ( i = 0; i < nelems; i++) 2606 2607 pgroup.close(gid); 2608 2609 log.debug("depth_first({}): nTotal={}", parentObject, nTotal); 2610 return nTotal; 2611 } // private depth_first() 2612 2613 /** 2614 * Returns a list of all the members of this H5File in a 2615 * breadth-first ordering that are rooted at the specified 2616 * object. 2617 */ 2618 private static List<HObject> getMembersBreadthFirst(HObject obj) 2619 { 2620 List<HObject> allMembers = new Vector<>(); 2621 Queue<HObject> queue = new LinkedList<>(); 2622 HObject currentObject = obj; 2623 2624 queue.add(currentObject); 2625 2626 while (!queue.isEmpty()) { 2627 currentObject = queue.remove(); 2628 allMembers.add(currentObject); 2629 2630 if (currentObject instanceof Group) { 2631 queue.addAll(((Group)currentObject).getMemberList()); 2632 } 2633 } 2634 2635 return allMembers; 2636 } 2637 2638 private HObject copyDataset(Dataset srcDataset, H5Group pgroup, String dstName) throws Exception 2639 { 2640 Dataset dataset = null; 2641 long srcdid = -1; 2642 long dstdid = -1; 2643 long ocp_plist_id = -1; 2644 String dname = null; 2645 String path = null; 2646 2647 if (pgroup.isRoot()) 2648 path = HObject.SEPARATOR; 2649 else 2650 path = pgroup.getPath() + pgroup.getName() + HObject.SEPARATOR; 2651 2652 if ((dstName == null) || dstName.equals(HObject.SEPARATOR) || (dstName.length() < 1)) 2653 dstName = srcDataset.getName(); 2654 dname = path + dstName; 2655 2656 if (((H5Datatype)srcDataset.getDatatype()).isStdRef()) { 2657 log.debug("copyDataset(): isStdRef"); 2658 } 2659 try { 2660 srcdid = srcDataset.open(); 2661 dstdid = pgroup.open(); 2662 2663 try { 2664 ocp_plist_id = H5.H5Pcreate(HDF5Constants.H5P_OBJECT_COPY); 2665 H5.H5Pset_copy_object(ocp_plist_id, HDF5Constants.H5O_COPY_EXPAND_REFERENCE_FLAG); 2666 H5.H5Ocopy(srcdid, ".", dstdid, dstName, ocp_plist_id, HDF5Constants.H5P_DEFAULT); 2667 } 2668 catch (Exception ex) { 2669 log.debug("copyDataset(): {} failure: ", dname, ex); 2670 } 2671 finally { 2672 try { 2673 H5.H5Pclose(ocp_plist_id); 2674 } 2675 catch (Exception ex) { 2676 log.debug("copyDataset(): {} H5Pclose(ocp_plist_id {}) failure: ", dname, ocp_plist_id, 2677 ex); 2678 } 2679 } 2680 2681 if (srcDataset instanceof H5ScalarDS) 2682 dataset = new H5ScalarDS(pgroup.getFileFormat(), dstName, path); 2683 else 2684 dataset = new H5CompoundDS(pgroup.getFileFormat(), dstName, path); 2685 2686 pgroup.addToMemberList(dataset); 2687 } 2688 finally { 2689 try { 2690 srcDataset.close(srcdid); 2691 } 2692 catch (Exception ex) { 2693 log.debug("copyDataset(): {} srcDataset.close(srcdid {}) failure: ", dname, srcdid, ex); 2694 } 2695 try { 2696 pgroup.close(dstdid); 2697 } 2698 catch (Exception ex) { 2699 log.debug("copyDataset(): {} pgroup.close(dstdid {}) failure: ", dname, dstdid, ex); 2700 } 2701 } 2702 2703 return dataset; 2704 } 2705 2706 /** 2707 * Constructs a dataset for specified dataset identifier. 2708 * 2709 * @param did 2710 * the dataset identifier 2711 * @param name 2712 * the name of the dataset 2713 * @param path 2714 * the path of the dataset 2715 * 2716 * @return the dataset if successful; otherwise return null. 2717 * 2718 * @throws HDF5Exception 2719 * If there is an error at the HDF5 library level. 2720 */ 2721 private Dataset getDataset(long did, String name, String path) throws HDF5Exception 2722 { 2723 Dataset dataset = null; 2724 if (did >= 0) { 2725 long tid = -1; 2726 int tclass = -1; 2727 try { 2728 tid = H5.H5Dget_type(did); 2729 tclass = H5.H5Tget_class(tid); 2730 if (tclass == HDF5Constants.H5T_ARRAY) { 2731 // for ARRAY, the type is determined by the base type 2732 long btid = H5.H5Tget_super(tid); 2733 tclass = H5.H5Tget_class(btid); 2734 try { 2735 H5.H5Tclose(btid); 2736 } 2737 catch (Exception ex) { 2738 log.debug("getDataset(): {} H5Tclose(btid {}) failure: ", name, btid, ex); 2739 } 2740 } 2741 } 2742 finally { 2743 try { 2744 H5.H5Tclose(tid); 2745 } 2746 catch (Exception ex) { 2747 log.debug("getDataset(): {} H5Tclose(tid {}) failure: ", name, tid, ex); 2748 } 2749 } 2750 2751 if (tclass == HDF5Constants.H5T_COMPOUND) 2752 dataset = new H5CompoundDS(this, name, path); 2753 else 2754 dataset = new H5ScalarDS(this, name, path); 2755 } 2756 else { 2757 log.debug("getDataset(): id failure"); 2758 } 2759 2760 return dataset; 2761 } 2762 2763 /** 2764 * Copies a named datatype to another location. 2765 * 2766 * @param srcType 2767 * the source datatype 2768 * @param pgroup 2769 * the group which the new datatype is copied to 2770 * @param dstName 2771 * the name of the new dataype 2772 * 2773 * @throws Exception 2774 * If there is a failure. 2775 */ 2776 private HObject copyDatatype(Datatype srcType, H5Group pgroup, String dstName) throws Exception 2777 { 2778 Datatype datatype = null; 2779 long tid_src = -1; 2780 long gid_dst = -1; 2781 String path = null; 2782 2783 if (pgroup.isRoot()) 2784 path = HObject.SEPARATOR; 2785 else 2786 path = pgroup.getPath() + pgroup.getName() + HObject.SEPARATOR; 2787 2788 if ((dstName == null) || dstName.equals(HObject.SEPARATOR) || (dstName.length() < 1)) 2789 dstName = srcType.getName(); 2790 2791 try { 2792 tid_src = srcType.open(); 2793 gid_dst = pgroup.open(); 2794 2795 try { 2796 H5.H5Ocopy(tid_src, ".", gid_dst, dstName, HDF5Constants.H5P_DEFAULT, 2797 HDF5Constants.H5P_DEFAULT); 2798 } 2799 catch (Exception ex) { 2800 log.debug("copyDatatype(): {} H5Ocopy(tid_src {}) failure: ", dstName, tid_src, ex); 2801 } 2802 int nativeClass = H5.H5Tget_class(tid_src); 2803 if (nativeClass == HDF5Constants.H5T_REFERENCE) 2804 datatype = new H5ReferenceType(pgroup.getFileFormat(), dstName, path); 2805 else 2806 datatype = new H5Datatype(pgroup.getFileFormat(), dstName, path); 2807 2808 pgroup.addToMemberList(datatype); 2809 } 2810 finally { 2811 try { 2812 srcType.close(tid_src); 2813 } 2814 catch (Exception ex) { 2815 log.debug("copyDatatype(): {} srcType.close(tid_src {}) failure: ", dstName, tid_src, ex); 2816 } 2817 try { 2818 pgroup.close(gid_dst); 2819 } 2820 catch (Exception ex) { 2821 log.debug("copyDatatype(): {} pgroup.close(gid_dst {}) failure: ", dstName, gid_dst, ex); 2822 } 2823 } 2824 2825 return datatype; 2826 } 2827 2828 /** 2829 * Copies a group and its members to a new location. 2830 * 2831 * @param srcGroup 2832 * the source group 2833 * @param dstGroup 2834 * the location where the new group is located 2835 * @param dstName 2836 * the name of the new group 2837 * 2838 * @throws Exception 2839 * If there is a failure. 2840 */ 2841 private HObject copyGroup(H5Group srcGroup, H5Group dstGroup, String dstName) throws Exception 2842 { 2843 H5Group group = null; 2844 long srcgid = -1, dstgid = -1; 2845 String path = null; 2846 2847 if (dstGroup.isRoot()) 2848 path = HObject.SEPARATOR; 2849 else 2850 path = dstGroup.getPath() + dstGroup.getName() + HObject.SEPARATOR; 2851 2852 if ((dstName == null) || dstName.equals(HObject.SEPARATOR) || (dstName.length() < 1)) 2853 dstName = srcGroup.getName(); 2854 2855 try { 2856 srcgid = srcGroup.open(); 2857 dstgid = dstGroup.open(); 2858 try { 2859 H5.H5Ocopy(srcgid, ".", dstgid, dstName, HDF5Constants.H5P_DEFAULT, 2860 HDF5Constants.H5P_DEFAULT); 2861 } 2862 catch (Exception ex) { 2863 log.debug("copyGroup(): {} H5Ocopy(srcgid {}) failure: ", dstName, srcgid, ex); 2864 } 2865 2866 group = new H5Group(dstGroup.getFileFormat(), dstName, path, dstGroup); 2867 depth_first(group, Integer.MIN_VALUE); // reload all 2868 dstGroup.addToMemberList(group); 2869 } 2870 2871 finally { 2872 try { 2873 srcGroup.close(srcgid); 2874 } 2875 catch (Exception ex) { 2876 log.debug("copyGroup(): {} srcGroup.close(srcgid {}) failure: ", dstName, srcgid, ex); 2877 } 2878 try { 2879 dstGroup.close(dstgid); 2880 } 2881 catch (Exception ex) { 2882 log.debug("copyGroup(): {} pgroup.close(dstgid {}) failure: ", dstName, dstgid, ex); 2883 } 2884 } 2885 2886 return group; 2887 } 2888 2889 /** 2890 * Constructs a group for specified group identifier and retrieves members. 2891 * 2892 * @param gid 2893 * The group identifier. 2894 * @param name 2895 * The group name. 2896 * @param pGroup 2897 * The parent group, or null for the root group. 2898 * 2899 * @return The group if successful; otherwise returns false. 2900 * 2901 * @throws HDF5Exception 2902 * If there is an error at the HDF5 library level. 2903 */ 2904 private H5Group getGroup(long gid, String name, Group pGroup) throws HDF5Exception 2905 { 2906 String parentPath = null; 2907 String thisFullName = null; 2908 String memberFullName = null; 2909 2910 if (pGroup == null) { 2911 thisFullName = name = "/"; 2912 } 2913 else { 2914 parentPath = pGroup.getFullName(); 2915 if ((parentPath == null) || parentPath.equals("/")) 2916 thisFullName = "/" + name; 2917 else 2918 thisFullName = parentPath + "/" + name; 2919 } 2920 2921 // get rid of any extra "/" 2922 if (parentPath != null) 2923 parentPath = parentPath.replaceAll("//", "/"); 2924 if (thisFullName != null) 2925 thisFullName = thisFullName.replaceAll("//", "/"); 2926 2927 log.trace("getGroup(): fullName={}", thisFullName); 2928 2929 H5Group group = new H5Group(this, name, parentPath, pGroup); 2930 2931 H5G_info_t group_info = null; 2932 H5O_info_t obj_info = null; 2933 long objid = -1; 2934 String link_name = null; 2935 try { 2936 group_info = H5.H5Gget_info(gid); 2937 } 2938 catch (Exception ex) { 2939 log.debug("getGroup(): {} H5Gget_info(gid {}) failure: ", name, gid, ex); 2940 } 2941 try { 2942 objid = H5.H5Oopen(gid, thisFullName, HDF5Constants.H5P_DEFAULT); 2943 } 2944 catch (Exception ex) { 2945 log.debug("getGroup(): {} H5Oopen(gid {}) failure: ", name, gid, ex); 2946 } 2947 2948 // retrieve only the immediate members of the group, do not follow 2949 // subgroups 2950 for (int i = 0; i < group_info.nlinks; i++) { 2951 try { 2952 link_name = H5.H5Lget_name_by_idx(gid, thisFullName, indexType, indexOrder, i, 2953 HDF5Constants.H5P_DEFAULT); 2954 obj_info = H5.H5Oget_info_by_idx(objid, thisFullName, indexType, indexOrder, i, 2955 HDF5Constants.H5P_DEFAULT); 2956 } 2957 catch (HDF5Exception ex) { 2958 log.debug("getGroup()[{}]: {} name,info failure: ", i, name, ex); 2959 // do not stop if accessing one member fails 2960 continue; 2961 } 2962 // create a new group 2963 if (obj_info.type == HDF5Constants.H5O_TYPE_GROUP) { 2964 H5Group g = new H5Group(this, link_name, thisFullName, group); 2965 group.addToMemberList(g); 2966 } 2967 else if (obj_info.type == HDF5Constants.H5O_TYPE_DATASET) { 2968 long did = -1; 2969 Dataset d = null; 2970 2971 if ((thisFullName == null) || thisFullName.equals("/")) 2972 memberFullName = "/" + link_name; 2973 else 2974 memberFullName = thisFullName + "/" + link_name; 2975 2976 try { 2977 did = H5.H5Dopen(fid, memberFullName, HDF5Constants.H5P_DEFAULT); 2978 d = getDataset(did, link_name, thisFullName); 2979 } 2980 finally { 2981 try { 2982 H5.H5Dclose(did); 2983 } 2984 catch (Exception ex) { 2985 log.debug("getGroup()[{}]: {} H5Dclose(did {}) failure: ", i, name, did, ex); 2986 } 2987 } 2988 group.addToMemberList(d); 2989 } 2990 else if (obj_info.type == HDF5Constants.H5O_TYPE_NAMED_DATATYPE) { 2991 Datatype t = new H5Datatype(group.getFileFormat(), link_name, thisFullName); 2992 group.addToMemberList(t); 2993 } 2994 } // End of for loop. 2995 try { 2996 if (objid >= 0) 2997 H5.H5Oclose(objid); 2998 } 2999 catch (Exception ex) { 3000 log.debug("getGroup(): {} H5Oclose(oid {}) failure: ", name, objid, ex); 3001 } 3002 3003 return group; 3004 } 3005 3006 /** 3007 * Retrieves the name of the target object that is being linked to. 3008 * 3009 * @param obj 3010 * The current link object. 3011 * 3012 * @return The name of the target object. 3013 * 3014 * @throws Exception 3015 * If there is an error at the HDF5 library level. 3016 */ 3017 public static String getLinkTargetName(HObject obj) throws Exception 3018 { 3019 String[] link_value = {null, null}; 3020 String targetObjName = null; 3021 3022 if (obj == null) { 3023 log.debug("getLinkTargetName(): object is null"); 3024 return null; 3025 } 3026 3027 if (obj.getFullName().equals("/")) { 3028 log.debug("getLinkTargetName(): object is root group, links not allowed"); 3029 return null; 3030 } 3031 3032 H5L_info_t link_info = null; 3033 if (obj.getFID() < 0) 3034 log.trace("getLinkTargetName(): file id for:{} is invalid", obj.getFullName()); 3035 else { 3036 try { 3037 link_info = H5.H5Lget_info(obj.getFID(), obj.getFullName(), HDF5Constants.H5P_DEFAULT); 3038 } 3039 catch (Exception err) { 3040 log.debug("getLinkTargetName(): H5Lget_info {} failure: ", obj.getFullName(), err); 3041 } 3042 } 3043 if (link_info != null) { 3044 if ((link_info.type == HDF5Constants.H5L_TYPE_SOFT) || 3045 (link_info.type == HDF5Constants.H5L_TYPE_EXTERNAL)) { 3046 try { 3047 H5.H5Lget_value(obj.getFID(), obj.getFullName(), link_value, HDF5Constants.H5P_DEFAULT); 3048 } 3049 catch (Exception ex) { 3050 log.debug("getLinkTargetName(): H5Lget_value {} failure: ", obj.getFullName(), ex); 3051 } 3052 if (link_info.type == HDF5Constants.H5L_TYPE_SOFT) 3053 targetObjName = link_value[0]; 3054 else if (link_info.type == HDF5Constants.H5L_TYPE_EXTERNAL) 3055 targetObjName = link_value[1] + FileFormat.FILE_OBJ_SEP + link_value[0]; 3056 } 3057 } 3058 3059 return targetObjName; 3060 } 3061 3062 /** 3063 * Export dataset. 3064 * 3065 * @param file_export_name 3066 * The file name to export data into. 3067 * @param object 3068 * The id of the HDF5 dataset. 3069 * @param binary_order 3070 * The data byte order 3071 * 3072 * @throws Exception 3073 * If there is a failure. 3074 */ 3075 @Override 3076 public void exportDataset(String file_export_name, Dataset object, int binary_order) throws Exception 3077 { 3078 long did = object.open(); 3079 H5.H5export_dataset(file_export_name, did, object.getFullName(), binary_order); 3080 object.close(did); 3081 } 3082 3083 /** 3084 * Renames an attribute. 3085 * 3086 * @param obj 3087 * The object whose attribute is to be renamed. 3088 * @param oldAttrName 3089 * The current name of the attribute. 3090 * @param newAttrName 3091 * The new name of the attribute. 3092 * 3093 * @throws Exception 3094 * If there is an error at the HDF5 library level. 3095 */ 3096 @Override 3097 public void renameAttribute(HObject obj, String oldAttrName, String newAttrName) throws Exception 3098 { 3099 log.trace("renameAttribute(): rename {} to {}", oldAttrName, newAttrName); 3100 H5.H5Arename_by_name(obj.getFID(), obj.getFullName(), oldAttrName, newAttrName, 3101 HDF5Constants.H5P_DEFAULT); 3102 } 3103 3104 /** 3105 * Rename the given object 3106 * 3107 * @param obj 3108 * the object to be renamed. 3109 * @param newName 3110 * the new name of the object. 3111 * 3112 * @throws Exception 3113 * If there is a failure. 3114 */ 3115 public static void renameObject(HObject obj, String newName) throws Exception 3116 { 3117 renameObject(obj, obj.getPath(), newName); 3118 } 3119 3120 /** 3121 * Rename the given object 3122 * 3123 * @param obj 3124 * the object to be renamed. 3125 * @param newPath 3126 * the new path of the object. 3127 * @param newName 3128 * the new name of the object. 3129 * 3130 * @throws Exception 3131 * If there is a failure. 3132 */ 3133 public static void renameObject(HObject obj, String newPath, String newName) throws Exception 3134 { 3135 String currentFullPath = obj.getFullName(); 3136 String newFullPath = obj.createFullname(newPath, newName); 3137 3138 log.trace("renameObject(): currentFullPath={} newFullPath={}", currentFullPath, newFullPath); 3139 if ((currentFullPath != null) && (newFullPath != null)) { 3140 currentFullPath = currentFullPath.replaceAll("//", "/"); 3141 newFullPath = newFullPath.replaceAll("//", "/"); 3142 3143 if (currentFullPath.equals("/") && obj instanceof Group) 3144 throw new HDF5Exception("Can't rename the root group."); 3145 3146 if (currentFullPath.equals(newFullPath)) 3147 throw new HDF5Exception("The new name is the same as the current name."); 3148 3149 // Call the library to move things in the file if object exists 3150 if (obj.getName() != null) 3151 H5.H5Lmove(obj.getFID(), currentFullPath, obj.getFID(), newFullPath, 3152 HDF5Constants.H5P_DEFAULT, HDF5Constants.H5P_DEFAULT); 3153 } 3154 } 3155 3156 /** 3157 * Get the value of the index type value. 3158 * 3159 * @return the int value of the index type value. 3160 * 3161 * @param strtype The name of the index type. 3162 */ 3163 public static int getIndexTypeValue(String strtype) 3164 { 3165 if (strtype.compareTo("H5_INDEX_NAME") == 0) 3166 return HDF5Constants.H5_INDEX_NAME; 3167 if (strtype.compareTo("H5_INDEX_CRT_ORDER") == 0) 3168 return HDF5Constants.H5_INDEX_CRT_ORDER; 3169 if (strtype.compareTo("H5_INDEX_N") == 0) 3170 return HDF5Constants.H5_INDEX_N; 3171 return HDF5Constants.H5_INDEX_UNKNOWN; 3172 } 3173 3174 /** 3175 * Get the value of the index order. 3176 * 3177 * @return the int value of the index order. 3178 * 3179 * @param strorder The name of the index order. 3180 */ 3181 public static int getIndexOrderValue(String strorder) 3182 { 3183 if (strorder.compareTo("H5_ITER_INC") == 0) 3184 return HDF5Constants.H5_ITER_INC; 3185 if (strorder.compareTo("H5_ITER_DEC") == 0) 3186 return HDF5Constants.H5_ITER_DEC; 3187 if (strorder.compareTo("H5_ITER_NATIVE") == 0) 3188 return HDF5Constants.H5_ITER_NATIVE; 3189 if (strorder.compareTo("H5_ITER_N") == 0) 3190 return HDF5Constants.H5_ITER_N; 3191 return HDF5Constants.H5_ITER_UNKNOWN; 3192 } 3193 3194 @Override 3195 /** 3196 * Get the value of the index type. 3197 * 3198 * @return the int value of the index type. 3199 * 3200 * @param strtype The name of the index type. 3201 */ 3202 public int getIndexType(String strtype) 3203 { 3204 if (strtype != null) { 3205 if (strtype.compareTo("H5_INDEX_NAME") == 0) 3206 return HDF5Constants.H5_INDEX_NAME; 3207 if (strtype.compareTo("H5_INDEX_CRT_ORDER") == 0) 3208 return HDF5Constants.H5_INDEX_CRT_ORDER; 3209 return HDF5Constants.H5_INDEX_UNKNOWN; 3210 } 3211 return getIndexType(); 3212 } 3213 3214 /** 3215 * Get the current value of the index type. 3216 * 3217 * @return the current value of the index type. 3218 */ 3219 public int getIndexType() { return indexType; } 3220 3221 @Override 3222 /** 3223 * set the int value of the index type. 3224 * 3225 * @param indexType 3226 * The value of the index type. 3227 */ 3228 public void setIndexType(int indexType) 3229 { 3230 this.indexType = indexType; 3231 } 3232 3233 @Override 3234 /** 3235 * Get the value of the index order value. 3236 * 3237 * @return the int value of the index order value. 3238 * 3239 * @param strorder The name of the index order. 3240 */ 3241 public int getIndexOrder(String strorder) 3242 { 3243 if (strorder != null) { 3244 if (strorder.compareTo("H5_ITER_INC") == 0) 3245 return HDF5Constants.H5_ITER_INC; 3246 if (strorder.compareTo("H5_ITER_DEC") == 0) 3247 return HDF5Constants.H5_ITER_DEC; 3248 if (strorder.compareTo("H5_ITER_NATIVE") == 0) 3249 return HDF5Constants.H5_ITER_NATIVE; 3250 if (strorder.compareTo("H5_ITER_N") == 0) 3251 return HDF5Constants.H5_ITER_N; 3252 return HDF5Constants.H5_ITER_UNKNOWN; 3253 } 3254 return getIndexOrder(); 3255 } 3256 3257 /** 3258 * Get the current value of the index order. 3259 * 3260 * @return the current value of the index order. 3261 */ 3262 public int getIndexOrder() { return indexOrder; } 3263 3264 @Override 3265 /** 3266 * set the current value of the index order. 3267 * 3268 * @param indexOrder 3269 * The index order. 3270 */ 3271 public void setIndexOrder(int indexOrder) 3272 { 3273 this.indexOrder = indexOrder; 3274 } 3275}