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