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.lang.reflect.Array; 018import java.math.BigDecimal; 019import java.math.BigInteger; 020import java.text.DecimalFormat; 021import java.util.ArrayList; 022import java.util.Arrays; 023import java.util.Iterator; 024import java.util.List; 025import java.util.Vector; 026 027import org.slf4j.Logger; 028import org.slf4j.LoggerFactory; 029 030import hdf.hdf5lib.H5; 031import hdf.hdf5lib.HDF5Constants; 032import hdf.hdf5lib.HDFArray; 033import hdf.hdf5lib.HDFNativeData; 034import hdf.hdf5lib.exceptions.HDF5DataFiltersException; 035import hdf.hdf5lib.exceptions.HDF5Exception; 036import hdf.hdf5lib.exceptions.HDF5LibraryException; 037import hdf.hdf5lib.structs.H5O_info_t; 038import hdf.hdf5lib.structs.H5O_token_t; 039 040import hdf.object.Attribute; 041import hdf.object.CompoundDS; 042import hdf.object.Dataset; 043import hdf.object.Datatype; 044import hdf.object.FileFormat; 045import hdf.object.Group; 046import hdf.object.HObject; 047import hdf.object.MetaDataContainer; 048import hdf.object.Utils; 049 050import hdf.object.h5.H5Datatype; 051import hdf.object.h5.H5MetaDataContainer; 052import hdf.object.h5.H5ReferenceType; 053 054/** 055 * The H5CompoundDS class defines an HDF5 dataset of compound datatypes. 056 * 057 * An HDF5 dataset is an object composed of a collection of data elements, or raw data, and metadata that stores a 058 * description of the data elements, data layout, and all other information necessary to write, read, and interpret the 059 * stored data. 060 * 061 * A HDF5 compound datatype is similar to a struct in C or a common block in Fortran: it is a collection of one or more 062 * atomic types or small arrays of such types. Each member of a compound type has a name which is unique within that 063 * type, and a byte offset that determines the first byte (smallest byte address) of that member in a compound datum. 064 * 065 * For more information on HDF5 datasets and datatypes, read 066 * <a href="https://hdfgroup.github.io/hdf5/_h5_d__u_g.html#sec_dataset">HDF5 Datasets in HDF5 User Guide</a> 067 * <a href="https://hdfgroup.github.io/hdf5/_h5_t__u_g.html#sec_datatype">HDF5 Datatypes in HDF5 User Guide</a> 068 * 069 * There are two basic types of compound datasets: simple compound data and nested compound data. Members of a simple 070 * compound dataset have atomic datatypes. Members of a nested compound dataset are compound or array of compound data. 071 * 072 * Since Java does not understand C structures, we cannot directly read/write compound data values as in the following C 073 * example. 074 * 075 * <pre> 076 * typedef struct s1_t { 077 * int a; 078 * float b; 079 * double c; 080 * } s1_t; 081 * s1_t s1[LENGTH]; 082 * ... 083 * H5Dwrite(..., s1); 084 * H5Dread(..., s1); 085 * </pre> 086 * 087 * Values of compound data fields are stored in java.util.Vector object. We read and write compound data by fields 088 * instead of compound structure. As for the example above, the java.util.Vector object has three elements: int[LENGTH], 089 * float[LENGTH] and double[LENGTH]. Since Java understands the primitive datatypes of int, float and double, we will be 090 * able to read/write the compound data by field. 091 * 092 * @version 1.1 9/4/2007 093 * @author Peter X. Cao 094 */ 095public class H5CompoundDS extends CompoundDS implements MetaDataContainer 096{ 097 private static final long serialVersionUID = -5968625125574032736L; 098 099 private static final Logger log = LoggerFactory.getLogger(H5CompoundDS.class); 100 101 /** 102 * The metadata object for this data object. Members of the metadata are instances of Attribute. 103 */ 104 private H5MetaDataContainer objMetadata; 105 106 /** the object properties */ 107 private H5O_info_t objInfo; 108 109 /** flag to indicate if the dataset is an external dataset */ 110 private boolean isExternal = false; 111 112 /** flag to indicate if the dataset is a virtual dataset */ 113 private boolean isVirtual = false; 114 /** the list of virtual names */ 115 private List<String> virtualNameList; 116 117 /** 118 * Constructs an instance of a HDF5 compound dataset with given file, dataset name and path. 119 * 120 * The dataset object represents an existing dataset in the file. For example, new 121 * H5CompoundDS(file, "dset1", "/g0/") constructs a dataset object that corresponds to the 122 * dataset,"dset1", at group "/g0/". 123 * 124 * This object is usually constructed at FileFormat.open(), which loads the file structure and 125 * object information into memory. It is rarely used elsewhere. 126 * 127 * @param theFile 128 * the file that contains the data object. 129 * @param theName 130 * the name of the data object, e.g. "dset". 131 * @param thePath 132 * the full path of the data object, e.g. "/arrays/". 133 */ 134 public H5CompoundDS(FileFormat theFile, String theName, String thePath) { 135 this(theFile, theName, thePath, null); 136 } 137 138 /** 139 * @deprecated Not for public use in the future.<br> 140 * Using {@link #H5CompoundDS(FileFormat, String, String)} 141 * 142 * @param theFile 143 * the file that contains the data object. 144 * @param theName 145 * the name of the data object, e.g. "dset". 146 * @param thePath 147 * the full path of the data object, e.g. "/arrays/". 148 * @param oid 149 * the oid of the data object. 150 */ 151 @Deprecated 152 public H5CompoundDS(FileFormat theFile, String theName, String thePath, long[] oid) { 153 super(theFile, theName, thePath, oid); 154 objMetadata = new H5MetaDataContainer(theFile, theName, thePath, this); 155 156 if (theFile != null) { 157 if (oid == null) { 158 // retrieve the object ID 159 byte[] refBuf = null; 160 try { 161 refBuf = H5.H5Rcreate_object(theFile.getFID(), this.getFullName(), HDF5Constants.H5P_DEFAULT); 162 this.oid = HDFNativeData.byteToLong(refBuf); 163 log.trace("constructor REF {} to OID {}", refBuf, this.oid); 164 } 165 catch (Exception ex) { 166 log.debug("constructor ID {} for {} failed H5Rcreate_object", theFile.getFID(), this.getFullName()); 167 } 168 finally { 169 if (refBuf != null) 170 H5.H5Rdestroy(refBuf); 171 } 172 } 173 log.trace("constructor OID {}", this.oid); 174 try { 175 objInfo = H5.H5Oget_info_by_name(theFile.getFID(), this.getFullName(), HDF5Constants.H5O_INFO_BASIC, HDF5Constants.H5P_DEFAULT); 176 } 177 catch (Exception ex) { 178 objInfo = new H5O_info_t(-1L, null, 0, 0, 0L, 0L, 0L, 0L, 0L); 179 } 180 } 181 else { 182 this.oid = null; 183 objInfo = new H5O_info_t(-1L, null, 0, 0, 0L, 0L, 0L, 0L, 0L); 184 } 185 } 186 187 /* 188 * (non-Javadoc) 189 * 190 * @see hdf.object.HObject#open() 191 */ 192 @Override 193 public long open() { 194 long did = HDF5Constants.H5I_INVALID_HID; 195 196 if (getFID() < 0) 197 log.trace("open(): file id for:{} is invalid", getPath() + getName()); 198 else { 199 try { 200 did = H5.H5Dopen(getFID(), getPath() + getName(), HDF5Constants.H5P_DEFAULT); 201 log.trace("open(): did={}", did); 202 } 203 catch (HDF5Exception ex) { 204 log.debug("open(): Failed to open dataset {}", getPath() + getName(), ex); 205 did = HDF5Constants.H5I_INVALID_HID; 206 } 207 } 208 209 return did; 210 } 211 212 /* 213 * (non-Javadoc) 214 * 215 * @see hdf.object.HObject#close(int) 216 */ 217 @Override 218 public void close(long did) { 219 if (did >= 0) { 220 try { 221 H5.H5Fflush(did, HDF5Constants.H5F_SCOPE_LOCAL); 222 } 223 catch (Exception ex) { 224 log.debug("close(): H5Fflush(did {}) failure: ", did, ex); 225 } 226 try { 227 H5.H5Dclose(did); 228 } 229 catch (HDF5Exception ex) { 230 log.debug("close(): H5Dclose(did {}) failure: ", did, ex); 231 } 232 } 233 } 234 235 /** 236 * Retrieves datatype and dataspace information from file and sets the dataset 237 * in memory. 238 * 239 * The init() is designed to support lazy operation in a dataset object. When a 240 * data object is retrieved from file, the datatype, dataspace and raw data are 241 * not loaded into memory. When it is asked to read the raw data from file, 242 * init() is first called to get the datatype and dataspace information, then 243 * load the raw data from file. 244 * 245 * init() is also used to reset the selection of a dataset (start, stride and 246 * count) to the default, which is the entire dataset for 1D or 2D datasets. In 247 * the following example, init() at step 1) retrieves datatype and dataspace 248 * information from file. getData() at step 3) reads only one data point. init() 249 * at step 4) resets the selection to the whole dataset. getData() at step 4) 250 * reads the values of whole dataset into memory. 251 * 252 * <pre> 253 * dset = (Dataset) file.get(NAME_DATASET); 254 * 255 * // 1) get datatype and dataspace information from file 256 * dset.init(); 257 * rank = dset.getRank(); // rank = 2, a 2D dataset 258 * count = dset.getSelectedDims(); 259 * start = dset.getStartDims(); 260 * dims = dset.getDims(); 261 * 262 * // 2) select only one data point 263 * for (int i = 0; i < rank; i++) { 264 * start[0] = 0; 265 * count[i] = 1; 266 * } 267 * 268 * // 3) read one data point 269 * data = dset.getData(); 270 * 271 * // 4) reset selection to the whole dataset 272 * dset.init(); 273 * 274 * // 5) clean the memory data buffer 275 * dset.clearData(); 276 * 277 * // 6) Read the whole dataset 278 * data = dset.getData(); 279 * </pre> 280 */ 281 @Override 282 public void init() { 283 if (inited) { 284 resetSelection(); 285 log.trace("init(): Dataset already initialized"); 286 return; // already called. Initialize only once 287 } 288 289 long did = HDF5Constants.H5I_INVALID_HID; 290 long tid = HDF5Constants.H5I_INVALID_HID; 291 long sid = HDF5Constants.H5I_INVALID_HID; 292 flatNameList = new Vector<>(); 293 flatTypeList = new Vector<>(); 294 295 did = open(); 296 if (did >= 0) { 297 // check if it is an external or virtual dataset 298 long pid = HDF5Constants.H5I_INVALID_HID; 299 try { 300 pid = H5.H5Dget_create_plist(did); 301 try { 302 int nfiles = H5.H5Pget_external_count(pid); 303 isExternal = (nfiles > 0); 304 int layoutType = H5.H5Pget_layout(pid); 305 if (isVirtual = (layoutType == HDF5Constants.H5D_VIRTUAL)) { 306 try { 307 long vmaps = H5.H5Pget_virtual_count(pid); 308 if (vmaps > 0) { 309 virtualNameList = new Vector<>(); 310 for (long next = 0; next < vmaps; next++) { 311 try { 312 String fname = H5.H5Pget_virtual_filename(pid, next); 313 virtualNameList.add(fname); 314 log.trace("init(): virtualNameList[{}]={}", next, fname); 315 } 316 catch (Exception err) { 317 log.trace("init(): vds[{}] continue", next); 318 } 319 } 320 } 321 } 322 catch (Exception err) { 323 log.debug("init(): vds count error: ", err); 324 } 325 } 326 log.trace("init(): pid={} nfiles={} isExternal={} isVirtual={}", pid, nfiles, isExternal, isVirtual); 327 } 328 catch (Exception ex) { 329 log.debug("init(): check if it is an external or virtual dataset: ", ex); 330 } 331 } 332 catch (Exception ex) { 333 log.debug("init(): H5Dget_create_plist() failure: ", ex); 334 } 335 finally { 336 try { 337 H5.H5Pclose(pid); 338 } 339 catch (Exception ex) { 340 log.debug("init(): H5Pclose(pid {}) failure: ", pid, ex); 341 } 342 } 343 344 try { 345 sid = H5.H5Dget_space(did); 346 rank = H5.H5Sget_simple_extent_ndims(sid); 347 space_type = H5.H5Sget_simple_extent_type(sid); 348 if (space_type == HDF5Constants.H5S_NULL) 349 isNULL = true; 350 else 351 isNULL = false; 352 tid = H5.H5Dget_type(did); 353 log.trace("init(): tid={} sid={} rank={}", tid, sid, rank); 354 355 if (rank == 0) { 356 // a scalar data point 357 isScalar = true; 358 rank = 1; 359 dims = new long[] { 1 }; 360 log.trace("init(): rank is a scalar data point"); 361 } 362 else { 363 isScalar = false; 364 dims = new long[rank]; 365 maxDims = new long[rank]; 366 H5.H5Sget_simple_extent_dims(sid, dims, maxDims); 367 log.trace("init(): rank={}, dims={}, maxDims={}", rank, dims, maxDims); 368 } 369 370 try { 371 int nativeClass = H5.H5Tget_class(tid); 372 if (nativeClass == HDF5Constants.H5T_REFERENCE) { 373 long lsize = 1; 374 if (rank > 0) { 375 log.trace("init():rank={}, dims={}", rank, dims); 376 for (int j = 0; j < dims.length; j++) { 377 lsize *= dims[j]; 378 } 379 } 380 datatype = new H5ReferenceType(getFileFormat(), lsize, tid); 381 } 382 else 383 datatype = new H5Datatype(getFileFormat(), tid); 384 385 log.trace("init(): tid={} has isText={} : isVLEN={} : isEnum={} : isUnsigned={} : isStdRef={} : isRegRef={}", tid, 386 datatype.isText(), datatype.isVLEN(), ((H5Datatype) datatype).isEnum(), datatype.isUnsigned(), 387 ((H5Datatype) datatype).isStdRef(), ((H5Datatype) datatype).isRegRef()); 388 389 H5Datatype.extractCompoundInfo((H5Datatype) datatype, "", flatNameList, flatTypeList); 390 } 391 catch (Exception ex) { 392 log.debug("init(): failed to create datatype for dataset: ", ex); 393 datatype = null; 394 } 395 396 // initialize member information 397 numberOfMembers = flatNameList.size(); 398 log.trace("init(): numberOfMembers={}", numberOfMembers); 399 400 memberNames = new String[numberOfMembers]; 401 memberTypes = new Datatype[numberOfMembers]; 402 memberOrders = new int[numberOfMembers]; 403 isMemberSelected = new boolean[numberOfMembers]; 404 memberDims = new Object[numberOfMembers]; 405 406 for (int i = 0; i < numberOfMembers; i++) { 407 isMemberSelected[i] = true; 408 memberOrders[i] = 1; 409 memberDims[i] = null; 410 411 try { 412 memberTypes[i] = flatTypeList.get(i); 413 log.trace("init()[{}]: memberTypes[{}]={}", i, i, memberTypes[i].getDescription()); 414 415 if (memberTypes[i].isArray()) { 416 long mdim[] = memberTypes[i].getArrayDims(); 417 int idim[] = new int[mdim.length]; 418 int arrayNpoints = 1; 419 420 for (int j = 0; j < idim.length; j++) { 421 idim[j] = (int) mdim[j]; 422 arrayNpoints *= idim[j]; 423 } 424 425 memberDims[i] = idim; 426 memberOrders[i] = arrayNpoints; 427 } 428 } 429 catch (Exception ex) { 430 log.debug("init()[{}]: memberTypes[{}] get failure: ", i, i, ex); 431 memberTypes[i] = null; 432 } 433 434 try { 435 memberNames[i] = flatNameList.get(i); 436 log.trace("init()[{}]: memberNames[{}]={}", i, i, memberNames[i]); 437 } 438 catch (Exception ex) { 439 log.debug("init()[{}]: memberNames[{}] get failure: ", i, i, ex); 440 memberNames[i] = "null"; 441 } 442 } // (int i=0; i<numberOfMembers; i++) 443 444 inited = true; 445 } 446 catch (HDF5Exception ex) { 447 numberOfMembers = 0; 448 memberNames = null; 449 memberTypes = null; 450 memberOrders = null; 451 log.debug("init(): ", ex); 452 } 453 finally { 454 if (datatype != null) 455 datatype.close(tid); 456 457 try { 458 H5.H5Sclose(sid); 459 } 460 catch (HDF5Exception ex2) { 461 log.debug("init(): H5Sclose(sid {}) failure: ", sid, ex2); 462 } 463 } 464 465 close(did); 466 467 startDims = new long[rank]; 468 selectedDims = new long[rank]; 469 470 resetSelection(); 471 } 472 else { 473 log.debug("init(): failed to open dataset"); 474 } 475 } 476 477 /** 478 * Get the token for this object. 479 * 480 * @return true if it has any attributes, false otherwise. 481 */ 482 public long[] getToken() { 483 H5O_token_t token = objInfo.token; 484 return HDFNativeData.byteToLong(token.data); 485 } 486 487 /** 488 * Check if the object has any attributes attached. 489 * 490 * @return true if it has any attributes, false otherwise. 491 */ 492 @Override 493 public boolean hasAttribute() { 494 objInfo.num_attrs = objMetadata.getObjectAttributeSize(); 495 496 if (objInfo.num_attrs < 0) { 497 long did = open(); 498 if (did >= 0) { 499 objInfo.num_attrs = 0; 500 501 try { 502 objInfo = H5.H5Oget_info(did); 503 } 504 catch (Exception ex) { 505 objInfo.num_attrs = 0; 506 log.debug("hasAttribute(): get object info failure: ", ex); 507 } 508 finally { 509 close(did); 510 } 511 objMetadata.setObjectAttributeSize((int) objInfo.num_attrs); 512 } 513 else { 514 log.debug("hasAttribute(): could not open dataset"); 515 } 516 } 517 518 log.trace("hasAttribute(): nAttributes={}", objInfo.num_attrs); 519 return (objInfo.num_attrs > 0); 520 } 521 522 /** 523 * Returns the datatype of the data object. 524 * 525 * @return the datatype of the data object. 526 */ 527 @Override 528 public Datatype getDatatype() { 529 if (!inited) 530 init(); 531 532 if (datatype == null) { 533 long did = HDF5Constants.H5I_INVALID_HID; 534 long tid = HDF5Constants.H5I_INVALID_HID; 535 536 did = open(); 537 if (did >= 0) { 538 try { 539 tid = H5.H5Dget_type(did); 540 int nativeClass = H5.H5Tget_class(tid); 541 if (nativeClass == HDF5Constants.H5T_REFERENCE) { 542 long lsize = 1; 543 if (rank > 0) { 544 log.trace("getDatatype(): rank={}, dims={}", rank, dims); 545 for (int j = 0; j < dims.length; j++) { 546 lsize *= dims[j]; 547 } 548 } 549 datatype = new H5ReferenceType(getFileFormat(), lsize, tid); 550 } 551 else 552 datatype = new H5Datatype(getFileFormat(), tid); 553 } 554 catch (Exception ex) { 555 log.debug("getDatatype(): ", ex); 556 } 557 finally { 558 try { 559 H5.H5Tclose(tid); 560 } 561 catch (HDF5Exception ex) { 562 log.debug("getDatatype(): H5Tclose(tid {}) failure: ", tid, ex); 563 } 564 try { 565 H5.H5Dclose(did); 566 } 567 catch (HDF5Exception ex) { 568 log.debug("getDatatype(): H5Dclose(did {}) failure: ", did, ex); 569 } 570 } 571 } 572 } 573 574 if (isExternal) { 575 String pdir = this.getFileFormat().getAbsoluteFile().getParent(); 576 577 if (pdir == null) { 578 pdir = "."; 579 } 580 System.setProperty("user.dir", pdir); 581 log.trace("getDatatype(): External dataset: user.dir={}", pdir); 582 } 583 584 return datatype; 585 } 586 587 /** 588 * Removes all of the elements from metadata list. 589 * The list should be empty after this call returns. 590 */ 591 @Override 592 public void clear() { 593 super.clear(); 594 objMetadata.clear(); 595 } 596 597 /* 598 * (non-Javadoc) 599 * 600 * @see hdf.object.Dataset#readBytes() 601 */ 602 @Override 603 public byte[] readBytes() throws HDF5Exception { 604 byte[] theData = null; 605 606 if (!isInited()) 607 init(); 608 609 long did = open(); 610 if (did >= 0) { 611 long fspace = HDF5Constants.H5I_INVALID_HID; 612 long mspace = HDF5Constants.H5I_INVALID_HID; 613 long tid = HDF5Constants.H5I_INVALID_HID; 614 615 try { 616 long[] lsize = { 1 }; 617 for (int j = 0; j < selectedDims.length; j++) 618 lsize[0] *= selectedDims[j]; 619 620 fspace = H5.H5Dget_space(did); 621 mspace = H5.H5Screate_simple(rank, selectedDims, null); 622 623 // set the rectangle selection 624 // HDF5 bug: for scalar dataset, H5Sselect_hyperslab gives core dump 625 if (rank * dims[0] > 1) 626 H5.H5Sselect_hyperslab(fspace, HDF5Constants.H5S_SELECT_SET, startDims, selectedStride, selectedDims, null); // set block to 1 627 628 tid = H5.H5Dget_type(did); 629 long size = H5.H5Tget_size(tid) * lsize[0]; 630 log.trace("readBytes(): size = {}", size); 631 632 if (size < Integer.MIN_VALUE || size > Integer.MAX_VALUE) 633 throw new Exception("Invalid int size"); 634 635 theData = new byte[(int)size]; 636 637 log.trace("readBytes(): H5Dread: did={} tid={} fspace={} mspace={}", did, tid, fspace, mspace); 638 H5.H5Dread(did, tid, mspace, fspace, HDF5Constants.H5P_DEFAULT, theData); 639 } 640 catch (Exception ex) { 641 log.debug("readBytes(): failed to read data: ", ex); 642 } 643 finally { 644 try { 645 H5.H5Sclose(fspace); 646 } 647 catch (Exception ex2) { 648 log.debug("readBytes(): H5Sclose(fspace {}) failure: ", fspace, ex2); 649 } 650 try { 651 H5.H5Sclose(mspace); 652 } 653 catch (Exception ex2) { 654 log.debug("readBytes(): H5Sclose(mspace {}) failure: ", mspace, ex2); 655 } 656 try { 657 H5.H5Tclose(tid); 658 } 659 catch (HDF5Exception ex2) { 660 log.debug("readBytes(): H5Tclose(tid {}) failure: ", tid, ex2); 661 } 662 close(did); 663 } 664 } 665 666 return theData; 667 } 668 669 /** 670 * Reads the data from file. 671 * 672 * read() reads the data from file to a memory buffer and returns the memory 673 * buffer. The dataset object does not hold the memory buffer. To store the 674 * memory buffer in the dataset object, one must call getData(). 675 * 676 * By default, the whole dataset is read into memory. Users can also select 677 * a subset to read. Subsetting is done in an implicit way. 678 * 679 * <b>How to Select a Subset</b> 680 * 681 * A selection is specified by three arrays: start, stride and count. 682 * <ol> 683 * <li>start: offset of a selection 684 * <li>stride: determines how many elements to move in each dimension 685 * <li>count: number of elements to select in each dimension 686 * </ol> 687 * getStartDims(), getStride() and getSelectedDims() returns the start, 688 * stride and count arrays respectively. Applications can make a selection 689 * by changing the values of the arrays. 690 * 691 * The following example shows how to make a subset. In the example, the 692 * dataset is a 4-dimensional array of [200][100][50][10], i.e. dims[0]=200; 693 * dims[1]=100; dims[2]=50; dims[3]=10; <br> 694 * We want to select every other data point in dims[1] and dims[2] 695 * 696 * <pre> 697 * int rank = dataset.getRank(); // number of dimensions of the dataset 698 * long[] dims = dataset.getDims(); // the dimension sizes of the dataset 699 * long[] selected = dataset.getSelectedDims(); // the selected size of the 700 * // dataset 701 * long[] start = dataset.getStartDims(); // the offset of the selection 702 * long[] stride = dataset.getStride(); // the stride of the dataset 703 * int[] selectedIndex = dataset.getSelectedIndex(); // the selected 704 * // dimensions for 705 * // display 706 * 707 * // select dim1 and dim2 as 2D data for display, and slice through dim0 708 * selectedIndex[0] = 1; 709 * selectedIndex[1] = 2; 710 * selectedIndex[1] = 0; 711 * 712 * // reset the selection arrays 713 * for (int i = 0; i < rank; i++) { 714 * start[i] = 0; 715 * selected[i] = 1; 716 * stride[i] = 1; 717 * } 718 * 719 * // set stride to 2 on dim1 and dim2 so that every other data point is 720 * // selected. 721 * stride[1] = 2; 722 * stride[2] = 2; 723 * 724 * // set the selection size of dim1 and dim2 725 * selected[1] = dims[1] / stride[1]; 726 * selected[2] = dims[1] / stride[2]; 727 * 728 * // when dataset.getData() is called, the selection above will be used 729 * // since 730 * // the dimension arrays are passed by reference. Changes of these arrays 731 * // outside the dataset object directly change the values of these array 732 * // in the dataset object. 733 * </pre> 734 * 735 * For CompoundDS, the memory data object is an java.util.List object. Each 736 * element of the list is a data array that corresponds to a compound field. 737 * 738 * For example, if compound dataset "comp" has the following nested 739 * structure, and member datatypes 740 * 741 * <pre> 742 * comp --> m01 (int) 743 * comp --> m02 (float) 744 * comp --> nest1 --> m11 (char) 745 * comp --> nest1 --> m12 (String) 746 * comp --> nest1 --> nest2 --> m21 (long) 747 * comp --> nest1 --> nest2 --> m22 (double) 748 * </pre> 749 * 750 * getData() returns a list of six arrays: {int[], float[], char[], 751 * String[], long[] and double[]}. 752 * 753 * @return the data read from file. 754 * 755 * @see #getData() 756 * @see hdf.object.DataFormat#read() 757 * 758 * @throws Exception 759 * if object can not be read 760 */ 761 @Override 762 public Object read() throws Exception { 763 Object readData = null; 764 765 if (!isInited()) 766 init(); 767 768 try { 769 readData = compoundDatasetCommonIO(H5File.IO_TYPE.READ, null); 770 } 771 catch (Exception ex) { 772 log.debug("read(): failed to read compound dataset: ", ex); 773 throw new Exception("failed to read compound dataset: " + ex.getMessage(), ex); 774 } 775 776 return readData; 777 } 778 779 /** 780 * Writes the given data buffer into this dataset in a file. 781 * 782 * The data buffer is a vector that contains the data values of compound fields. The data is written 783 * into file field by field. 784 * 785 * @param buf 786 * The vector that contains the data values of compound fields. 787 * 788 * @throws Exception 789 * If there is an error at the HDF5 library level. 790 */ 791 @Override 792 public void write(Object buf) throws Exception { 793 if (this.getFileFormat().isReadOnly()) 794 throw new Exception("cannot write to compound dataset in file opened as read-only"); 795 796 if (!isInited()) 797 init(); 798 799 try { 800 compoundDatasetCommonIO(H5File.IO_TYPE.WRITE, buf); 801 } 802 catch (Exception ex) { 803 log.debug("write(Object): failed to write compound dataset: ", ex); 804 throw new Exception("failed to write compound dataset: " + ex.getMessage(), ex); 805 } 806 } 807 808 /* 809 * Routine to convert datatypes that are read in as byte arrays to 810 * regular types. 811 */ 812 @Override 813 protected Object convertByteMember(final Datatype dtype, byte[] byteData) { 814 Object theObj = null; 815 log.debug("convertByteMember(): dtype={} byteData={}", dtype, byteData); 816 817 if (dtype.isFloat() && dtype.getDatatypeSize() == 16) 818 theObj = ((H5Datatype)dtype).byteToBigDecimal(byteData, 0); 819 else 820 theObj = super.convertByteMember(dtype, byteData); 821 822 return theObj; 823 } 824 825 private Object compoundDatasetCommonIO(H5File.IO_TYPE ioType, Object writeBuf) throws Exception { 826 H5Datatype dsDatatype = (H5Datatype) getDatatype(); 827 Object theData = null; 828 829 if (numberOfMembers <= 0) { 830 log.debug("compoundDatasetCommonIO(): Dataset contains no members"); 831 throw new Exception("dataset contains no members"); 832 } 833 834 /* 835 * I/O type-specific pre-initialization. 836 */ 837 if (ioType == H5File.IO_TYPE.WRITE) { 838 if ((writeBuf == null) || !(writeBuf instanceof List)) { 839 log.debug("compoundDatasetCommonIO(): writeBuf is null or invalid"); 840 throw new Exception("write buffer is null or invalid"); 841 } 842 843 /* 844 * Check for any unsupported datatypes and fail early before 845 * attempting to write to the dataset. 846 */ 847 if (dsDatatype.isArray() && dsDatatype.getDatatypeBase().isCompound()) { 848 log.debug("compoundDatasetCommonIO(): cannot write dataset of type ARRAY of COMPOUND"); 849 throw new HDF5Exception("Unsupported dataset of type ARRAY of COMPOUND"); 850 } 851 852 if (dsDatatype.isVLEN() && !dsDatatype.isVarStr() && dsDatatype.getDatatypeBase().isCompound()) { 853 log.debug("compoundDatasetCommonIO(): cannot write dataset of type VLEN of COMPOUND"); 854 throw new HDF5Exception("Unsupported dataset of type VLEN of COMPOUND"); 855 } 856 } 857 858 long did = open(); 859 if (did >= 0) { 860 long[] spaceIDs = { HDF5Constants.H5I_INVALID_HID, HDF5Constants.H5I_INVALID_HID }; // spaceIDs[0]=mspace, spaceIDs[1]=fspace 861 862 try { 863 /* 864 * NOTE: this call sets up a hyperslab selection in the file according to the 865 * current selection in the dataset object. 866 */ 867 long totalSelectedSpacePoints = H5Utils.getTotalSelectedSpacePoints(did, dims, startDims, 868 selectedStride, selectedDims, spaceIDs); 869 870 theData = compoundTypeIO(ioType, did, spaceIDs, (int) totalSelectedSpacePoints, dsDatatype, writeBuf, new int[]{0}); 871 } 872 finally { 873 if (HDF5Constants.H5S_ALL != spaceIDs[0]) { 874 try { 875 H5.H5Sclose(spaceIDs[0]); 876 } 877 catch (Exception ex) { 878 log.debug("compoundDatasetCommonIO(): H5Sclose(spaceIDs[0] {}) failure: ", spaceIDs[0], ex); 879 } 880 } 881 882 if (HDF5Constants.H5S_ALL != spaceIDs[1]) { 883 try { 884 H5.H5Sclose(spaceIDs[1]); 885 } 886 catch (Exception ex) { 887 log.debug("compoundDatasetCommonIO(): H5Sclose(spaceIDs[1] {}) failure: ", spaceIDs[1], ex); 888 } 889 } 890 891 close(did); 892 } 893 } 894 else 895 log.debug("compoundDatasetCommonIO(): failed to open dataset"); 896 897 return theData; 898 } 899 900 /* 901 * Private recursive routine to read/write an entire compound datatype field by 902 * field. This routine is called recursively for ARRAY of COMPOUND and VLEN of 903 * COMPOUND datatypes. 904 * 905 * NOTE: the globalMemberIndex hack is ugly, but we need to keep track of a 906 * running counter so that we can index properly into the flattened name list 907 * generated from H5Datatype.extractCompoundInfo() at dataset init time. 908 */ 909 private Object compoundTypeIO(H5File.IO_TYPE ioType, long did, long[] spaceIDs, int nSelPoints, 910 final H5Datatype cmpdType, Object writeBuf, int[] globalMemberIndex) { 911 Object theData = null; 912 913 if (cmpdType.isArray()) { 914 log.trace("compoundTypeIO(): ARRAY type"); 915 916 long[] arrayDims = cmpdType.getArrayDims(); 917 int arrSize = nSelPoints; 918 for (int i = 0; i < arrayDims.length; i++) 919 arrSize *= arrayDims[i]; 920 theData = compoundTypeIO(ioType, did, spaceIDs, arrSize, (H5Datatype) cmpdType.getDatatypeBase(), writeBuf, globalMemberIndex); 921 } 922 else if (cmpdType.isVLEN() && !cmpdType.isVarStr()) { 923 /* 924 * TODO: true variable-length support. 925 */ 926 String[] errVal = new String[nSelPoints]; 927 String errStr = "*UNSUPPORTED*"; 928 929 for (int j = 0; j < nSelPoints; j++) 930 errVal[j] = errStr; 931 932 /* 933 * Setup a fake data list. 934 */ 935 Datatype baseType = cmpdType.getDatatypeBase(); 936 while (baseType != null && !baseType.isCompound()) { 937 baseType = baseType.getDatatypeBase(); 938 } 939 940 List<Object> fakeVlenData = (List<Object>) H5Datatype.allocateArray((H5Datatype) baseType, nSelPoints); 941 fakeVlenData.add(errVal); 942 943 theData = fakeVlenData; 944 } 945 else if (cmpdType.isCompound()) { 946 List<Object> memberDataList = null; 947 List<Datatype> typeList = cmpdType.getCompoundMemberTypes(); 948 949 log.trace("compoundTypeIO(): {} {} members:", (ioType == H5File.IO_TYPE.READ) ? "read" : "write", typeList.size()); 950 951 if (ioType == H5File.IO_TYPE.READ) 952 memberDataList = (List<Object>) H5Datatype.allocateArray(cmpdType, nSelPoints); 953 954 try { 955 for (int i = 0, writeListIndex = 0; i < typeList.size(); i++) { 956 H5Datatype memberType = null; 957 String memberName = null; 958 Object memberData = null; 959 960 try { 961 memberType = (H5Datatype) typeList.get(i); 962 } 963 catch (Exception ex) { 964 log.debug("compoundTypeIO(): get member {} failure: ", i, ex); 965 globalMemberIndex[0]++; 966 continue; 967 } 968 969 /* 970 * Since the type list used here is not a flattened structure, we need to skip 971 * the member selection check for compound types, as otherwise having a single 972 * member not selected would skip the reading/writing for the entire compound 973 * type. The member selection check will be deferred to the recursive compound 974 * read/write below. 975 */ 976 if (!memberType.isCompound()) { 977 if (!isMemberSelected[globalMemberIndex[0] % this.getMemberCount()]) { 978 log.debug("compoundTypeIO(): member[{}] is not selected", i); 979 globalMemberIndex[0]++; 980 continue; // the field is not selected 981 } 982 } 983 984 if (!memberType.isCompound()) { 985 try { 986 memberName = new String(flatNameList.get(globalMemberIndex[0])); 987 } 988 catch (Exception ex) { 989 log.debug("compoundTypeIO(): get member {} name failure: ", i, ex); 990 memberName = "null"; 991 } 992 } 993 994 log.trace("compoundTypeIO(): member[{}]({}) is type {}", i, memberName, memberType.getDescription()); 995 996 if (ioType == H5File.IO_TYPE.READ) { 997 try { 998 if (memberType.isCompound()) 999 memberData = compoundTypeIO(ioType, did, spaceIDs, nSelPoints, memberType, writeBuf, globalMemberIndex); 1000 else if (memberType.isArray() /* || (memberType.isVLEN() && !memberType.isVarStr()) */) { 1001 /* 1002 * Recursively detect any nested array/vlen of compound types. 1003 */ 1004 boolean compoundFound = false; 1005 1006 Datatype base = memberType.getDatatypeBase(); 1007 while (base != null) { 1008 if (base.isCompound()) 1009 compoundFound = true; 1010 1011 base = base.getDatatypeBase(); 1012 } 1013 1014 if (compoundFound) { 1015 /* 1016 * Skip the top-level array/vlen type. 1017 */ 1018 globalMemberIndex[0]++; 1019 1020 memberData = compoundTypeIO(ioType, did, spaceIDs, nSelPoints, memberType, writeBuf, globalMemberIndex); 1021 } 1022 else { 1023 memberData = readSingleCompoundMember(did, spaceIDs, nSelPoints, memberType, memberName); 1024 globalMemberIndex[0]++; 1025 } 1026 } 1027 else { 1028 memberData = readSingleCompoundMember(did, spaceIDs, nSelPoints, memberType, memberName); 1029 globalMemberIndex[0]++; 1030 } 1031 } 1032 catch (Exception ex) { 1033 log.debug("compoundTypeIO(): failed to read member {}: ", i, ex); 1034 globalMemberIndex[0]++; 1035 memberData = null; 1036 } 1037 1038 if (memberData == null) { 1039 String[] errVal = new String[nSelPoints]; 1040 String errStr = "*ERROR*"; 1041 1042 for (int j = 0; j < nSelPoints; j++) 1043 errVal[j] = errStr; 1044 1045 memberData = errVal; 1046 } 1047 1048 memberDataList.add(memberData); 1049 } 1050 else { 1051 try { 1052 /* 1053 * TODO: currently doesn't correctly handle non-selected compound members. 1054 */ 1055 memberData = ((List<?>) writeBuf).get(writeListIndex++); 1056 } 1057 catch (Exception ex) { 1058 log.debug("compoundTypeIO(): get member[{}] data failure: ", i, ex); 1059 globalMemberIndex[0]++; 1060 continue; 1061 } 1062 1063 if (memberData == null) { 1064 log.debug("compoundTypeIO(): member[{}] data is null", i); 1065 globalMemberIndex[0]++; 1066 continue; 1067 } 1068 1069 try { 1070 if (memberType.isCompound()) { 1071 List<?> nestedList = (List<?>) ((List<?>) writeBuf).get(writeListIndex++); 1072 compoundTypeIO(ioType, did, spaceIDs, nSelPoints, memberType, nestedList, globalMemberIndex); 1073 } 1074 else { 1075 writeSingleCompoundMember(did, spaceIDs, nSelPoints, memberType, memberName, memberData); 1076 globalMemberIndex[0]++; 1077 } 1078 } 1079 catch (Exception ex) { 1080 log.debug("compoundTypeIO(): failed to write member[{}]: ", i, ex); 1081 globalMemberIndex[0]++; 1082 } 1083 } 1084 } // (i = 0, writeListIndex = 0; i < atomicTypeList.size(); i++) 1085 } 1086 catch (Exception ex) { 1087 log.debug("compoundTypeIO(): failure: ", ex); 1088 memberDataList = null; 1089 } 1090 1091 theData = memberDataList; 1092 } 1093 1094 return theData; 1095 } 1096 1097 /* 1098 * Private routine to read a single field of a compound datatype by creating a 1099 * compound datatype and inserting the single field into that datatype. 1100 */ 1101 private Object readSingleCompoundMember(long dsetID, long[] spaceIDs, int nSelPoints, 1102 final H5Datatype memberType, String memberName) throws Exception { 1103 H5Datatype dsDatatype = (H5Datatype) this.getDatatype(); 1104 Object memberData = null; 1105 1106 try { 1107 memberData = H5Datatype.allocateArray(memberType, nSelPoints); 1108 log.trace("readSingleCompoundMember(): allocateArray {} points ", nSelPoints); 1109 } 1110 catch (OutOfMemoryError err) { 1111 memberData = null; 1112 throw new Exception("Out of memory"); 1113 } 1114 catch (Exception ex) { 1115 log.debug("readSingleCompoundMember(): ", ex); 1116 memberData = null; 1117 } 1118 1119 if (memberData != null) { 1120 /* 1121 * Create a compound datatype containing just a single field (the one which we 1122 * want to read). 1123 */ 1124 long compTid = -1; 1125 try { 1126 compTid = dsDatatype.createCompoundFieldType(memberName); 1127 } 1128 catch (HDF5Exception ex) { 1129 log.debug("readSingleCompoundMember(): unable to create compound field type for member of type {}: ", 1130 memberType.getDescription(), ex); 1131 memberData = null; 1132 } 1133 1134 /* 1135 * Actually read the data for this member now that everything has been setup. 1136 */ 1137 try { 1138 if (memberType.isVarStr()) { 1139 log.trace("readSingleCompoundMember(): H5DreadVL did={} compTid={} spaceIDs[0]={} spaceIDs[1]={}", 1140 dsetID, compTid, (spaceIDs[0] == HDF5Constants.H5P_DEFAULT) ? "H5P_DEFAULT" : spaceIDs[0], 1141 (spaceIDs[1] == HDF5Constants.H5P_DEFAULT) ? "H5P_DEFAULT" : spaceIDs[1]); 1142 1143 H5.H5Dread_VLStrings(dsetID, compTid, spaceIDs[0], spaceIDs[1], HDF5Constants.H5P_DEFAULT, (Object[]) memberData); 1144 } 1145 else if (memberType.isVLEN() || (memberType.isArray() && memberType.getDatatypeBase().isVLEN())) { 1146 log.trace("readSingleCompoundMember(): H5DreadVL did={} compTid={} spaceIDs[0]={} spaceIDs[1]={}", 1147 dsetID, compTid, (spaceIDs[0] == HDF5Constants.H5P_DEFAULT) ? "H5P_DEFAULT" : spaceIDs[0], 1148 (spaceIDs[1] == HDF5Constants.H5P_DEFAULT) ? "H5P_DEFAULT" : spaceIDs[1]); 1149 1150 H5.H5DreadVL(dsetID, compTid, spaceIDs[0], spaceIDs[1], HDF5Constants.H5P_DEFAULT, (Object[]) memberData); 1151 } 1152 else { 1153 log.trace("readSingleCompoundMember(): H5Dread did={} compTid={} spaceIDs[0]={} spaceIDs[1]={}", 1154 dsetID, compTid, (spaceIDs[0] == HDF5Constants.H5P_DEFAULT) ? "H5P_DEFAULT" : spaceIDs[0], 1155 (spaceIDs[1] == HDF5Constants.H5P_DEFAULT) ? "H5P_DEFAULT" : spaceIDs[1]); 1156 1157 H5.H5Dread(dsetID, compTid, spaceIDs[0], spaceIDs[1], HDF5Constants.H5P_DEFAULT, memberData); 1158 } 1159 } 1160 catch (HDF5DataFiltersException exfltr) { 1161 log.debug("readSingleCompoundMember(): read failure: ", exfltr); 1162 throw new Exception("Filter not available exception: " + exfltr.getMessage(), exfltr); 1163 } 1164 catch (Exception ex) { 1165 log.debug("readSingleCompoundMember(): read failure: ", ex); 1166 throw new Exception("failed to read compound member: " + ex.getMessage(), ex); 1167 } 1168 finally { 1169 dsDatatype.close(compTid); 1170 } 1171 1172 /* 1173 * Perform any necessary data conversions. 1174 */ 1175 if (memberType.isUnsigned()) { 1176 log.trace("readSingleCompoundMember(): converting from unsigned C-type integers"); 1177 memberData = Dataset.convertFromUnsignedC(memberData, null); 1178 } 1179 else if (Utils.getJavaObjectRuntimeClass(memberData) == 'B') { 1180 log.trace("readSingleCompoundMember(): converting byte array member into Object"); 1181 1182 /* 1183 * For all other types that get read into memory as a byte[] (such as nested 1184 * compounds and arrays of compounds), we must manually convert the byte[] into 1185 * something usable. 1186 */ 1187 memberData = convertByteMember(memberType, (byte[]) memberData); 1188 } 1189 } 1190 1191 return memberData; 1192 } 1193 1194 /* 1195 * Private routine to write a single field of a compound datatype by creating a 1196 * compound datatype and inserting the single field into that datatype. 1197 */ 1198 private void writeSingleCompoundMember(long dsetID, long[] spaceIDs, int nSelPoints, 1199 final H5Datatype memberType, String memberName, Object theData) throws Exception { 1200 H5Datatype dsDatatype = (H5Datatype) this.getDatatype(); 1201 1202 /* 1203 * Check for any unsupported datatypes before attempting to write this compound 1204 * member. 1205 */ 1206 if (memberType.isVLEN() && !memberType.isVarStr()) { 1207 log.debug("writeSingleCompoundMember(): writing of VL non-strings is not currently supported"); 1208 throw new Exception("writing of VL non-strings is not currently supported"); 1209 } 1210 1211 /* 1212 * Perform any necessary data conversions before writing the data. 1213 */ 1214 Object tmpData = theData; 1215 try { 1216 if (memberType.isUnsigned()) { 1217 // Check if we need to convert unsigned integer data from Java-style 1218 // to C-style integers 1219 long tsize = memberType.getDatatypeSize(); 1220 String cname = theData.getClass().getName(); 1221 char dname = cname.charAt(cname.lastIndexOf('[') + 1); 1222 boolean doIntConversion = (((tsize == 1) && (dname == 'S')) 1223 || ((tsize == 2) && (dname == 'I')) || ((tsize == 4) && (dname == 'J'))); 1224 1225 if (doIntConversion) { 1226 log.trace("writeSingleCompoundMember(): converting integer data to unsigned C-type integers"); 1227 tmpData = convertToUnsignedC(theData, null); 1228 } 1229 } 1230 else if (memberType.isString() && (Array.get(theData, 0) instanceof String)) { 1231 log.trace("writeSingleCompoundMember(): converting string array to byte array"); 1232 tmpData = stringToByte((String[]) theData, (int) memberType.getDatatypeSize()); 1233 } 1234 else if (memberType.isEnum() && (Array.get(theData, 0) instanceof String)) { 1235 log.trace("writeSingleCompoundMember(): converting enum names to values"); 1236 tmpData = memberType.convertEnumNameToValue((String[]) theData); 1237 } 1238 } 1239 catch (Exception ex) { 1240 log.debug("writeSingleCompoundMember(): data conversion failure: ", ex); 1241 tmpData = null; 1242 } 1243 1244 if (tmpData == null) { 1245 log.debug("writeSingleCompoundMember(): data is null"); 1246 return; 1247 } 1248 1249 /* 1250 * Create a compound datatype containing just a single field (the one which we 1251 * want to write). 1252 */ 1253 long compTid = -1; 1254 try { 1255 compTid = dsDatatype.createCompoundFieldType(memberName); 1256 } 1257 catch (HDF5Exception ex) { 1258 log.debug("writeSingleCompoundMember(): unable to create compound field type for member of type {}: ", 1259 memberType.getDescription(), ex); 1260 } 1261 1262 /* 1263 * Actually write the data now that everything has been setup. 1264 */ 1265 try { 1266 if (memberType.isVarStr()) { 1267 log.trace("writeSingleCompoundMember(): H5Dwrite_string did={} compTid={} spaceIDs[0]={} spaceIDs[1]={}", 1268 dsetID, compTid, (spaceIDs[0] == HDF5Constants.H5P_DEFAULT) ? "H5P_DEFAULT" : spaceIDs[0], 1269 (spaceIDs[1] == HDF5Constants.H5P_DEFAULT) ? "H5P_DEFAULT" : spaceIDs[1]); 1270 1271 H5.H5Dwrite_string(dsetID, compTid, spaceIDs[0], spaceIDs[1], HDF5Constants.H5P_DEFAULT, (String[]) tmpData); 1272 } 1273 else { 1274 log.trace("writeSingleCompoundMember(): H5Dwrite did={} compTid={} spaceIDs[0]={} spaceIDs[1]={}", 1275 dsetID, compTid, (spaceIDs[0] == HDF5Constants.H5P_DEFAULT) ? "H5P_DEFAULT" : spaceIDs[0], 1276 (spaceIDs[1] == HDF5Constants.H5P_DEFAULT) ? "H5P_DEFAULT" : spaceIDs[1]); 1277 1278 // BUG!!! does not write nested compound data and no 1279 // exception was caught. Need to check if it is a java 1280 // error or C library error. 1281 H5.H5Dwrite(dsetID, compTid, spaceIDs[0], spaceIDs[1], HDF5Constants.H5P_DEFAULT, tmpData); 1282 } 1283 } 1284 catch (Exception ex) { 1285 log.debug("writeSingleCompoundMember(): write failure: ", ex); 1286 throw new Exception("failed to write compound member: " + ex.getMessage(), ex); 1287 } 1288 finally { 1289 dsDatatype.close(compTid); 1290 } 1291 } 1292 1293 /** 1294 * Converts the data values of this data object to appropriate Java integers if 1295 * they are unsigned integers. 1296 * 1297 * @see hdf.object.Dataset#convertToUnsignedC(Object) 1298 * @see hdf.object.Dataset#convertFromUnsignedC(Object, Object) 1299 * 1300 * @return the converted data buffer. 1301 */ 1302 @Override 1303 public Object convertFromUnsignedC() { 1304 throw new UnsupportedOperationException("H5CompoundDS:convertFromUnsignedC Unsupported operation."); 1305 } 1306 1307 /** 1308 * Converts Java integer data values of this data object back to unsigned C-type 1309 * integer data if they are unsigned integers. 1310 * 1311 * @see hdf.object.Dataset#convertToUnsignedC(Object) 1312 * @see hdf.object.Dataset#convertToUnsignedC(Object, Object) 1313 * 1314 * @return the converted data buffer. 1315 */ 1316 @Override 1317 public Object convertToUnsignedC() { 1318 throw new UnsupportedOperationException("H5CompoundDS:convertToUnsignedC Unsupported operation."); 1319 } 1320 1321 /** 1322 * Retrieves the object's metadata, such as attributes, from the file. 1323 * 1324 * Metadata, such as attributes, is stored in a List. 1325 * 1326 * @return the list of metadata objects. 1327 * 1328 * @throws HDF5Exception 1329 * if the metadata can not be retrieved 1330 */ 1331 @Override 1332 public List<Attribute> getMetadata() throws HDF5Exception { 1333 int gmIndexType = 0; 1334 int gmIndexOrder = 0; 1335 1336 try { 1337 gmIndexType = fileFormat.getIndexType(null); 1338 } 1339 catch (Exception ex) { 1340 log.debug("getMetadata(): getIndexType failed: ", ex); 1341 } 1342 try { 1343 gmIndexOrder = fileFormat.getIndexOrder(null); 1344 } 1345 catch (Exception ex) { 1346 log.debug("getMetadata(): getIndexOrder failed: ", ex); 1347 } 1348 return this.getMetadata(gmIndexType, gmIndexOrder); 1349 } 1350 1351 /** 1352 * Retrieves the object's metadata, such as attributes, from the file. 1353 * 1354 * Metadata, such as attributes, is stored in a List. 1355 * 1356 * @param attrPropList 1357 * the list of properties to get 1358 * 1359 * @return the list of metadata objects. 1360 * 1361 * @throws HDF5Exception 1362 * if the metadata can not be retrieved 1363 */ 1364 public List<Attribute> getMetadata(int... attrPropList) throws HDF5Exception { 1365 if (!isInited()) 1366 init(); 1367 1368 try { 1369 this.linkTargetObjName = H5File.getLinkTargetName(this); 1370 } 1371 catch (Exception ex) { 1372 log.debug("getMetadata(): getLinkTargetName failed: ", ex); 1373 } 1374 1375 if (objMetadata.getAttributeList() == null) { 1376 long did = HDF5Constants.H5I_INVALID_HID; 1377 long pcid = HDF5Constants.H5I_INVALID_HID; 1378 long paid = HDF5Constants.H5I_INVALID_HID; 1379 1380 did = open(); 1381 if (did >= 0) { 1382 try { 1383 // get the compression and chunk information 1384 pcid = H5.H5Dget_create_plist(did); 1385 paid = H5.H5Dget_access_plist(did); 1386 long storageSize = H5.H5Dget_storage_size(did); 1387 int nfilt = H5.H5Pget_nfilters(pcid); 1388 int layoutType = H5.H5Pget_layout(pcid); 1389 1390 storageLayout.setLength(0); 1391 compression.setLength(0); 1392 1393 if (layoutType == HDF5Constants.H5D_CHUNKED) { 1394 chunkSize = new long[rank]; 1395 H5.H5Pget_chunk(pcid, rank, chunkSize); 1396 int n = chunkSize.length; 1397 storageLayout.append("CHUNKED: ").append(chunkSize[0]); 1398 for (int i = 1; i < n; i++) 1399 storageLayout.append(" X ").append(chunkSize[i]); 1400 1401 if (nfilt > 0) { 1402 long nelmts = 1; 1403 long uncompSize; 1404 long datumSize = getDatatype().getDatatypeSize(); 1405 1406 if (datumSize < 0) { 1407 long tmptid = HDF5Constants.H5I_INVALID_HID; 1408 try { 1409 tmptid = H5.H5Dget_type(did); 1410 datumSize = H5.H5Tget_size(tmptid); 1411 } 1412 finally { 1413 try { 1414 H5.H5Tclose(tmptid); 1415 } 1416 catch (Exception ex2) { 1417 log.debug("getMetadata(): H5Tclose(tmptid {}) failure: ", tmptid, ex2); 1418 } 1419 } 1420 } 1421 1422 for (int i = 0; i < rank; i++) 1423 nelmts *= dims[i]; 1424 uncompSize = nelmts * datumSize; 1425 1426 /* compression ratio = uncompressed size / compressed size */ 1427 1428 if (storageSize != 0) { 1429 double ratio = (double) uncompSize / (double) storageSize; 1430 DecimalFormat df = new DecimalFormat(); 1431 df.setMinimumFractionDigits(3); 1432 df.setMaximumFractionDigits(3); 1433 compression.append(df.format(ratio)).append(":1"); 1434 } 1435 } 1436 } 1437 else if (layoutType == HDF5Constants.H5D_COMPACT) { 1438 storageLayout.append("COMPACT"); 1439 } 1440 else if (layoutType == HDF5Constants.H5D_CONTIGUOUS) { 1441 storageLayout.append("CONTIGUOUS"); 1442 if (H5.H5Pget_external_count(pcid) > 0) 1443 storageLayout.append(" - EXTERNAL "); 1444 } 1445 else if (layoutType == HDF5Constants.H5D_VIRTUAL) { 1446 storageLayout.append("VIRTUAL - "); 1447 try { 1448 long vmaps = H5.H5Pget_virtual_count(pcid); 1449 try { 1450 int virtView = H5.H5Pget_virtual_view(paid); 1451 long virtGap = H5.H5Pget_virtual_printf_gap(paid); 1452 if (virtView == HDF5Constants.H5D_VDS_FIRST_MISSING) 1453 storageLayout.append("First Missing"); 1454 else 1455 storageLayout.append("Last Available"); 1456 storageLayout.append("\nGAP : ").append(virtGap); 1457 } 1458 catch (Exception err) { 1459 log.debug("getMetadata(): vds error: ", err); 1460 storageLayout.append("ERROR"); 1461 } 1462 storageLayout.append("\nMAPS : ").append(vmaps); 1463 if (vmaps > 0) { 1464 for (long next = 0; next < vmaps; next++) { 1465 try { 1466 H5.H5Pget_virtual_vspace(pcid, next); 1467 H5.H5Pget_virtual_srcspace(pcid, next); 1468 String fname = H5.H5Pget_virtual_filename(pcid, next); 1469 String dsetname = H5.H5Pget_virtual_dsetname(pcid, next); 1470 storageLayout.append("\n").append(fname).append(" : ").append(dsetname); 1471 } 1472 catch (Exception err) { 1473 log.debug("getMetadata(): vds space[{}] error: ", next, err); 1474 storageLayout.append("ERROR"); 1475 } 1476 } 1477 } 1478 } 1479 catch (Exception err) { 1480 log.debug("getMetadata(): vds count error: ", err); 1481 storageLayout.append("ERROR"); 1482 } 1483 } 1484 else { 1485 chunkSize = null; 1486 storageLayout.append("NONE"); 1487 } 1488 1489 int[] flags = { 0, 0 }; 1490 long[] cdNelmts = { 20 }; 1491 int[] cdValues = new int[(int) cdNelmts[0]]; 1492 String[] cdName = { "", "" }; 1493 log.trace("getMetadata(): {} filters in pipeline", nfilt); 1494 int filter = -1; 1495 int[] filterConfig = { 1 }; 1496 1497 filters.setLength(0); 1498 1499 if (nfilt == 0) { 1500 filters.append("NONE"); 1501 } 1502 else { 1503 for (int i = 0, k = 0; i < nfilt; i++) { 1504 log.trace("getMetadata(): filter[{}]", i); 1505 if (i > 0) 1506 filters.append(", "); 1507 if (k > 0) 1508 compression.append(", "); 1509 1510 try { 1511 cdNelmts[0] = 20; 1512 cdValues = new int[(int) cdNelmts[0]]; 1513 cdValues = new int[(int) cdNelmts[0]]; 1514 filter = H5.H5Pget_filter(pcid, i, flags, cdNelmts, cdValues, 120, cdName, filterConfig); 1515 log.trace("getMetadata(): filter[{}] is {} has {} elements ", i, cdName[0], cdNelmts[0]); 1516 for (int j = 0; j < cdNelmts[0]; j++) 1517 log.trace("getMetadata(): filter[{}] element {} = {}", i, j, cdValues[j]); 1518 } 1519 catch (Exception err) { 1520 log.debug("getMetadata(): filter[{}] error: ", i, err); 1521 filters.append("ERROR"); 1522 continue; 1523 } 1524 1525 if (filter == HDF5Constants.H5Z_FILTER_NONE) { 1526 filters.append("NONE"); 1527 } 1528 else if (filter == HDF5Constants.H5Z_FILTER_DEFLATE) { 1529 filters.append("GZIP"); 1530 compression.append(COMPRESSION_GZIP_TXT).append(cdValues[0]); 1531 k++; 1532 } 1533 else if (filter == HDF5Constants.H5Z_FILTER_FLETCHER32) { 1534 filters.append("Error detection filter"); 1535 } 1536 else if (filter == HDF5Constants.H5Z_FILTER_SHUFFLE) { 1537 filters.append("SHUFFLE: Nbytes = ").append(cdValues[0]); 1538 } 1539 else if (filter == HDF5Constants.H5Z_FILTER_NBIT) { 1540 filters.append("NBIT"); 1541 } 1542 else if (filter == HDF5Constants.H5Z_FILTER_SCALEOFFSET) { 1543 filters.append("SCALEOFFSET: MIN BITS = ").append(cdValues[0]); 1544 } 1545 else if (filter == HDF5Constants.H5Z_FILTER_SZIP) { 1546 filters.append("SZIP"); 1547 compression.append("SZIP: Pixels per block = ").append(cdValues[1]); 1548 k++; 1549 int flag = -1; 1550 try { 1551 flag = H5.H5Zget_filter_info(filter); 1552 } 1553 catch (Exception ex) { 1554 log.debug("getMetadata(): H5Zget_filter_info failure: ", ex); 1555 flag = -1; 1556 } 1557 if (flag == HDF5Constants.H5Z_FILTER_CONFIG_DECODE_ENABLED) 1558 compression.append(": H5Z_FILTER_CONFIG_DECODE_ENABLED"); 1559 else if ((flag == HDF5Constants.H5Z_FILTER_CONFIG_ENCODE_ENABLED) 1560 || (flag >= (HDF5Constants.H5Z_FILTER_CONFIG_ENCODE_ENABLED 1561 + HDF5Constants.H5Z_FILTER_CONFIG_DECODE_ENABLED))) 1562 compression.append(": H5Z_FILTER_CONFIG_ENCODE_ENABLED"); 1563 } 1564 else { 1565 filters.append("USERDEFINED ").append(cdName[0]).append("(").append(filter).append("): "); 1566 for (int j = 0; j < cdNelmts[0]; j++) { 1567 if (j > 0) 1568 filters.append(", "); 1569 filters.append(cdValues[j]); 1570 } 1571 log.debug("getMetadata(): filter[{}] is user defined compression", i); 1572 } 1573 } // (int i=0; i<nfilt; i++) 1574 } 1575 1576 if (compression.length() == 0) 1577 compression.append("NONE"); 1578 log.trace("getMetadata(): filter compression={}", compression); 1579 log.trace("getMetadata(): filter information={}", filters); 1580 1581 storage.setLength(0); 1582 storage.append("SIZE: ").append(storageSize); 1583 1584 try { 1585 int[] at = { 0 }; 1586 H5.H5Pget_alloc_time(pcid, at); 1587 storage.append(", allocation time: "); 1588 if (at[0] == HDF5Constants.H5D_ALLOC_TIME_EARLY) 1589 storage.append("Early"); 1590 else if (at[0] == HDF5Constants.H5D_ALLOC_TIME_INCR) 1591 storage.append("Incremental"); 1592 else if (at[0] == HDF5Constants.H5D_ALLOC_TIME_LATE) 1593 storage.append("Late"); 1594 else 1595 storage.append("Default"); 1596 } 1597 catch (Exception ex) { 1598 log.debug("getMetadata(): Storage allocation time:", ex); 1599 } 1600 log.trace("getMetadata(): storage={}", storage); 1601 } 1602 finally { 1603 try { 1604 H5.H5Pclose(paid); 1605 } 1606 catch (Exception ex) { 1607 log.debug("getMetadata(): H5Pclose(paid {}) failure: ", paid, ex); 1608 } 1609 try { 1610 H5.H5Pclose(pcid); 1611 } 1612 catch (Exception ex) { 1613 log.debug("getMetadata(): H5Pclose(pcid {}) failure: ", pcid, ex); 1614 } 1615 close(did); 1616 } 1617 } 1618 } 1619 1620 List<Attribute> attrlist = null; 1621 try { 1622 attrlist = objMetadata.getMetadata(attrPropList); 1623 } 1624 catch (Exception ex) { 1625 log.debug("getMetadata(): getMetadata failed: ", ex); 1626 } 1627 return attrlist; 1628 } 1629 1630 /** 1631 * Writes a specific piece of metadata (such as an attribute) into the file. 1632 * 1633 * If an HDF(4&5) attribute exists in the file, this method updates its 1634 * value. If the attribute does not exist in the file, it creates the 1635 * attribute in the file and attaches it to the object. It will fail to 1636 * write a new attribute to the object where an attribute with the same name 1637 * already exists. To update the value of an existing attribute in the file, 1638 * one needs to get the instance of the attribute by getMetadata(), change 1639 * its values, then use writeMetadata() to write the value. 1640 * 1641 * @param info 1642 * the metadata to write. 1643 * 1644 * @throws Exception 1645 * if the metadata can not be written 1646 */ 1647 @Override 1648 public void writeMetadata(Object info) throws Exception { 1649 try { 1650 objMetadata.writeMetadata(info); 1651 } 1652 catch (Exception ex) { 1653 log.debug("writeMetadata(): Object not an Attribute"); 1654 return; 1655 } 1656 } 1657 1658 /** 1659 * Deletes an existing piece of metadata from this object. 1660 * 1661 * @param info 1662 * the metadata to delete. 1663 * 1664 * @throws HDF5Exception 1665 * if the metadata can not be removed 1666 */ 1667 @Override 1668 public void removeMetadata(Object info) throws HDF5Exception { 1669 try { 1670 objMetadata.removeMetadata(info); 1671 } 1672 catch (Exception ex) { 1673 log.debug("removeMetadata(): Object not an Attribute"); 1674 return; 1675 } 1676 1677 Attribute attr = (Attribute) info; 1678 log.trace("removeMetadata(): {}", attr.getAttributeName()); 1679 long did = open(); 1680 if (did >= 0) { 1681 try { 1682 H5.H5Adelete(did, attr.getAttributeName()); 1683 } 1684 finally { 1685 close(did); 1686 } 1687 } 1688 else { 1689 log.debug("removeMetadata(): failed to open compound dataset"); 1690 } 1691 } 1692 1693 /** 1694 * Updates an existing piece of metadata attached to this object. 1695 * 1696 * @param info 1697 * the metadata to update. 1698 * 1699 * @throws HDF5Exception 1700 * if the metadata can not be updated 1701 */ 1702 @Override 1703 public void updateMetadata(Object info) throws HDF5Exception { 1704 try { 1705 objMetadata.updateMetadata(info); 1706 } 1707 catch (Exception ex) { 1708 log.debug("updateMetadata(): Object not an Attribute"); 1709 return; 1710 } 1711 } 1712 1713 /* 1714 * (non-Javadoc) 1715 * 1716 * @see hdf.object.HObject#setName(java.lang.String) 1717 */ 1718 @Override 1719 public void setName(String newName) throws Exception { 1720 if (newName == null) 1721 throw new IllegalArgumentException("The new name is NULL"); 1722 1723 H5File.renameObject(this, newName); 1724 super.setName(newName); 1725 } 1726 1727 /** 1728 * @deprecated Not for public use in the future. <br> 1729 * Using 1730 * {@link #create(String, Group, long[], long[], long[], int, String[], Datatype[], int[], long[][], Object)} 1731 * 1732 * @param name 1733 * the name of the dataset to create. 1734 * @param pgroup 1735 * parent group where the new dataset is created. 1736 * @param dims 1737 * the dimension size of the dataset. 1738 * @param memberNames 1739 * the names of compound datatype 1740 * @param memberDatatypes 1741 * the datatypes of the compound datatype 1742 * @param memberSizes 1743 * the dim sizes of the members 1744 * @param data 1745 * list of data arrays written to the new dataset, null if no data is written to the new 1746 * dataset. 1747 * 1748 * @return the new compound dataset if successful; otherwise returns null. 1749 * 1750 * @throws Exception 1751 * if there is a failure. 1752 */ 1753 @Deprecated 1754 public static Dataset create(String name, Group pgroup, long[] dims, String[] memberNames, 1755 Datatype[] memberDatatypes, int[] memberSizes, Object data) throws Exception { 1756 if ((pgroup == null) || (name == null) || (dims == null) || (memberNames == null) 1757 || (memberDatatypes == null) || (memberSizes == null)) { 1758 return null; 1759 } 1760 1761 int nMembers = memberNames.length; 1762 int memberRanks[] = new int[nMembers]; 1763 long memberDims[][] = new long[nMembers][1]; 1764 for (int i = 0; i < nMembers; i++) { 1765 memberRanks[i] = 1; 1766 memberDims[i][0] = memberSizes[i]; 1767 } 1768 1769 return H5CompoundDS.create(name, pgroup, dims, memberNames, memberDatatypes, memberRanks, memberDims, data); 1770 } 1771 1772 /** 1773 * @deprecated Not for public use in the future. <br> 1774 * Using 1775 * {@link #create(String, Group, long[], long[], long[], int, String[], Datatype[], int[], long[][], Object)} 1776 * 1777 * @param name 1778 * the name of the dataset to create. 1779 * @param pgroup 1780 * parent group where the new dataset is created. 1781 * @param dims 1782 * the dimension size of the dataset. 1783 * @param memberNames 1784 * the names of compound datatype 1785 * @param memberDatatypes 1786 * the datatypes of the compound datatype 1787 * @param memberRanks 1788 * the ranks of the members 1789 * @param memberDims 1790 * the dim sizes of the members 1791 * @param data 1792 * list of data arrays written to the new dataset, null if no data is written to the new 1793 * dataset. 1794 * 1795 * @return the new compound dataset if successful; otherwise returns null. 1796 * 1797 * @throws Exception 1798 * if the dataset can not be created. 1799 */ 1800 @Deprecated 1801 public static Dataset create(String name, Group pgroup, long[] dims, String[] memberNames, 1802 Datatype[] memberDatatypes, int[] memberRanks, long[][] memberDims, Object data) throws Exception { 1803 return H5CompoundDS.create(name, pgroup, dims, null, null, -1, memberNames, memberDatatypes, memberRanks, 1804 memberDims, data); 1805 } 1806 1807 /** 1808 * Creates a simple compound dataset in a file with/without chunking and compression. 1809 * 1810 * This function provides an easy way to create a simple compound dataset in file by hiding tedious 1811 * details of creating a compound dataset from users. 1812 * 1813 * This function calls H5.H5Dcreate() to create a simple compound dataset in file. Nested compound 1814 * dataset is not supported. The required information to create a compound dataset includes the 1815 * name, the parent group and data space of the dataset, the names, datatypes and data spaces of the 1816 * compound fields. Other information such as chunks, compression and the data buffer is optional. 1817 * 1818 * The following example shows how to use this function to create a compound dataset in file. 1819 * 1820 * <pre> 1821 * H5File file = null; 1822 * String message = ""; 1823 * Group pgroup = null; 1824 * int[] DATA_INT = new int[DIM_SIZE]; 1825 * float[] DATA_FLOAT = new float[DIM_SIZE]; 1826 * String[] DATA_STR = new String[DIM_SIZE]; 1827 * long[] DIMs = { 50, 10 }; 1828 * long[] CHUNKs = { 25, 5 }; 1829 * 1830 * try { 1831 * file = (H5File) H5FILE.open(fname, H5File.CREATE); 1832 * file.open(); 1833 * pgroup = (Group) file.get("/"); 1834 * } 1835 * catch (Exception ex) { 1836 * } 1837 * 1838 * Vector data = new Vector(); 1839 * data.add(0, DATA_INT); 1840 * data.add(1, DATA_FLOAT); 1841 * data.add(2, DATA_STR); 1842 * 1843 * // create groups 1844 * Datatype[] mdtypes = new H5Datatype[3]; 1845 * String[] mnames = { "int", "float", "string" }; 1846 * Dataset dset = null; 1847 * try { 1848 * mdtypes[0] = new H5Datatype(Datatype.CLASS_INTEGER, 4, Datatype.NATIVE, Datatype.NATIVE); 1849 * mdtypes[1] = new H5Datatype(Datatype.CLASS_FLOAT, 4, Datatype.NATIVE, Datatype.NATIVE); 1850 * mdtypes[2] = new H5Datatype(Datatype.CLASS_STRING, STR_LEN, Datatype.NATIVE, Datatype.NATIVE); 1851 * dset = file.createCompoundDS("/CompoundDS", pgroup, DIMs, null, CHUNKs, 9, mnames, mdtypes, null, data); 1852 * } 1853 * catch (Exception ex) { 1854 * failed(message, ex, file); 1855 * return 1; 1856 * } 1857 * </pre> 1858 * 1859 * @param name 1860 * the name of the dataset to create. 1861 * @param pgroup 1862 * parent group where the new dataset is created. 1863 * @param dims 1864 * the dimension size of the dataset. 1865 * @param maxdims 1866 * the max dimension size of the dataset. maxdims is set to dims if maxdims = null. 1867 * @param chunks 1868 * the chunk size of the dataset. No chunking if chunk = null. 1869 * @param gzip 1870 * GZIP compression level (1 to 9). 0 or negative values if no compression. 1871 * @param memberNames 1872 * the names of compound datatype 1873 * @param memberDatatypes 1874 * the datatypes of the compound datatype 1875 * @param memberRanks 1876 * the ranks of the members 1877 * @param memberDims 1878 * the dim sizes of the members 1879 * @param data 1880 * list of data arrays written to the new dataset, null if no data is written to the new 1881 * dataset. 1882 * 1883 * @return the new compound dataset if successful; otherwise returns null. 1884 * 1885 * @throws Exception 1886 * if there is a failure. 1887 */ 1888 public static Dataset create(String name, Group pgroup, long[] dims, long[] maxdims, long[] chunks, int gzip, 1889 String[] memberNames, Datatype[] memberDatatypes, int[] memberRanks, long[][] memberDims, Object data) throws Exception { 1890 H5CompoundDS dataset = null; 1891 String fullPath = null; 1892 long did = HDF5Constants.H5I_INVALID_HID; 1893 long plist = HDF5Constants.H5I_INVALID_HID; 1894 long sid = HDF5Constants.H5I_INVALID_HID; 1895 long tid = HDF5Constants.H5I_INVALID_HID; 1896 1897 if ((pgroup == null) || (name == null) || (dims == null) || ((gzip > 0) && (chunks == null)) 1898 || (memberNames == null) || (memberDatatypes == null) || (memberRanks == null) 1899 || (memberDims == null)) { 1900 log.debug("create(): one or more parameters are null"); 1901 return null; 1902 } 1903 1904 H5File file = (H5File) pgroup.getFileFormat(); 1905 if (file == null) { 1906 log.debug("create(): parent group FileFormat is null"); 1907 return null; 1908 } 1909 1910 String path = HObject.SEPARATOR; 1911 if (!pgroup.isRoot()) { 1912 path = pgroup.getPath() + pgroup.getName() + HObject.SEPARATOR; 1913 if (name.endsWith("/")) 1914 name = name.substring(0, name.length() - 1); 1915 int idx = name.lastIndexOf('/'); 1916 if (idx >= 0) 1917 name = name.substring(idx + 1); 1918 } 1919 1920 fullPath = path + name; 1921 1922 int typeSize = 0; 1923 int nMembers = memberNames.length; 1924 long[] mTypes = new long[nMembers]; 1925 int memberSize = 1; 1926 for (int i = 0; i < nMembers; i++) { 1927 memberSize = 1; 1928 for (int j = 0; j < memberRanks[i]; j++) 1929 memberSize *= memberDims[i][j]; 1930 1931 mTypes[i] = -1; 1932 // the member is an array 1933 if ((memberSize > 1) && (!memberDatatypes[i].isString())) { 1934 long tmptid = -1; 1935 if ((tmptid = memberDatatypes[i].createNative()) >= 0) { 1936 try { 1937 mTypes[i] = H5.H5Tarray_create(tmptid, memberRanks[i], memberDims[i]); 1938 } 1939 finally { 1940 try { 1941 H5.H5Tclose(tmptid); 1942 } 1943 catch (Exception ex) { 1944 log.debug("create(): H5Tclose(tmptid {}) failure: ", tmptid, ex); 1945 } 1946 } 1947 } 1948 } 1949 else { 1950 mTypes[i] = memberDatatypes[i].createNative(); 1951 } 1952 try { 1953 typeSize += H5.H5Tget_size(mTypes[i]); 1954 } 1955 catch (Exception ex) { 1956 log.debug("create(): array create H5Tget_size:", ex); 1957 1958 while (i > 0) { 1959 try { 1960 H5.H5Tclose(mTypes[i]); 1961 } 1962 catch (HDF5Exception ex2) { 1963 log.debug("create(): H5Tclose(mTypes[{}] {}) failure: ", i, mTypes[i], ex2); 1964 } 1965 i--; 1966 } 1967 throw ex; 1968 } 1969 } // (int i = 0; i < nMembers; i++) { 1970 1971 // setup chunking and compression 1972 boolean isExtentable = false; 1973 if (maxdims != null) { 1974 for (int i = 0; i < maxdims.length; i++) { 1975 if (maxdims[i] == 0) 1976 maxdims[i] = dims[i]; 1977 else if (maxdims[i] < 0) 1978 maxdims[i] = HDF5Constants.H5S_UNLIMITED; 1979 1980 if (maxdims[i] != dims[i]) 1981 isExtentable = true; 1982 } 1983 } 1984 1985 // HDF5 requires you to use chunking in order to define extendible 1986 // datasets. Chunking makes it possible to extend datasets efficiently, 1987 // without having to reorganize storage excessively. Using default size 1988 // of 64x...which has good performance 1989 if ((chunks == null) && isExtentable) { 1990 chunks = new long[dims.length]; 1991 for (int i = 0; i < dims.length; i++) 1992 chunks[i] = Math.min(dims[i], 64); 1993 } 1994 1995 // prepare the dataspace and datatype 1996 int rank = dims.length; 1997 1998 try { 1999 sid = H5.H5Screate_simple(rank, dims, maxdims); 2000 2001 // figure out creation properties 2002 plist = HDF5Constants.H5P_DEFAULT; 2003 2004 tid = H5.H5Tcreate(HDF5Constants.H5T_COMPOUND, typeSize); 2005 int offset = 0; 2006 for (int i = 0; i < nMembers; i++) { 2007 H5.H5Tinsert(tid, memberNames[i], offset, mTypes[i]); 2008 offset += H5.H5Tget_size(mTypes[i]); 2009 } 2010 2011 if (chunks != null) { 2012 plist = H5.H5Pcreate(HDF5Constants.H5P_DATASET_CREATE); 2013 2014 H5.H5Pset_layout(plist, HDF5Constants.H5D_CHUNKED); 2015 H5.H5Pset_chunk(plist, rank, chunks); 2016 2017 // compression requires chunking 2018 if (gzip > 0) { 2019 H5.H5Pset_deflate(plist, gzip); 2020 } 2021 } 2022 2023 long fid = file.getFID(); 2024 2025 did = H5.H5Dcreate(fid, fullPath, tid, sid, HDF5Constants.H5P_DEFAULT, plist, HDF5Constants.H5P_DEFAULT); 2026 dataset = new H5CompoundDS(file, name, path); 2027 } 2028 finally { 2029 try { 2030 H5.H5Pclose(plist); 2031 } 2032 catch (HDF5Exception ex) { 2033 log.debug("create(): H5Pclose(plist {}) failure: ", plist, ex); 2034 } 2035 try { 2036 H5.H5Sclose(sid); 2037 } 2038 catch (HDF5Exception ex) { 2039 log.debug("create(): H5Sclose(sid {}) failure: ", sid, ex); 2040 } 2041 try { 2042 H5.H5Tclose(tid); 2043 } 2044 catch (HDF5Exception ex) { 2045 log.debug("create(): H5Tclose(tid {}) failure: ", tid, ex); 2046 } 2047 try { 2048 H5.H5Dclose(did); 2049 } 2050 catch (HDF5Exception ex) { 2051 log.debug("create(): H5Dclose(did {}) failure: ", did, ex); 2052 } 2053 2054 for (int i = 0; i < nMembers; i++) { 2055 try { 2056 H5.H5Tclose(mTypes[i]); 2057 } 2058 catch (HDF5Exception ex) { 2059 log.debug("create(): H5Tclose(mTypes[{}] {}) failure: ", i, mTypes[i], ex); 2060 } 2061 } 2062 } 2063 2064 if (dataset != null) { 2065 pgroup.addToMemberList(dataset); 2066 if (data != null) { 2067 dataset.init(); 2068 long selected[] = dataset.getSelectedDims(); 2069 for (int i = 0; i < rank; i++) 2070 selected[i] = dims[i]; 2071 dataset.write(data); 2072 } 2073 } 2074 2075 return dataset; 2076 } 2077 2078 /* 2079 * (non-Javadoc) 2080 * 2081 * @see hdf.object.Dataset#isString(long) 2082 */ 2083 @Override 2084 public boolean isString(long tid) { 2085 boolean b = false; 2086 try { 2087 b = (HDF5Constants.H5T_STRING == H5.H5Tget_class(tid)); 2088 } 2089 catch (Exception ex) { 2090 b = false; 2091 } 2092 2093 return b; 2094 } 2095 2096 /* 2097 * (non-Javadoc) 2098 * 2099 * @see hdf.object.Dataset#getSize(long) 2100 */ 2101 @Override 2102 public long getSize(long tid) { 2103 return H5Datatype.getDatatypeSize(tid); 2104 } 2105 2106 /* 2107 * (non-Javadoc) 2108 * 2109 * @see hdf.object.Dataset#isVirtual() 2110 */ 2111 @Override 2112 public boolean isVirtual() { 2113 return isVirtual; 2114 } 2115 2116 /* 2117 * (non-Javadoc) 2118 * 2119 * @see hdf.object.Dataset#getVirtualFilename(int) 2120 */ 2121 @Override 2122 public String getVirtualFilename(int index) { 2123 if(isVirtual) 2124 return virtualNameList.get(index); 2125 else 2126 return null; 2127 } 2128 2129 /* 2130 * (non-Javadoc) 2131 * 2132 * @see hdf.object.Dataset#getVirtualMaps() 2133 */ 2134 @Override 2135 public int getVirtualMaps() { 2136 if(isVirtual) 2137 return virtualNameList.size(); 2138 else 2139 return -1; 2140 } 2141 2142 /* 2143 * (non-Javadoc) 2144 * 2145 * @see hdf.object.Dataset#toString(String delimiter, int maxItems) 2146 */ 2147 @Override 2148 public String toString(String delimiter, int maxItems) { 2149 Object theData = originalBuf; 2150 if (theData == null) { 2151 log.debug("toString: value is null"); 2152 return null; 2153 } 2154 2155 if (theData instanceof List<?>) { 2156 log.trace("toString: value is list"); 2157 return null; 2158 } 2159 2160 Class<? extends Object> valClass = theData.getClass(); 2161 2162 if (!valClass.isArray()) { 2163 log.trace("toString: finish - not array"); 2164 String strValue = theData.toString(); 2165 if (maxItems > 0 && strValue.length() > maxItems) 2166 // truncate the extra characters 2167 strValue = strValue.substring(0, maxItems); 2168 return strValue; 2169 } 2170 2171 // value is an array 2172 StringBuilder sb = new StringBuilder(); 2173 int n = Array.getLength(theData); 2174 if ((maxItems > 0) && (n > maxItems)) 2175 n = maxItems; 2176 2177 log.trace("toString: isStdRef={} Array.getLength={}", ((H5Datatype) getDatatype()).isStdRef(), n); 2178 if (((H5Datatype) getDatatype()).isStdRef()) { 2179 String cname = valClass.getName(); 2180 char dname = cname.charAt(cname.lastIndexOf('[') + 1); 2181 log.trace("toString: isStdRef with cname={} dname={}", cname, dname); 2182 String ref_str = ((H5ReferenceType) getDatatype()).getObjectReferenceName((byte[])theData); 2183 log.trace("toString: ref_str={}", ref_str); 2184 return ref_str; 2185 } 2186 else { 2187 return super.toString(delimiter, maxItems); 2188 } 2189 } 2190 2191}