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