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