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