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.math.MathContext; 021import java.util.ArrayList; 022import java.util.Arrays; 023import java.util.BitSet; 024import java.util.HashMap; 025import java.util.Iterator; 026import java.util.List; 027import java.util.Map.Entry; 028import java.util.Objects; 029import java.util.Vector; 030 031import org.slf4j.Logger; 032import org.slf4j.LoggerFactory; 033 034import hdf.hdf5lib.H5; 035import hdf.hdf5lib.HDF5Constants; 036import hdf.hdf5lib.HDFArray; 037import hdf.hdf5lib.HDFNativeData; 038import hdf.hdf5lib.exceptions.HDF5Exception; 039import hdf.hdf5lib.exceptions.HDF5LibraryException; 040import hdf.hdf5lib.structs.H5O_info_t; 041import hdf.hdf5lib.structs.H5O_token_t; 042 043import hdf.object.Attribute; 044import hdf.object.CompoundDS; 045import hdf.object.Datatype; 046import hdf.object.FileFormat; 047 048import hdf.object.h5.H5MetaDataContainer; 049 050/** 051 * This class defines HDF5 datatype characteristics and APIs for a data type. This class provides several methods to 052 * convert an HDF5 datatype identifier to a datatype object, and vice versa. A datatype object is described by four 053 * basic fields: datatype class, size, byte order, and sign, while an HDF5 datatype is presented by a datatype 054 * identifier. 055 * 056 * @version 1.1 9/4/2007 057 * @author Peter X. Cao 058 */ 059public class H5Datatype extends Datatype 060{ 061 private static final long serialVersionUID = -750546422258749792L; 062 063 private static final Logger log = LoggerFactory.getLogger(H5Datatype.class); 064 065 /** 066 * The metadata object for this data object. Members of the metadata are instances of Attribute. 067 */ 068 private H5MetaDataContainer objMetadata; 069 070 /** 071 * The dimension sizes of the reference object 072 */ 073 protected long[] refdims; 074 075 /** the datatype is an object reference */ 076 private boolean isRefObj = false; 077 078 /** the datatype is a region reference */ 079 private boolean isRegRef = false; 080 081 /** the datatype is a standard reference */ 082 private boolean isStdRef = false; 083 084 /** the object properties */ 085 private H5O_info_t objInfo; 086 087 /** 088 * The native class of the datatype. 089 */ 090 private int nativeClass = -1; 091 092 /** The native Precision properties of the number datatype. */ 093 private long nativePrecision = 0; 094 /** The native Offset properties of the number datatype. */ 095 private int nativeOffset = -1; 096 /** The native PadLSB properties of the number datatype. */ 097 private int nativePadLSB = -1; 098 /** The native PadMSB properties of the number datatype. */ 099 private int nativePadMSB = -1; 100 101 /** The native ebias properties of the float datatype. */ 102 private long nativeFPebias = 0; 103 /** The native spos properties of the float datatype. */ 104 private long nativeFPspos = -1; 105 /** The native epos properties of the float datatype. */ 106 private long nativeFPepos = -1; 107 /** The native esize properties of the float datatype. */ 108 private long nativeFPesize = -1; 109 /** The native mpos properties of the float datatype. */ 110 private long nativeFPmpos = -1; 111 /** The native msize properties of the float datatype. */ 112 private long nativeFPmsize = -1; 113 /** The native norm properties of the float datatype. */ 114 private int nativeFPnorm = -1; 115 /** The native inpad properties of the float datatype. */ 116 private int nativeFPinpad = -1; 117 118 /** The native padding properties of the string datatype. */ 119 private int nativeStrPad = -1; 120 /** The native CSET properties of the string datatype. */ 121 private int nativeStrCSET = -1; 122 123 /** 124 * The tag for an opaque datatype. 125 */ 126 private String opaqueTag = null; 127 128 /** 129 * Constructs an named HDF5 data type object for a given file, dataset name and group path. The datatype object 130 * represents an existing named datatype in file. For example, 131 * 132 * <pre> 133 * new H5Datatype(file, "dtype1", "/g0") 134 * </pre> 135 * 136 * constructs a datatype object that corresponds to the dataset,"dset1", at group "/g0". 137 * 138 * @param theFile 139 * the file that contains the datatype. 140 * @param theName 141 * the name of the dataset such as "dset1". 142 * @param thePath 143 * the group path to the dataset such as "/g0/". 144 */ 145 public H5Datatype(FileFormat theFile, String theName, String thePath) { 146 this(theFile, theName, thePath, null); 147 } 148 149 /** 150 * @deprecated Not for public use in the future. <br> 151 * Using {@link #H5Datatype(FileFormat, String, String)} 152 * @param theFile 153 * the file that contains the datatype. 154 * @param theName 155 * the name of the dataset such as "dset1". 156 * @param thePath 157 * the group path to the dataset such as "/g0/". 158 * @param oid 159 * the oid of the dataset. 160 */ 161 @Deprecated 162 public H5Datatype(FileFormat theFile, String theName, String thePath, long[] oid) { 163 super(theFile, theName, thePath, oid); 164 objMetadata = new H5MetaDataContainer(theFile, theName, thePath, this); 165 166 if (theFile != null) { 167 if (oid == null) { 168 // retrieve the object ID 169 byte[] refBuf = null; 170 try { 171 refBuf = H5.H5Rcreate_object(theFile.getFID(), this.getFullName(), HDF5Constants.H5P_DEFAULT); 172 this.oid = HDFNativeData.byteToLong(refBuf); 173 log.trace("constructor REF {} to OID {}", refBuf, this.oid); 174 } 175 catch (Exception ex) { 176 log.debug("constructor ID {} for {} failed H5Rcreate_object", theFile.getFID(), this.getFullName()); 177 } 178 finally { 179 if (refBuf != null) 180 H5.H5Rdestroy(refBuf); 181 } 182 } 183 log.trace("constructor OID {}", this.oid); 184 try { 185 objInfo = H5.H5Oget_info_by_name(theFile.getFID(), this.getFullName(), HDF5Constants.H5O_INFO_BASIC, 186 HDF5Constants.H5P_DEFAULT); 187 } 188 catch (Exception ex) { 189 objInfo = new H5O_info_t(-1L, null, 0, 0, 0L, 0L, 0L, 0L, 0L); 190 } 191 192 long tid = HDF5Constants.H5I_INVALID_HID; 193 try { 194 tid = open(); 195 } 196 catch (Exception ex) { 197 log.debug("constructor H5Topen() failure"); 198 } 199 finally { 200 close(tid); 201 } 202 } 203 else { 204 this.oid = null; 205 objInfo = new H5O_info_t(-1L, null, 0, 0, 0L, 0L, 0L, 0L, 0L); 206 } 207 } 208 209 /** 210 * Constructs a Datatype with specified class, size, byte order and sign. The following is a list of a few examples 211 * of H5Datatype. 212 * <ol> 213 * <li>to create unsigned native integer<br> 214 * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, Datatype.NATIVE, Datatype.NATIVE, Datatype.SIGN_NONE); 215 * <li>to create 16-bit signed integer with big endian<br> 216 * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, 2, Datatype.ORDER_BE, Datatype.NATIVE); 217 * <li>to create native float<br> 218 * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE, Datatype.NATIVE); 219 * <li>to create 64-bit double<br> 220 * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE, Datatype.NATIVE); 221 * </ol> 222 * 223 * @param tclass 224 * the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc. 225 * @param tsize 226 * the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4. Valid values are 227 * NATIVE or a positive value. For string datatypes, -1 is also a valid value (to create a 228 * variable-length string). 229 * @param torder 230 * the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX, ORDER_NONE and 231 * NATIVE. 232 * @param tsign 233 * the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE. 234 * @throws Exception 235 * if there is an error 236 */ 237 public H5Datatype(int tclass, int tsize, int torder, int tsign) throws Exception { 238 this(tclass, tsize, torder, tsign, null); 239 } 240 241 /** 242 * Constructs a Datatype with specified class, size, byte order and sign. The following is a list of a few examples 243 * of H5Datatype. 244 * <ol> 245 * <li>to create unsigned native integer<br> 246 * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, Datatype.NATIVE, Datatype.NATIVE, Datatype.SIGN_NONE); 247 * <li>to create 16-bit signed integer with big endian<br> 248 * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, 2, Datatype.ORDER_BE, Datatype.NATIVE); 249 * <li>to create native float<br> 250 * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE, Datatype.NATIVE); 251 * <li>to create 64-bit double<br> 252 * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE, Datatype.NATIVE); 253 * </ol> 254 * 255 * @param tclass 256 * the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc. 257 * @param tsize 258 * the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4. Valid values are 259 * NATIVE or a positive value. For string datatypes, -1 is also a valid value (to create a 260 * variable-length string). 261 * @param torder 262 * the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX, ORDER_NONE and 263 * NATIVE. 264 * @param tsign 265 * the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE. 266 * @param tbase 267 * the base datatype of the new datatype 268 * @throws Exception 269 * if there is an error 270 */ 271 public H5Datatype(int tclass, int tsize, int torder, int tsign, Datatype tbase) throws Exception { 272 this(tclass, tsize, torder, tsign, tbase, null); 273 } 274 275 /** 276 * Constructs a Datatype with specified class, size, byte order and sign. The following is a list of a few examples 277 * of H5Datatype. 278 * <ol> 279 * <li>to create unsigned native integer<br> 280 * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, Datatype.NATIVE, Datatype.NATIVE, Datatype.SIGN_NONE); 281 * <li>to create 16-bit signed integer with big endian<br> 282 * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, 2, Datatype.ORDER_BE, Datatype.NATIVE); 283 * <li>to create native float<br> 284 * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE, Datatype.NATIVE); 285 * <li>to create 64-bit double<br> 286 * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE, Datatype.NATIVE); 287 * </ol> 288 * 289 * @param tclass 290 * the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc. 291 * @param tsize 292 * the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4. Valid values are 293 * NATIVE or a positive value. For string datatypes, -1 is also a valid value (to create a 294 * variable-length string). 295 * @param torder 296 * the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX, ORDER_NONE and 297 * NATIVE. 298 * @param tsign 299 * the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE. 300 * @param tbase 301 * the base datatype of the new datatype 302 * @param pbase 303 * the parent datatype of the new datatype 304 * @throws Exception 305 * if there is an error 306 */ 307 public H5Datatype(int tclass, int tsize, int torder, int tsign, Datatype tbase, Datatype pbase) throws Exception { 308 super(tclass, tsize, torder, tsign, tbase, pbase); 309 datatypeDescription = getDescription(); 310 } 311 312 /** 313 * Constructs a Datatype with a given native datatype identifier. For example, if the datatype identifier is a 314 * 32-bit unsigned integer created from HDF5, 315 * 316 * <pre> 317 * int tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_UNINT32); 318 * Datatype dtype = new Datatype(tid); 319 * </pre> 320 * 321 * will construct a datatype equivalent to new Datatype(Datatype.CLASS_INTEGER, 4, Datatype.NATIVE, 322 * Datatype.SIGN_NONE); 323 * 324 * @see #fromNative(long nativeID) 325 * @param theFile 326 * the file that contains the datatype. 327 * @param nativeID 328 * the native datatype identifier. 329 * @throws Exception 330 * if there is an error 331 */ 332 public H5Datatype(FileFormat theFile, long nativeID) throws Exception { 333 this(theFile, nativeID, null); 334 } 335 336 /** 337 * Constructs a Datatype with a given native datatype identifier. For example, if the datatype identifier is a 338 * 32-bit unsigned integer created from HDF5, 339 * 340 * <pre> 341 * int tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_UNINT32); 342 * Datatype dtype = new Datatype(tid); 343 * </pre> 344 * 345 * will construct a datatype equivalent to new Datatype(Datatype.CLASS_INTEGER, 4, Datatype.NATIVE, 346 * Datatype.SIGN_NONE); 347 * 348 * @see #fromNative(long nativeID) 349 * @param theFile 350 * the file that contains the datatype. 351 * @param nativeID 352 * the native datatype identifier. 353 * @param pbase 354 * the parent datatype of the new datatype 355 * @throws Exception 356 * if there is an error 357 */ 358 public H5Datatype(FileFormat theFile, long nativeID, Datatype pbase) throws Exception { 359 super(theFile, nativeID, pbase); 360 fromNative(nativeID); 361 datatypeDescription = getDescription(); 362 } 363 364 /** 365 * Opens access to a named datatype. It calls H5.H5Topen(loc, name). 366 * 367 * @return the datatype identifier if successful; otherwise returns negative value. 368 * @see hdf.hdf5lib.H5#H5Topen(long, String, long) 369 */ 370 @Override 371 public long open() { 372 long tid = HDF5Constants.H5I_INVALID_HID; 373 374 if (fileFormat != null) { 375 try { 376 tid = H5.H5Topen(getFID(), getFullName(), HDF5Constants.H5P_DEFAULT); 377 fromNative(tid); 378 log.trace("open(): tid={}", tid); 379 } 380 catch (HDF5Exception ex) { 381 log.debug("open(): Failed to open datatype {}", getFullName(), ex); 382 tid = HDF5Constants.H5I_INVALID_HID; 383 } 384 } 385 386 return tid; 387 } 388 389 /** 390 * Closes a datatype identifier. It calls H5.H5close(tid). 391 * 392 * @param tid 393 * the datatype ID to close 394 */ 395 @Override 396 public void close(long tid) { 397 if (tid >= 0) { 398 try { 399 H5.H5Tclose(tid); 400 } 401 catch (HDF5Exception ex) { 402 log.debug("close(): H5Tclose(tid {}) failure: ", tid, ex); 403 } 404 } 405 } 406 407 /** 408 * Get the token for this object. 409 * 410 * @return true if it has any attributes, false otherwise. 411 */ 412 public long[] getToken() { 413 H5O_token_t token = objInfo.token; 414 return HDFNativeData.byteToLong(token.data); 415 } 416 417 /** 418 * Check if the object has any attributes attached. 419 * 420 * @return true if it has any attributes, false otherwise. 421 */ 422 @Override 423 public boolean hasAttribute() { 424 objInfo.num_attrs = objMetadata.getObjectAttributeSize(); 425 426 if (objInfo.num_attrs < 0) { 427 long tid = open(); 428 if (tid > 0) { 429 try { 430 objInfo = H5.H5Oget_info(tid); 431 } 432 catch (Exception ex) { 433 objInfo.num_attrs = 0; 434 log.debug("hasAttribute(): get object info failure: ", ex); 435 } 436 finally { 437 close(tid); 438 } 439 objMetadata.setObjectAttributeSize((int) objInfo.num_attrs); 440 } 441 else { 442 log.debug("hasAttribute(): could not open group"); 443 } 444 } 445 446 log.trace("hasAttribute(): nAttributes={}", objInfo.num_attrs); 447 return (objInfo.num_attrs > 0); 448 } 449 450 /** 451 * Converts values in an Enumeration Datatype to names. This method searches the identified enumeration datatype for 452 * the values appearing in <code>inValues</code> and returns the names corresponding to those values. If a given 453 * value is not found in the enumeration datatype, the name corresponding to that value will be set to 454 * <code>"ENUM ERR value"</code> in the string array that is returned. If the method fails in general, null will be 455 * returned instead of a String array. An empty <code>inValues</code> parameter would cause general failure. 456 * 457 * @param inValues 458 * The array of enumerations values to be converted. 459 * @return The string array of names if successful; otherwise return null. 460 * @throws HDF5Exception 461 * If there is an error at the HDF5 library level. 462 */ 463 public String[] convertEnumValueToName(Object inValues) 464 throws HDF5Exception { 465 log.trace("convertEnumValueToName() inValues={} start", inValues); 466 467 if (inValues == null) { 468 log.debug("convertEnumValueToName() failure: in values null "); 469 return null; 470 } 471 472 int inSize = 0; 473 String[] outNames = null; 474 String cName = inValues.getClass().getName(); 475 boolean isArray = cName.lastIndexOf('[') >= 0; 476 if (isArray) 477 inSize = Array.getLength(inValues); 478 else 479 inSize = 1; 480 481 if (inSize <= 0) { 482 log.debug("convertEnumValueToName() failure: inSize length invalid"); 483 log.debug("convertEnumValueToName(): inValues={} inSize={}", inValues, inSize); 484 return null; 485 } 486 487 if (enumMembers == null 488 || enumMembers.size() <= 0) { 489 log.debug("convertEnumValueToName(): no members"); 490 return null; 491 } 492 493 log.trace("convertEnumValueToName(): inSize={} nMembers={} enums={}", inSize, enumMembers.size(), enumMembers); 494 outNames = new String[inSize]; 495 for (int i = 0; i < inSize; i++) { 496 if (isArray) { 497 if (enumMembers.containsKey(String.valueOf(Array.get(inValues, i)))) 498 outNames[i] = enumMembers.get(String.valueOf(Array.get(inValues, i))); 499 else 500 outNames[i] = "**ENUM ERR " + Array.get(inValues, i) + "**"; 501 } 502 else { 503 if (enumMembers.containsKey(String.valueOf(inValues))) 504 outNames[i] = enumMembers.get(String.valueOf(inValues)); 505 else 506 outNames[i] = "**ENUM ERR " + inValues + "**"; 507 } 508 } 509 510 return outNames; 511 } 512 513 /** 514 * Converts names in an Enumeration Datatype to values. This method searches the identified enumeration datatype for 515 * the names appearing in <code>inValues</code> and returns the values corresponding to those names. 516 * 517 * @param in 518 * The array of enumerations names to be converted. 519 * @return The int array of values if successful; otherwise return null. 520 * @throws HDF5Exception 521 * If there is an error at the HDF5 library level. 522 */ 523 public Object[] convertEnumNameToValue(String[] in) 524 throws HDF5Exception { 525 int size = 0; 526 527 if (in == null) { 528 log.debug("convertEnumNameToValue() failure: in values null"); 529 return null; 530 } 531 532 if ((size = Array.getLength(in)) <= 0) { 533 log.debug("convertEnumNameToValue() failure: in size not valid"); 534 return null; 535 } 536 537 if (enumMembers == null 538 || enumMembers.size() <= 0) { 539 log.debug("convertEnumNameToValue(): no members"); 540 return null; 541 } 542 543 Object[] out = null; 544 if (datatypeSize == 1) 545 out = new Byte[size]; 546 else if (datatypeSize == 2) 547 out = new Short[size]; 548 else if (datatypeSize == 4) 549 out = new Integer[size]; 550 else if (datatypeSize == 8) 551 out = new Long[size]; 552 else 553 out = new Object[size]; 554 555 for (int i = 0; i < size; i++) { 556 if (in[i] == null 557 || in[i].length() <= 0) 558 continue; 559 560 for (Entry<String, String> entry : enumMembers.entrySet()) { 561 if (Objects.equals(in[i], entry.getValue())) { 562 if (datatypeSize == 1) { 563 log.trace("convertEnumNameToValue(): ENUM is H5T_NATIVE_INT8"); 564 out[i] = Byte.parseByte(entry.getKey()); 565 } 566 else if (datatypeSize == 2) { 567 log.trace("convertEnumNameToValue(): CLASS_INT-ENUM is H5T_NATIVE_INT16"); 568 out[i] = Short.parseShort(entry.getKey()); 569 } 570 else if (datatypeSize == 4) { 571 log.trace("convertEnumNameToValue(): CLASS_INT-ENUM is H5T_NATIVE_INT32"); 572 out[i] = Integer.parseInt(entry.getKey()); 573 } 574 else if (datatypeSize == 8) { 575 log.trace("convertEnumNameToValue(): CLASS_INT-ENUM is H5T_NATIVE_INT64"); 576 out[i] = Long.parseLong(entry.getKey()); 577 } 578 else { 579 log.debug("convertEnumNameToValue(): enum datatypeSize incorrect"); 580 out[i] = -1; 581 } 582 break; 583 } 584 } 585 } 586 587 return out; 588 } 589 590 /** 591 * Convert from an array of BigDecimal into an array of bytes 592 * 593 * @param start 594 * The position in the input array of BigDecimal to start 595 * @param len 596 * The number of 'BigDecimal' to convert 597 * @param data 598 * The input array of BigDecimal 599 * @return an array of bytes 600 */ 601 public byte[] bigDecimalToByte(int start, int len, BigDecimal[] data) { 602 int ii; 603 byte[] bd = new byte[(int) datatypeSize]; 604 byte[] bdconv = new byte[(int) datatypeSize]; 605 byte[] bdbytes = new byte[(int) datatypeSize * len]; 606 607 for (ii = 0; ii < len; ii++) { 608 BigDecimal entry = data[start + ii]; 609 bdconv = convertBigDecimalToByte(entry); 610 /* bitsets operate assuming LE order, BigInteger/BigDecimal expect BE */ 611 if (datatypeOrder == ORDER_BE) { 612 int k = 0; 613 for (int j = (int) datatypeSize - 1; j >= 0; j--) 614 bd[k++] = bdconv[j]; 615 } 616 else { 617 try { 618 System.arraycopy(bdconv, 0, bd, 0, (int) datatypeSize); 619 } 620 catch (Exception err) { 621 log.trace("bigDecimalToByte(): arraycopy failure: ", err); 622 } 623 } 624 try { 625 System.arraycopy(bd, 0, bdbytes, ii * 16, 16); 626 } 627 catch (Exception err) { 628 log.trace("bigDecimalToByte(): arraycopy failure: ", err); 629 } 630 } 631 return bdbytes; 632 } 633 634 /** 635 * Convert from a single BigDecimal object from an array of BigDecimal into an array of bytes 636 * 637 * @param start 638 * The position in the input array of BigDecimal to start 639 * @param data 640 * The input Float 641 * @return an array of bytes 642 */ 643 public byte[] bigDecimalToByte(BigDecimal[] data, int start) { 644 byte[] bdbytes = new byte[(int) datatypeSize]; 645 bdbytes = bigDecimalToByte(start, 1, data); 646 return bdbytes; 647 } 648 649 /** 650 * Convert a BigDecimal to a byte array . 651 * 652 * @param num 653 * The BigDecimal number to convert 654 * @return A byte array representing the BigDecimal. 655 */ 656 public byte[] convertBigDecimalToByte(BigDecimal num) { 657 BigInteger sig = new BigInteger(num.unscaledValue().toString()); 658 byte[] bsig = sig.toByteArray(); 659 int scale = num.scale(); 660 byte[] bscale = new byte[] { (byte) (scale >>> 24), (byte) (scale >>> 16), (byte) (scale >>> 8), 661 (byte) (scale) }; 662 byte[] both = new byte[bscale.length + bsig.length]; 663 try { 664 System.arraycopy(bscale, 0, both, 0, bscale.length); 665 System.arraycopy(bsig, 0, both, bscale.length, bsig.length); 666 } 667 catch (Exception err) { 668 log.trace("convertBigDecimalToByte(): arraycopy failure: ", err); 669 } 670 return both; 671 } 672 673 /** 674 * Convert a range from an array of bytes into an array of BigDecimal 675 * 676 * @param start 677 * The position in the input array of bytes to start 678 * @param len 679 * The number of 'BigDecimal' to convert 680 * @param data 681 * The input array of bytes 682 * @return an array of 'len' BigDecimal 683 */ 684 public BigDecimal[] byteToBigDecimal(int start, int len, byte[] data) { 685 int ii; 686 byte[] bd = new byte[(int) datatypeSize]; 687 BigDecimal[] BDarray = new BigDecimal[len]; 688 689 for (ii = 0; ii < len; ii++) { 690 int rawpos = (start + ii) * (int) datatypeSize; 691 /* bitsets operate assuming LE order, BigInteger/BigDecimal expect BE */ 692 if (datatypeOrder == ORDER_BE) { 693 int k = 0; 694 for (int j = (int) datatypeSize - 1; j >= 0; j--) 695 bd[k++] = data[rawpos + j]; 696 } 697 else { 698 try { 699 System.arraycopy(data, rawpos, bd, 0, (int) datatypeSize); 700 } 701 catch (Exception err) { 702 log.trace("byteToBigDecimal(): arraycopy failure: ", err); 703 } 704 } 705 BDarray[ii] = convertByteToBigDecimal(bd); 706 } 707 return BDarray; 708 } 709 710 /** 711 * Convert 4 bytes from an array of bytes into a single BigDecimal 712 * 713 * @param start 714 * The position in the input array of bytes to start 715 * @param data 716 * The input array of bytes 717 * @return The BigDecimal value of the bytes. 718 */ 719 public BigDecimal byteToBigDecimal(byte[] data, int start) { 720 BigDecimal[] bdval = new BigDecimal[1]; 721 bdval = byteToBigDecimal(start, 1, data); 722 return (bdval[0]); 723 } 724 725 /** 726 * Convert byte array data to a BigDecimal. 727 * 728 * @param raw 729 * The byte array to convert to a BigDecimal 730 * @return A BigDecimal representing the byte array. 731 */ 732 public BigDecimal convertByteToBigDecimal(byte[] raw) { 733 BitSet rawset = BitSet.valueOf(raw); 734 735 boolean sign = rawset.get(nativeOffset + (int) nativeFPspos); 736 BitSet mantissaset = rawset.get(nativeOffset + (int) nativeFPmpos, 737 nativeOffset + (int) nativeFPmpos + (int) nativeFPmsize); 738 BitSet exponentset = rawset.get(nativeOffset + (int) nativeFPepos, 739 nativeOffset + (int) nativeFPepos + (int) nativeFPesize); 740 byte[] expraw = Arrays.copyOf(exponentset.toByteArray(), (int) (nativeFPesize + 7) / 8); 741 byte[] bexp = new byte[expraw.length]; 742 /* bitsets operate assuming LE order, BigInteger/BigDecimal expect BE */ 743 if (datatypeOrder == ORDER_LE) { 744 int k = 0; 745 for (int j = expraw.length - 1; j >= 0; j--) 746 bexp[k++] = expraw[j]; 747 } 748 else { 749 try { 750 System.arraycopy(expraw, 0, bexp, 0, expraw.length); 751 } 752 catch (Exception err) { 753 log.trace("convertByteToBigDecimal(): arraycopy failure: ", err); 754 } 755 } 756 BigInteger bscale = new BigInteger(bexp); 757 long scale = bscale.longValue(); 758 scale -= nativeFPebias; 759 double powscale = Math.pow(2, scale); 760 761 byte[] manraw = Arrays.copyOf(mantissaset.toByteArray(), (int) (nativeFPmsize + 7) / 8); 762 byte[] bman = new byte[manraw.length]; 763 /* bitsets operate assuming LE order, BigInteger/BigDecimal expect BE */ 764 if (datatypeOrder == ORDER_BE) { 765 int k = 0; 766 for (int j = manraw.length - 1; j >= 0; j--) 767 bman[k++] = manraw[j]; 768 } 769 else { 770 try { 771 System.arraycopy(manraw, 0, bman, 0, manraw.length); 772 } 773 catch (Exception err) { 774 log.trace("convertByteToBigDecimal(): arraycopy failure: ", err); 775 } 776 } 777 BitSet manset = BitSet.valueOf(bman); 778 779 // calculate mantissa value 780 double val = 0.0; 781 for (int i = 0; i < (int) nativeFPmsize; i++) { 782 if (manset.get((int) nativeFPmsize - 1 - i)) 783 val += Math.pow(2, -(i)); 784 } 785 if (nativeFPnorm == HDF5Constants.H5T_NORM_IMPLIED 786 || nativeFPnorm == HDF5Constants.H5T_NORM_MSBSET) 787 val += 1; 788 BigDecimal sig = BigDecimal.valueOf(val); 789 if (sign) 790 sig.negate(MathContext.DECIMAL128); 791 return sig.multiply(new BigDecimal(powscale, MathContext.DECIMAL128)); 792 } 793 794 /* 795 * (non-Javadoc) 796 * @see hdf.object.Datatype#fromNative(int) 797 */ 798 @Override 799 public void fromNative(long tid) { 800 log.trace("fromNative(): start: tid={}", tid); 801 long tsize = -1; 802 int torder = -1; 803 boolean isChar = false; 804 boolean isUchar = false; 805 806 if (tid < 0) { 807 datatypeClass = CLASS_NO_CLASS; 808 } 809 else { 810 try { 811 nativeClass = H5.H5Tget_class(tid); 812 tsize = H5.H5Tget_size(tid); 813 isVariableStr = H5.H5Tis_variable_str(tid); 814 isVLEN = false; 815 log.trace("fromNative(): tclass={}, tsize={}, torder={}, isVLEN={}", nativeClass, tsize, torder, 816 isVLEN); 817 if (H5.H5Tcommitted(tid)) { 818 isNamed = true; 819 try { 820 setFullname(null, H5.H5Iget_name(tid)); 821 } 822 catch (Exception nex) { 823 log.debug("fromNative(): setName failure: {}", nex.getMessage()); 824 } 825 log.trace("fromNative(): path={} name={}", this.getPath(), this.getName()); 826 } 827 log.trace("fromNative(): isNamed={}", isNamed()); 828 } 829 catch (Exception ex) { 830 log.debug("fromNative(): failure: ", ex); 831 datatypeClass = CLASS_NO_CLASS; 832 } 833 834 try { 835 isUchar = H5.H5Tequal(tid, HDF5Constants.H5T_NATIVE_UCHAR); 836 isChar = (H5.H5Tequal(tid, HDF5Constants.H5T_NATIVE_CHAR) 837 || isUchar); 838 log.trace("fromNative(): tclass={}, tsize={}, torder={}, isUchar={}, isChar={}", nativeClass, tsize, 839 torder, isUchar, isChar); 840 } 841 catch (Exception ex) { 842 log.debug("fromNative(): native char type failure: ", ex); 843 } 844 845 datatypeOrder = HDF5Constants.H5T_ORDER_NONE; 846 boolean IsAtomic = datatypeClassIsAtomic(nativeClass); 847 if (IsAtomic 848 || (nativeClass == HDF5Constants.H5T_COMPOUND)) { 849 try { 850 torder = H5.H5Tget_order(tid); 851 datatypeOrder = (torder == HDF5Constants.H5T_ORDER_BE) ? ORDER_BE : ORDER_LE; 852 } 853 catch (Exception ex) { 854 log.debug("fromNative(): get_order failure: ", ex); 855 } 856 } 857 858 if (IsAtomic 859 && !datatypeClassIsOpaque(nativeClass)) { 860 try { 861 nativePrecision = H5.H5Tget_precision_long(tid); 862 } 863 catch (Exception ex) { 864 log.debug("fromNative(): get_precision failure: ", ex); 865 } 866 867 try { 868 nativeOffset = H5.H5Tget_offset(tid); 869 } 870 catch (Exception ex) { 871 log.debug("fromNative(): get_offset failure: ", ex); 872 } 873 874 try { 875 int[] pads = new int[2]; 876 H5.H5Tget_pad(tid, pads); 877 nativePadLSB = pads[0]; 878 nativePadMSB = pads[1]; 879 } 880 catch (Exception ex) { 881 log.debug("fromNative(): get_pad failure: ", ex); 882 } 883 } 884 885 log.trace("fromNative(): isUchar={}, nativePrecision={}, nativeOffset={}, nativePadLSB={}, nativePadMSB={}", 886 isUchar, nativePrecision, nativeOffset, nativePadLSB, nativePadMSB); 887 888 datatypeSign = NATIVE; // default 889 if (nativeClass == HDF5Constants.H5T_ARRAY) { 890 long tmptid = HDF5Constants.H5I_INVALID_HID; 891 datatypeClass = CLASS_ARRAY; 892 try { 893 int ndims = H5.H5Tget_array_ndims(tid); 894 arrayDims = new long[ndims]; 895 H5.H5Tget_array_dims(tid, arrayDims); 896 897 tmptid = H5.H5Tget_super(tid); 898 int nativeBaseClass = H5.H5Tget_class(tmptid); 899 if (nativeBaseClass == HDF5Constants.H5T_REFERENCE) 900 baseType = new H5ReferenceType(this.fileFormat, 1, tmptid); 901 else 902 baseType = new H5Datatype(this.fileFormat, tmptid, this); 903 if (baseType == null) { 904 log.debug("fromNative(): ARRAY datatype has null base type"); 905 throw new Exception("Datatype (ARRAY) has no base datatype"); 906 } 907 908 datatypeSign = baseType.getDatatypeSign(); 909 } 910 catch (Exception ex) { 911 log.debug("fromNative(): array type failure: ", ex); 912 } 913 finally { 914 close(tmptid); 915 } 916 } 917 else if (nativeClass == HDF5Constants.H5T_COMPOUND) { 918 datatypeClass = CLASS_COMPOUND; 919 920 try { 921 int nMembers = H5.H5Tget_nmembers(tid); 922 compoundMemberNames = new Vector<>(nMembers); 923 compoundMemberTypes = new Vector<>(nMembers); 924 compoundMemberOffsets = new Vector<>(nMembers); 925 log.trace("fromNative(): compound type nMembers={} start", nMembers); 926 927 for (int i = 0; i < nMembers; i++) { 928 String memberName = H5.H5Tget_member_name(tid, i); 929 log.trace("fromNative(): compound type [{}] name={} start", i, memberName); 930 long memberOffset = H5.H5Tget_member_offset(tid, i); 931 long memberID = HDF5Constants.H5I_INVALID_HID; 932 H5Datatype membertype = null; 933 try { 934 memberID = H5.H5Tget_member_type(tid, i); 935 int nativeMemberClass = H5.H5Tget_class(memberID); 936 if (nativeMemberClass == HDF5Constants.H5T_REFERENCE) 937 membertype = new H5ReferenceType(this.fileFormat, 1, memberID); 938 else 939 membertype = new H5Datatype(this.fileFormat, memberID, this); 940 } 941 catch (Exception ex1) { 942 log.debug("fromNative(): compound type failure: ", ex1); 943 } 944 finally { 945 close(memberID); 946 } 947 948 compoundMemberNames.add(i, memberName); 949 compoundMemberOffsets.add(i, memberOffset); 950 compoundMemberTypes.add(i, membertype); 951 } 952 } 953 catch (HDF5LibraryException ex) { 954 log.debug("fromNative(): compound type failure: ", ex); 955 } 956 } 957 else if (nativeClass == HDF5Constants.H5T_INTEGER) { 958 datatypeClass = CLASS_INTEGER; 959 try { 960 log.trace("fromNative(): integer type"); 961 int tsign = H5.H5Tget_sign(tid); 962 datatypeSign = (tsign == HDF5Constants.H5T_SGN_NONE) ? SIGN_NONE : SIGN_2; 963 } 964 catch (Exception ex) { 965 log.debug("fromNative(): int type failure: ", ex); 966 } 967 } 968 else if (nativeClass == HDF5Constants.H5T_FLOAT) { 969 datatypeClass = CLASS_FLOAT; 970 try { 971 nativeFPebias = H5.H5Tget_ebias_long(tid); 972 } 973 catch (Exception ex) { 974 log.debug("fromNative(): get_ebias failure: ", ex); 975 } 976 try { 977 long[] fields = new long[5]; 978 H5.H5Tget_fields(tid, fields); 979 nativeFPspos = fields[0]; 980 nativeFPepos = fields[1]; 981 nativeFPesize = fields[2]; 982 nativeFPmpos = fields[3]; 983 nativeFPmsize = fields[4]; 984 } 985 catch (Exception ex) { 986 log.debug("fromNative(): get_fields failure: ", ex); 987 } 988 try { 989 nativeFPnorm = H5.H5Tget_norm(tid); 990 } 991 catch (Exception ex) { 992 log.debug("fromNative(): get_norm failure: ", ex); 993 } 994 try { 995 nativeFPinpad = H5.H5Tget_inpad(tid); 996 } 997 catch (Exception ex) { 998 log.debug("fromNative(): get_inpad failure: ", ex); 999 } 1000 } 1001 else if (isChar) { 1002 datatypeClass = CLASS_CHAR; 1003 datatypeSign = (isUchar) ? SIGN_NONE : SIGN_2; 1004 log.trace("fromNative(): CLASS_CHAR:datatypeSign={}", datatypeSign); 1005 } 1006 else if (nativeClass == HDF5Constants.H5T_STRING) { 1007 datatypeClass = CLASS_STRING; 1008 try { 1009 isVLEN = H5.H5Tdetect_class(tid, HDF5Constants.H5T_VLEN) 1010 || isVariableStr; 1011 log.trace("fromNative(): H5T_STRING:var str type={}", isVLEN); 1012 nativeStrPad = H5.H5Tget_strpad(tid); 1013 } 1014 catch (Exception ex) { 1015 log.debug("fromNative(): var str type failure: ", ex); 1016 } 1017 try { 1018 nativeStrCSET = H5.H5Tget_cset(tid); 1019 } 1020 catch (Exception ex) { 1021 log.debug("fromNative(): H5T_STRING:get_cset failure: ", ex); 1022 } 1023 log.trace("fromNative(): H5T_STRING:nativeStrPad={}, nativeStrCSET={}", nativeStrPad, nativeStrCSET); 1024 } 1025 else if (nativeClass == HDF5Constants.H5T_REFERENCE) { 1026 datatypeClass = CLASS_REFERENCE; 1027 log.trace("fromNative(): reference type"); 1028 try { 1029 isStdRef = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF); 1030 log.trace("fromNative(): reference type is orig StdRef:{}", isStdRef); 1031 if (H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF)) 1032 tsize = HDF5Constants.H5R_REF_BUF_SIZE; 1033 } 1034 catch (Exception ex) { 1035 log.debug("fromNative(): H5T_STD_REF: ", ex); 1036 } 1037 try { 1038 isRegRef = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF_DSETREG); 1039 log.trace("fromNative(): reference type isRegRef:{}", isRegRef); 1040 if (isRegRef) 1041 tsize = HDF5Constants.H5R_DSET_REG_REF_BUF_SIZE; 1042 } 1043 catch (Exception ex) { 1044 log.debug("fromNative(): H5T_STD_REF_DSETREG: ", ex); 1045 } 1046 try { 1047 isRefObj = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF_OBJ); 1048 log.trace("fromNative(): reference type isRefObj:{}", isRefObj); 1049 if (isRefObj) 1050 tsize = HDF5Constants.H5R_OBJ_REF_BUF_SIZE; 1051 } 1052 catch (Exception ex) { 1053 log.debug("fromNative(): H5T_STD_REF_OBJ: ", ex); 1054 } 1055 } 1056 else if (nativeClass == HDF5Constants.H5T_ENUM) { 1057 datatypeClass = CLASS_ENUM; 1058 long tmptid = HDF5Constants.H5I_INVALID_HID; 1059 long basetid = HDF5Constants.H5I_INVALID_HID; 1060 try { 1061 log.trace("fromNative(): enum type"); 1062 basetid = H5.H5Tget_super(tid); 1063 tmptid = basetid; 1064 basetid = H5.H5Tget_native_type(tmptid); 1065 log.trace("fromNative(): enum type basetid={}", basetid); 1066 if (basetid >= 0) { 1067 baseType = new H5Datatype(this.fileFormat, tmptid, this); 1068 datatypeSign = baseType.getDatatypeSign(); 1069 } 1070 } 1071 catch (Exception ex) { 1072 log.debug("fromNative(): enum type failure: ", ex); 1073 } 1074 finally { 1075 close(tmptid); 1076 close(basetid); 1077 } 1078 try { 1079 int enumMemberCount = H5.H5Tget_nmembers(tid); 1080 String name = null; 1081 String enumStr = null; 1082 byte[] val = new byte[(int) tsize]; 1083 enumMembers = new HashMap<>(); 1084 for (int i = 0; i < enumMemberCount; i++) { 1085 name = H5.H5Tget_member_name(tid, i); 1086 H5.H5Tget_member_value(tid, i, val); 1087 switch ((int) H5.H5Tget_size(tid)) { 1088 case 1: 1089 enumStr = Byte.toString((HDFNativeData.byteToByte(val[0]))[0]); 1090 break; 1091 case 2: 1092 enumStr = Short.toString((HDFNativeData.byteToShort(val))[0]); 1093 break; 1094 case 4: 1095 enumStr = Integer.toString((HDFNativeData.byteToInt(val))[0]); 1096 break; 1097 case 8: 1098 enumStr = Long.toString((HDFNativeData.byteToLong(val))[0]); 1099 break; 1100 default: 1101 enumStr = "-1"; 1102 break; 1103 } 1104 enumMembers.put(enumStr, name); 1105 } 1106 } 1107 catch (Exception ex) { 1108 log.debug("fromNative(): enum type failure: ", ex); 1109 } 1110 } 1111 else if (nativeClass == HDF5Constants.H5T_VLEN) { 1112 long tmptid = HDF5Constants.H5I_INVALID_HID; 1113 datatypeClass = CLASS_VLEN; 1114 isVLEN = true; 1115 try { 1116 log.trace("fromNative(): vlen type"); 1117 tmptid = H5.H5Tget_super(tid); 1118 int nativeBaseClass = H5.H5Tget_class(tmptid); 1119 if (nativeBaseClass == HDF5Constants.H5T_REFERENCE) 1120 baseType = new H5ReferenceType(this.fileFormat, 1, tmptid); 1121 else 1122 baseType = new H5Datatype(this.fileFormat, tmptid, this); 1123 if (baseType == null) { 1124 log.debug("fromNative(): VLEN datatype has null base type"); 1125 throw new Exception("Datatype (VLEN) has no base datatype"); 1126 } 1127 1128 datatypeSign = baseType.getDatatypeSign(); 1129 } 1130 catch (Exception ex) { 1131 log.debug("fromNative(): vlen type failure: ", ex); 1132 } 1133 finally { 1134 close(tmptid); 1135 } 1136 } 1137 else if (nativeClass == HDF5Constants.H5T_BITFIELD) { 1138 datatypeClass = CLASS_BITFIELD; 1139 } 1140 else if (nativeClass == HDF5Constants.H5T_OPAQUE) { 1141 datatypeClass = CLASS_OPAQUE; 1142 1143 try { 1144 opaqueTag = H5.H5Tget_tag(tid); 1145 } 1146 catch (Exception ex) { 1147 log.debug("fromNative(): opaque type tag retrieval failed: ", ex); 1148 opaqueTag = null; 1149 } 1150 } 1151 else { 1152 log.debug("fromNative(): datatypeClass is unknown"); 1153 } 1154 1155 datatypeSize = (isVLEN 1156 && !isVariableStr) ? HDF5Constants.H5T_VL_T : tsize; 1157 } 1158 if (datatypeSize == NATIVE) 1159 datatypeNATIVE = true; 1160 else 1161 datatypeNATIVE = false; 1162 log.trace("fromNative(): datatypeClass={} baseType={} datatypeSize={}", datatypeClass, baseType, datatypeSize); 1163 } 1164 1165 /** 1166 * @param tid 1167 * the datatype identification disk. 1168 * @return the memory datatype identifier if successful, and negative otherwise. 1169 */ 1170 public static long toNative(long tid) { 1171 // data type information 1172 log.trace("toNative(): tid={} start", tid); 1173 long nativeID = HDF5Constants.H5I_INVALID_HID; 1174 1175 try { 1176 nativeID = H5.H5Tget_native_type(tid); 1177 } 1178 catch (Exception ex) { 1179 log.debug("toNative(): H5Tget_native_type(tid {}) failure: ", tid, ex); 1180 } 1181 1182 try { 1183 if (H5.H5Tis_variable_str(tid)) 1184 H5.H5Tset_size(nativeID, HDF5Constants.H5T_VARIABLE); 1185 } 1186 catch (Exception ex) { 1187 log.debug("toNative(): var str type size failure: ", ex); 1188 } 1189 1190 return nativeID; 1191 } 1192 1193 /* 1194 * (non-Javadoc) 1195 * @see hdf.object.Datatype#createNative() 1196 */ 1197 @SuppressWarnings("rawtypes") 1198 @Override 1199 public long createNative() { 1200 long tid = HDF5Constants.H5I_INVALID_HID; 1201 long tmptid = HDF5Constants.H5I_INVALID_HID; 1202 1203 String the_path = getFullName(); 1204 // isNamed == true should have non-null fileFormat 1205 if (isNamed()) { 1206 try { 1207 tid = H5.H5Topen(getFID(), the_path, HDF5Constants.H5P_DEFAULT); 1208 } 1209 catch (Exception ex) { 1210 log.debug("createNative(): name {} H5Topen failure: ", the_path, ex); 1211 } 1212 } 1213 else 1214 log.debug("createNative(): isNamed={} and named path={}", isNamed(), the_path); 1215 1216 if (tid >= 0) 1217 return tid; 1218 1219 log.trace("createNative(): datatypeClass={} datatypeSize={} baseType={}", datatypeClass, datatypeSize, 1220 baseType); 1221 1222 switch (datatypeClass) { 1223 case CLASS_ARRAY: 1224 try { 1225 if (baseType == null) { 1226 log.debug("createNative(): CLASS_ARRAY base type is NULL"); 1227 break; 1228 } 1229 1230 if ((tmptid = baseType.createNative()) < 0) { 1231 log.debug("createNative(): failed to create native datatype for ARRAY base datatype"); 1232 break; 1233 } 1234 1235 tid = H5.H5Tarray_create(tmptid, arrayDims.length, arrayDims); 1236 } 1237 catch (Exception ex) { 1238 log.debug("createNative(): native array datatype creation failed: ", ex); 1239 if (tid >= 0) 1240 close(tid); 1241 tid = HDF5Constants.H5I_INVALID_HID; 1242 } 1243 finally { 1244 close(tmptid); 1245 } 1246 1247 break; 1248 case CLASS_COMPOUND: 1249 try { 1250 tid = H5.H5Tcreate(CLASS_COMPOUND, datatypeSize); 1251 1252 for (int i = 0; i < compoundMemberTypes.size(); i++) { 1253 H5Datatype memberType = null; 1254 String memberName = null; 1255 long memberOffset = -1; 1256 1257 try { 1258 memberType = (H5Datatype) compoundMemberTypes.get(i); 1259 } 1260 catch (Exception ex) { 1261 log.debug("createNative(): get compound member[{}] type failure: ", i, ex); 1262 memberType = null; 1263 } 1264 1265 try { 1266 memberName = compoundMemberNames.get(i); 1267 } 1268 catch (Exception ex) { 1269 log.debug("createNative(): get compound member[{}] name failure: ", i, ex); 1270 memberName = null; 1271 } 1272 1273 try { 1274 memberOffset = compoundMemberOffsets.get(i); 1275 } 1276 catch (Exception ex) { 1277 log.debug("createNative(): get compound member[{}] offset failure: ", i, ex); 1278 memberOffset = -1; 1279 } 1280 1281 long memberID = HDF5Constants.H5I_INVALID_HID; 1282 try { 1283 memberID = memberType.createNative(); 1284 log.trace("createNative(): {} member[{}] with offset={} ID={}: ", memberName, i, memberOffset, 1285 memberID); 1286 1287 H5.H5Tinsert(tid, memberName, memberOffset, memberID); 1288 } 1289 catch (Exception ex) { 1290 log.debug("createNative(): compound type member[{}] insertion failure: ", i, ex); 1291 } 1292 finally { 1293 close(memberID); 1294 } 1295 } 1296 } 1297 catch (Exception ex) { 1298 log.debug("createNative(): native compound datatype creation failed: ", ex); 1299 if (tid >= 0) 1300 close(tid); 1301 tid = HDF5Constants.H5I_INVALID_HID; 1302 } 1303 break; 1304 case CLASS_INTEGER: 1305 log.trace("createNative(): CLASS_INT of size {}", datatypeSize); 1306 1307 try { 1308 switch ((int) datatypeSize) { 1309 case 1: 1310 log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT8"); 1311 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT8); 1312 break; 1313 case 2: 1314 log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT16"); 1315 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT16); 1316 break; 1317 case 4: 1318 log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT32"); 1319 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT32); 1320 break; 1321 case 8: 1322 log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT64"); 1323 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT64); 1324 break; 1325 default: 1326 if (datatypeSize == NATIVE) { 1327 datatypeNATIVE = true; 1328 log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT"); 1329 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT); 1330 datatypeSize = H5.H5Tget_size(HDF5Constants.H5T_NATIVE_INT); 1331 } 1332 else { 1333 datatypeNATIVE = false; 1334 /* Custom sized integer */ 1335 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT8); 1336 H5.H5Tset_size(tid, datatypeSize); 1337 H5.H5Tset_precision(tid, 8 * datatypeSize); 1338 } 1339 break; 1340 } 1341 1342 if (datatypeOrder == Datatype.ORDER_BE) { 1343 log.trace("createNative(): CLASS_INT order is H5T_ORDER_BE"); 1344 H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE); 1345 } 1346 else if (datatypeOrder == Datatype.ORDER_LE) { 1347 log.trace("createNative(): CLASS_INT order is H5T_ORDER_LE"); 1348 H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE); 1349 } 1350 1351 if (datatypeSign == Datatype.SIGN_NONE) { 1352 log.trace("createNative(): CLASS_INT sign is H5T_SGN_NONE"); 1353 H5.H5Tset_sign(tid, HDF5Constants.H5T_SGN_NONE); 1354 } 1355 } 1356 catch (Exception ex) { 1357 log.debug("createNative(): native integer datatype creation failed: ", ex); 1358 if (tid >= 0) 1359 close(tid); 1360 tid = -1; 1361 } 1362 1363 break; 1364 case CLASS_ENUM: 1365 log.trace("createNative(): CLASS_ENUM"); 1366 try { 1367 if (baseType != null) { 1368 if ((tmptid = baseType.createNative()) < 0) { 1369 log.debug("createNative(): failed to create native type for ENUM base datatype"); 1370 break; 1371 } 1372 1373 tid = H5.H5Tenum_create(tmptid); 1374 } 1375 else { 1376 if (datatypeSize == NATIVE) { 1377 datatypeNATIVE = true; 1378 datatypeSize = H5.H5Tget_size(HDF5Constants.H5T_NATIVE_INT); 1379 } 1380 else 1381 datatypeNATIVE = false; 1382 1383 tid = H5.H5Tcreate(HDF5Constants.H5T_ENUM, datatypeSize); 1384 } 1385 1386 if (datatypeOrder == Datatype.ORDER_BE) { 1387 log.trace("createNative(): CLASS_ENUM order is H5T_ORDER_BE"); 1388 H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE); 1389 } 1390 else if (datatypeOrder == Datatype.ORDER_LE) { 1391 log.trace("createNative(): CLASS_ENUM order is H5T_ORDER_LE"); 1392 H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE); 1393 } 1394 1395 if (datatypeSign == Datatype.SIGN_NONE) { 1396 log.trace("createNative(): CLASS_ENUM sign is H5T_SGN_NONE"); 1397 H5.H5Tset_sign(tid, HDF5Constants.H5T_SGN_NONE); 1398 } 1399 } 1400 catch (Exception ex) { 1401 log.debug("createNative(): native enum datatype creation failed: ", ex); 1402 if (tid >= 0) 1403 close(tid); 1404 tid = HDF5Constants.H5I_INVALID_HID; 1405 } 1406 finally { 1407 close(tmptid); 1408 } 1409 1410 break; 1411 case CLASS_FLOAT: 1412 try { 1413 if (datatypeSize > 8) 1414 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_LDOUBLE); 1415 else 1416 tid = H5.H5Tcopy( 1417 (datatypeSize == 8) ? HDF5Constants.H5T_NATIVE_DOUBLE : HDF5Constants.H5T_NATIVE_FLOAT); 1418 1419 if (datatypeOrder == Datatype.ORDER_BE) { 1420 H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE); 1421 } 1422 else if (datatypeOrder == Datatype.ORDER_LE) { 1423 H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE); 1424 } 1425 1426 if (nativeFPebias > 0) { 1427 H5.H5Tset_ebias(tid, nativeFPebias); 1428 } 1429 1430 if (nativeFPnorm >= 0) { 1431 H5.H5Tset_norm(tid, nativeFPnorm); 1432 } 1433 1434 if (nativeFPinpad >= 0) { 1435 H5.H5Tset_inpad(tid, nativeFPinpad); 1436 } 1437 1438 if ((nativeFPesize >= 0) 1439 && (nativeFPmsize >= 0)) { 1440 H5.H5Tset_fields(tid, nativeFPspos, nativeFPmpos, nativeFPesize, nativeFPmpos, nativeFPmsize); 1441 } 1442 } 1443 catch (Exception ex) { 1444 log.debug("createNative(): native floating-point datatype creation failed: ", ex); 1445 if (tid >= 0) 1446 close(tid); 1447 tid = HDF5Constants.H5I_INVALID_HID; 1448 } 1449 1450 break; 1451 case CLASS_CHAR: 1452 try { 1453 tid = H5.H5Tcopy((datatypeSign == Datatype.SIGN_NONE) ? HDF5Constants.H5T_NATIVE_UCHAR 1454 : HDF5Constants.H5T_NATIVE_CHAR); 1455 } 1456 catch (Exception ex) { 1457 log.debug("createNative(): native character datatype creation failed: ", ex); 1458 if (tid >= 0) 1459 close(tid); 1460 tid = HDF5Constants.H5I_INVALID_HID; 1461 } 1462 1463 break; 1464 case CLASS_STRING: 1465 try { 1466 tid = H5.H5Tcopy(HDF5Constants.H5T_C_S1); 1467 1468 H5.H5Tset_size(tid, (isVLEN 1469 || datatypeSize < 0) ? HDF5Constants.H5T_VARIABLE : datatypeSize); 1470 1471 log.trace("createNative(): isVlenStr={} nativeStrPad={} nativeStrCSET={}", isVLEN, nativeStrPad, 1472 nativeStrCSET); 1473 1474 H5.H5Tset_strpad(tid, (nativeStrPad >= 0) ? nativeStrPad : HDF5Constants.H5T_STR_NULLTERM); 1475 1476 if (nativeStrCSET >= 0) { 1477 H5.H5Tset_cset(tid, nativeStrCSET); 1478 } 1479 } 1480 catch (Exception ex) { 1481 log.debug("createNative(): native string datatype creation failed: ", ex); 1482 if (tid >= 0) 1483 close(tid); 1484 tid = HDF5Constants.H5I_INVALID_HID; 1485 } 1486 1487 break; 1488 case CLASS_REFERENCE: 1489 try { 1490 long objRefTypeSize = H5.H5Tget_size(HDF5Constants.H5T_STD_REF_OBJ); 1491 long dsetRefTypeSize = H5.H5Tget_size(HDF5Constants.H5T_STD_REF_DSETREG); 1492 // use datatypeSize as which type to copy 1493 log.debug("createNative(): datatypeSize:{} ", datatypeSize); 1494 if (datatypeSize < 0 1495 || datatypeSize > dsetRefTypeSize) { 1496 tid = H5.H5Tcopy(HDF5Constants.H5T_STD_REF); 1497 log.debug("createNative(): HDF5Constants.H5T_STD_REF"); 1498 } 1499 else if (datatypeSize > objRefTypeSize) { 1500 tid = H5.H5Tcopy(HDF5Constants.H5T_STD_REF_DSETREG); 1501 log.debug("createNative(): HDF5Constants.H5T_STD_REF_DSETREG"); 1502 } 1503 else { 1504 tid = H5.H5Tcopy(HDF5Constants.H5T_STD_REF_OBJ); 1505 log.debug("createNative(): HDF5Constants.H5T_STD_REF_OBJ"); 1506 } 1507 } 1508 catch (Exception ex) { 1509 log.debug("createNative(): native reference datatype creation failed: ", ex); 1510 if (tid >= 0) 1511 close(tid); 1512 tid = HDF5Constants.H5I_INVALID_HID; 1513 } 1514 1515 break; 1516 case CLASS_VLEN: 1517 try { 1518 if (baseType == null) { 1519 log.debug("createNative(): CLASS_VLEN base type is NULL"); 1520 break; 1521 } 1522 1523 if ((tmptid = baseType.createNative()) < 0) { 1524 log.debug("createNative(): failed to create native datatype for VLEN base datatype"); 1525 break; 1526 } 1527 1528 tid = H5.H5Tvlen_create(tmptid); 1529 } 1530 catch (Exception ex) { 1531 log.debug("createNative(): native variable-length datatype creation failed: ", ex); 1532 if (tid >= 0) 1533 close(tid); 1534 tid = HDF5Constants.H5I_INVALID_HID; 1535 } 1536 finally { 1537 close(tmptid); 1538 } 1539 1540 break; 1541 case CLASS_BITFIELD: 1542 log.trace("createNative(): CLASS_BITFIELD size is {}", datatypeSize); 1543 1544 try { 1545 switch ((int) datatypeSize) { 1546 case 1: 1547 log.trace("createNative(): CLASS_BITFIELD is H5T_NATIVE_B8"); 1548 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B8); 1549 break; 1550 case 2: 1551 log.trace("createNative(): CLASS_BITFIELD is H5T_NATIVE_B16"); 1552 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B16); 1553 break; 1554 case 4: 1555 log.trace("createNative(): CLASS_BITFIELD is H5T_NATIVE_B32"); 1556 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B32); 1557 break; 1558 case 8: 1559 log.trace("createNative(): CLASS_BITFIELD is H5T_NATIVE_B64"); 1560 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B64); 1561 break; 1562 default: 1563 if (datatypeSize == NATIVE) { 1564 datatypeNATIVE = true; 1565 datatypeSize = 1; 1566 } 1567 else 1568 datatypeNATIVE = false; 1569 1570 /* Custom sized bitfield */ 1571 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B8); 1572 H5.H5Tset_size(tid, datatypeSize); 1573 H5.H5Tset_precision(tid, 8 * datatypeSize); 1574 1575 break; 1576 } 1577 1578 if (datatypeOrder == Datatype.ORDER_BE) { 1579 log.trace("createNative(): CLASS_BITFIELD order is H5T_ORDER_BE"); 1580 H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE); 1581 } 1582 else if (datatypeOrder == Datatype.ORDER_LE) { 1583 log.trace("createNative(): CLASS_BITFIELD order is H5T_ORDER_LE"); 1584 H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE); 1585 } 1586 } 1587 catch (Exception ex) { 1588 log.debug("createNative(): native bitfield datatype creation failed: ", ex); 1589 if (tid >= 0) 1590 close(tid); 1591 tid = HDF5Constants.H5I_INVALID_HID; 1592 } 1593 1594 break; 1595 case CLASS_OPAQUE: 1596 log.trace("createNative(): CLASS_OPAQUE is {}-byte H5T_OPAQUE", datatypeSize); 1597 1598 try { 1599 if (datatypeSize == NATIVE) { 1600 datatypeNATIVE = true; 1601 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_OPAQUE); 1602 datatypeSize = H5.H5Tget_size(HDF5Constants.H5T_NATIVE_OPAQUE); 1603 } 1604 else { 1605 datatypeNATIVE = false; 1606 tid = H5.H5Tcreate(HDF5Constants.H5T_OPAQUE, datatypeSize); 1607 } 1608 1609 if (opaqueTag != null) { 1610 H5.H5Tset_tag(tid, opaqueTag); 1611 } 1612 } 1613 catch (Exception ex) { 1614 log.debug("createNative(): native opaque datatype creation failed: ", ex); 1615 if (tid >= 0) 1616 close(tid); 1617 tid = HDF5Constants.H5I_INVALID_HID; 1618 } 1619 1620 break; 1621 default: 1622 log.debug("createNative(): Unknown class"); 1623 break; 1624 } // (tclass) 1625 1626 // set up enum members 1627 if ((datatypeClass == CLASS_ENUM) 1628 && (enumMembers != null)) { 1629 log.trace("createNative(): set up enum members"); 1630 try { 1631 String memstr; 1632 String memname; 1633 byte[] memval = null; 1634 1635 Iterator entries = enumMembers.entrySet().iterator(); 1636 while (entries.hasNext()) { 1637 Entry thisEntry = (Entry) entries.next(); 1638 memstr = (String) thisEntry.getKey(); 1639 memname = (String) thisEntry.getValue(); 1640 1641 if (datatypeSize == 1) { 1642 log.trace("createNative(): CLASS_ENUM is H5T_NATIVE_INT8"); 1643 Byte tval = Byte.parseByte(memstr); 1644 memval = HDFNativeData.byteToByte(tval); 1645 } 1646 else if (datatypeSize == 2) { 1647 log.trace("createNative(): CLASS_ENUM is H5T_NATIVE_INT16"); 1648 Short tval = Short.parseShort(memstr); 1649 memval = HDFNativeData.shortToByte(tval); 1650 } 1651 else if (datatypeSize == 4) { 1652 log.trace("createNative(): CLASS_ENUM is H5T_NATIVE_INT32"); 1653 Integer tval = Integer.parseInt(memstr); 1654 memval = HDFNativeData.intToByte(tval); 1655 } 1656 else if (datatypeSize == 8) { 1657 log.trace("createNative(): CLASS_INT-ENUM is H5T_NATIVE_INT64"); 1658 Long tval = Long.parseLong(memstr); 1659 memval = HDFNativeData.longToByte(tval); 1660 } 1661 else { 1662 log.debug("createNative(): enum datatypeSize incorrect"); 1663 } 1664 log.trace("createNative(): H5Tenum_insert {} {}", memname, memval); 1665 H5.H5Tenum_insert(tid, memname, memval); 1666 } 1667 } 1668 catch (Exception ex) { 1669 log.debug("createNative(): set up enum members failure: ", ex); 1670 } 1671 } // (datatypeClass == CLASS_ENUM) 1672 1673 try { 1674 tmptid = tid; 1675 tid = H5.H5Tget_native_type(tmptid); 1676 } 1677 catch (HDF5Exception ex) { 1678 log.debug("createNative(): H5Tget_native_type({}) failure: ", tmptid, ex); 1679 } 1680 finally { 1681 close(tmptid); 1682 } 1683 1684 return tid; 1685 } 1686 1687 /** 1688 * Allocates a one-dimensional array of byte, short, int, long, float, double, or String to store data in memory. 1689 * For example, 1690 * 1691 * <pre> 1692 * long tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT32); 1693 * int[] data = (int[]) H5Datatype.allocateArray(datatype, 100); 1694 * </pre> 1695 * 1696 * returns a 32-bit integer array of size 100. 1697 * 1698 * @param dtype 1699 * the type. 1700 * @param numPoints 1701 * the total number of data points of the array. 1702 * @return the array object if successful; otherwise, return null. 1703 * @throws OutOfMemoryError 1704 * If there is a failure. 1705 */ 1706 public static final Object allocateArray(final H5Datatype dtype, int numPoints) 1707 throws OutOfMemoryError { 1708 log.trace("allocateArray(): start: numPoints={}", numPoints); 1709 1710 Object data = null; 1711 H5Datatype baseType = (H5Datatype) dtype.getDatatypeBase(); 1712 int typeClass = dtype.getDatatypeClass(); 1713 long typeSize = dtype.getDatatypeSize(); 1714 1715 if (numPoints < 0) { 1716 log.debug("allocateArray(): numPoints < 0"); 1717 return null; 1718 } 1719 1720 // Scalar members have dimensionality zero, i.e. size =0 1721 // what can we do about it, set the size to 1 1722 if (numPoints == 0) 1723 numPoints = 1; 1724 1725 log.trace("allocateArray(): tclass={} : tsize={}", typeClass, typeSize); 1726 1727 if (dtype.isVarStr()) { 1728 log.trace("allocateArray(): is_variable_str={}", dtype.isVarStr()); 1729 1730 data = new String[numPoints]; 1731 for (int i = 0; i < numPoints; i++) 1732 ((String[]) data)[i] = ""; 1733 } 1734 else if (typeClass == HDF5Constants.H5T_INTEGER) { 1735 log.trace("allocateArray(): class H5T_INTEGER"); 1736 if (typeSize == NATIVE) 1737 typeSize = H5.H5Tget_size(HDF5Constants.H5T_NATIVE_INT); 1738 1739 switch ((int) typeSize) { 1740 case 1: 1741 data = new byte[numPoints]; 1742 break; 1743 case 2: 1744 data = new short[numPoints]; 1745 break; 1746 case 4: 1747 data = new int[numPoints]; 1748 break; 1749 case 8: 1750 data = new long[numPoints]; 1751 break; 1752 default: 1753 break; 1754 } 1755 } 1756 else if (typeClass == HDF5Constants.H5T_ENUM) { 1757 log.trace("allocateArray(): class H5T_ENUM"); 1758 1759 if (baseType != null) 1760 data = H5Datatype.allocateArray(baseType, numPoints); 1761 else { 1762 if (typeSize == NATIVE) 1763 typeSize = H5.H5Tget_size(HDF5Constants.H5T_NATIVE_INT); 1764 data = new byte[(int) (numPoints * typeSize)]; 1765 } 1766 } 1767 else if (typeClass == HDF5Constants.H5T_COMPOUND) { 1768 log.trace("allocateArray(): class H5T_COMPOUND"); 1769 1770 data = new ArrayList<>(dtype.getCompoundMemberTypes().size()); 1771 } 1772 else if (typeClass == HDF5Constants.H5T_FLOAT) { 1773 log.trace("allocateArray(): class H5T_FLOAT"); 1774 if (typeSize == NATIVE) 1775 typeSize = H5.H5Tget_size(HDF5Constants.H5T_NATIVE_FLOAT); 1776 1777 switch ((int) typeSize) { 1778 case 4: 1779 data = new float[numPoints]; 1780 break; 1781 case 8: 1782 data = new double[numPoints]; 1783 break; 1784 case 16: 1785 data = new byte[numPoints * 16]; 1786 break; 1787 default: 1788 break; 1789 } 1790 } 1791 else if ((typeClass == HDF5Constants.H5T_STRING) 1792 || (typeClass == HDF5Constants.H5T_REFERENCE)) { 1793 log.trace("allocateArray(): class H5T_STRING || H5T_REFERENCE"); 1794 1795 data = new byte[(int) (numPoints * typeSize)]; 1796 } 1797 else if (dtype.isVLEN()) { 1798 log.trace("allocateArray(): isVLEN"); 1799 1800 data = new ArrayList[numPoints]; 1801 for (int j = 0; j < numPoints; j++) 1802 ((ArrayList[])data)[j] = new ArrayList<byte[]>(); 1803 // if (baseType != null) 1804 // ((ArrayList<>)data).add(H5Datatype.allocateArray(baseType, numPoints)); 1805 } 1806 else if (typeClass == HDF5Constants.H5T_ARRAY) { 1807 log.trace("allocateArray(): class H5T_ARRAY"); 1808 1809 try { 1810 log.trace("allocateArray(): ArrayRank={}", dtype.getArrayDims().length); 1811 1812 // Use the base datatype to define the array 1813 long[] arrayDims = dtype.getArrayDims(); 1814 int asize = numPoints; 1815 for (int j = 0; j < arrayDims.length; j++) { 1816 log.trace("allocateArray(): Array dims[{}]={}", j, arrayDims[j]); 1817 1818 asize *= arrayDims[j]; 1819 } 1820 1821 if (baseType != null) 1822 data = H5Datatype.allocateArray(baseType, asize); 1823 } 1824 catch (Exception ex) { 1825 log.debug("allocateArray(): H5T_ARRAY class failure: ", ex); 1826 } 1827 } 1828 else if ((typeClass == HDF5Constants.H5T_OPAQUE) 1829 || (typeClass == HDF5Constants.H5T_BITFIELD)) { 1830 log.trace("allocateArray(): class H5T_OPAQUE || H5T_BITFIELD"); 1831 if (typeSize == NATIVE) 1832 typeSize = H5.H5Tget_size(typeClass); 1833 1834 data = new byte[(int) (numPoints * typeSize)]; 1835 } 1836 else { 1837 log.debug("allocateArray(): class ???? ({})", typeClass); 1838 1839 data = null; 1840 } 1841 1842 return data; 1843 } 1844 1845 /** 1846 * Returns the size (in bytes) of a given datatype identifier. It basically just calls H5Tget_size(tid). 1847 * 1848 * @param tid 1849 * The datatype identifier. 1850 * @return The size of the datatype in bytes. 1851 * @see hdf.hdf5lib.H5#H5Tget_size(long) 1852 */ 1853 public static final long getDatatypeSize(long tid) { 1854 // data type information 1855 long tsize = -1; 1856 1857 try { 1858 tsize = H5.H5Tget_size(tid); 1859 } 1860 catch (Exception ex) { 1861 tsize = -1; 1862 } 1863 1864 return tsize; 1865 } 1866 1867 /* 1868 * (non-Javadoc) 1869 * @see hdf.object.Datatype#getDescription() 1870 */ 1871 @Override 1872 public String getDescription() { 1873 log.trace("getDescription(): start - isNamed={}", isNamed()); 1874 1875 if (datatypeDescription != null) 1876 return datatypeDescription; 1877 1878 StringBuilder description = new StringBuilder(); 1879 long tid = HDF5Constants.H5I_INVALID_HID; 1880 1881 switch (datatypeClass) { 1882 case CLASS_CHAR: 1883 log.trace("getDescription(): Char"); 1884 description.append("8-bit ").append(isUnsigned() ? "unsigned " : "").append("integer"); 1885 break; 1886 case CLASS_INTEGER: 1887 log.trace("getDescription(): Int [{}]", datatypeNATIVE); 1888 if (datatypeNATIVE) 1889 description.append("native ").append(isUnsigned() ? "unsigned " : "").append("integer"); 1890 else 1891 description.append(String.valueOf(datatypeSize * 8)).append("-bit ") 1892 .append(isUnsigned() ? "unsigned " : "").append("integer"); 1893 break; 1894 case CLASS_FLOAT: 1895 log.trace("getDescription(): Float"); 1896 if (datatypeNATIVE) 1897 description.append("native floating-point"); 1898 else 1899 description.append(String.valueOf(datatypeSize * 8)).append("-bit floating-point"); 1900 break; 1901 case CLASS_STRING: 1902 log.trace("getDescription(): String"); 1903 description.append("String, length = ").append(isVarStr() ? "variable" : datatypeSize); 1904 1905 try { 1906 tid = createNative(); 1907 if (tid >= 0) { 1908 String strPadType; 1909 String strCSETType; 1910 int strPad = H5.H5Tget_strpad(tid); 1911 int strCSET = H5.H5Tget_cset(tid); 1912 1913 if (strPad == HDF5Constants.H5T_STR_NULLTERM) 1914 strPadType = "H5T_STR_NULLTERM"; 1915 else if (strPad == HDF5Constants.H5T_STR_NULLPAD) 1916 strPadType = "H5T_STR_NULLPAD"; 1917 else if (strPad == HDF5Constants.H5T_STR_SPACEPAD) 1918 strPadType = "H5T_STR_SPACEPAD"; 1919 else 1920 strPadType = null; 1921 1922 if (strPadType != null) 1923 description.append(", padding = ").append(strPadType); 1924 1925 if (strCSET == HDF5Constants.H5T_CSET_ASCII) 1926 strCSETType = "H5T_CSET_ASCII"; 1927 else if (strCSET == HDF5Constants.H5T_CSET_UTF8) 1928 strCSETType = "H5T_CSET_UTF8"; 1929 else 1930 strCSETType = null; 1931 1932 if (strCSETType != null) 1933 description.append(", cset = ").append(strCSETType); 1934 } 1935 else { 1936 log.debug("createNative() failure"); 1937 } 1938 } 1939 catch (Exception ex) { 1940 log.debug("H5Tget_strpad failure: ", ex); 1941 } 1942 finally { 1943 close(tid); 1944 } 1945 break; 1946 case CLASS_BITFIELD: 1947 log.trace("getDescription(): Bit"); 1948 if (datatypeNATIVE) 1949 description.append("native bitfield"); 1950 else 1951 description.append(String.valueOf(datatypeSize * 8)).append("-bit bitfield"); 1952 break; 1953 case CLASS_OPAQUE: 1954 log.trace("getDescription(): Opaque"); 1955 if (datatypeNATIVE) 1956 description.append("native Opaque"); 1957 else 1958 description.append(String.valueOf(datatypeSize)).append("-byte Opaque"); 1959 1960 if (opaqueTag != null) { 1961 description.append(", tag = ").append(opaqueTag); 1962 } 1963 1964 break; 1965 case CLASS_COMPOUND: 1966 log.trace("getDescription(): Compound"); 1967 description.append("Compound"); 1968 1969 if ((compoundMemberTypes != null) 1970 && !compoundMemberTypes.isEmpty()) { 1971 Iterator<String> memberNames = null; 1972 Iterator<Datatype> memberTypes = compoundMemberTypes.iterator(); 1973 1974 if (compoundMemberNames != null) 1975 memberNames = compoundMemberNames.iterator(); 1976 1977 description.append(" {"); 1978 1979 while (memberTypes.hasNext()) { 1980 if (memberNames != null 1981 && memberNames.hasNext()) { 1982 description.append(memberNames.next()).append(" = "); 1983 } 1984 1985 description.append(memberTypes.next().getDescription()); 1986 1987 if (memberTypes.hasNext()) 1988 description.append(", "); 1989 } 1990 1991 description.append("}"); 1992 } 1993 1994 break; 1995 case CLASS_REFERENCE: 1996 log.trace("getDescription(): Ref"); 1997 description.append("Reference"); 1998 1999 try { 2000 boolean isRegionType = false; 2001 2002 tid = createNative(); 2003 if (tid >= 0) { 2004 if (!H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF)) { 2005 isRegionType = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF_DSETREG); 2006 2007 description.setLength(0); 2008 if (isRegionType) { 2009 description.append("Dataset region reference"); 2010 } 2011 else { 2012 description.append("Object reference"); 2013 } 2014 } 2015 } 2016 } 2017 catch (Exception ex) { 2018 log.debug("H5.H5Tequal failure: ", ex); 2019 } 2020 finally { 2021 close(tid); 2022 } 2023 2024 break; 2025 case CLASS_ENUM: 2026 log.trace("getDescription(): Enum"); 2027 if (datatypeNATIVE) 2028 description.append("native enum"); 2029 else 2030 description.append(String.valueOf(datatypeSize * 8)).append("-bit enum"); 2031 2032 String members = getEnumMembersAsString(); 2033 if (members != null) 2034 description.append(" (").append(members).append(")"); 2035 2036 break; 2037 case CLASS_VLEN: 2038 log.trace("getDescription(): Var Len"); 2039 description.append("Variable-length"); 2040 2041 if (baseType != null) 2042 description.append(" of ").append(baseType.getDescription()); 2043 2044 break; 2045 case CLASS_ARRAY: 2046 log.trace("getDescription(): Array"); 2047 description.append("Array"); 2048 2049 if (arrayDims != null) { 2050 description.append(" ["); 2051 for (int i = 0; i < arrayDims.length; i++) { 2052 description.append(arrayDims[i]); 2053 if (i < arrayDims.length - 1) 2054 description.append(" x "); 2055 } 2056 description.append("]"); 2057 } 2058 2059 if (baseType != null) 2060 description.append(" of ").append(baseType.getDescription()); 2061 2062 break; 2063 default: 2064 description.append("Unknown"); 2065 break; 2066 } 2067 if (isNamed()) 2068 description.append("->").append(getFullName()); 2069 2070 return description.toString(); 2071 } 2072 2073 /** 2074 * Checks if a datatype specified by the identifier is an unsigned integer. 2075 * 2076 * @param tid 2077 * the datatype ID to be checked. 2078 * @return true is the datatype is an unsigned integer; otherwise returns false. 2079 */ 2080 public static final boolean isUnsigned(long tid) { 2081 boolean unsigned = false; 2082 2083 if (tid >= 0) { 2084 try { 2085 int tclass = H5.H5Tget_class(tid); 2086 log.trace("isUnsigned(): tclass = {}", tclass); 2087 if (tclass != HDF5Constants.H5T_FLOAT 2088 && tclass != HDF5Constants.H5T_STRING && tclass != HDF5Constants.H5T_REFERENCE 2089 && tclass != HDF5Constants.H5T_BITFIELD && tclass != HDF5Constants.H5T_OPAQUE 2090 && tclass != HDF5Constants.H5T_VLEN && tclass != HDF5Constants.H5T_COMPOUND 2091 && tclass != HDF5Constants.H5T_ARRAY) { 2092 int tsign = H5.H5Tget_sign(tid); 2093 if (tsign == HDF5Constants.H5T_SGN_NONE) 2094 unsigned = true; 2095 else 2096 log.trace("isUnsigned(): not unsigned"); 2097 } 2098 else { 2099 log.trace("isUnsigned(): tclass not integer type"); 2100 } 2101 } 2102 catch (Exception ex) { 2103 log.debug("isUnsigned(): Datatype {} failure", tid, ex); 2104 unsigned = false; 2105 } 2106 } 2107 else { 2108 log.trace("isUnsigned(): not a valid datatype"); 2109 } 2110 2111 return unsigned; 2112 } 2113 2114 /** 2115 * Removes all of the elements from metadata list. The list should be empty after this call returns. 2116 */ 2117 @Override 2118 public void clear() { 2119 super.clear(); 2120 objMetadata.clear(); 2121 } 2122 2123 /** 2124 * Retrieves the object's metadata, such as attributes, from the file. Metadata, such as attributes, is stored in a 2125 * List. 2126 * 2127 * @return the list of metadata objects. 2128 * @throws HDF5Exception 2129 * if the metadata can not be retrieved 2130 */ 2131 @Override 2132 public List<Attribute> getMetadata() 2133 throws HDF5Exception { 2134 int gmIndexType = 0; 2135 int gmIndexOrder = 0; 2136 2137 try { 2138 gmIndexType = fileFormat.getIndexType(null); 2139 } 2140 catch (Exception ex) { 2141 log.debug("getMetadata(): getIndexType failed: ", ex); 2142 } 2143 try { 2144 gmIndexOrder = fileFormat.getIndexOrder(null); 2145 } 2146 catch (Exception ex) { 2147 log.debug("getMetadata(): getIndexOrder failed: ", ex); 2148 } 2149 return this.getMetadata(gmIndexType, gmIndexOrder); 2150 } 2151 2152 /** 2153 * Retrieves the object's metadata, such as attributes, from the file. Metadata, such as attributes, is stored in a 2154 * List. 2155 * 2156 * @param attrPropList 2157 * the list of properties to get 2158 * @return the list of metadata objects. 2159 * @throws HDF5Exception 2160 * if the metadata can not be retrieved 2161 */ 2162 public List<Attribute> getMetadata(int... attrPropList) 2163 throws HDF5Exception { 2164 try { 2165 this.linkTargetObjName = H5File.getLinkTargetName(this); 2166 } 2167 catch (Exception ex) { 2168 log.debug("getMetadata(): getLinkTargetName failed: ", ex); 2169 } 2170 2171 List<Attribute> attrlist = null; 2172 try { 2173 attrlist = objMetadata.getMetadata(attrPropList); 2174 } 2175 catch (Exception ex) { 2176 log.debug("getMetadata(): getMetadata failed: ", ex); 2177 } 2178 return attrlist; 2179 } 2180 2181 /** 2182 * Writes a specific piece of metadata (such as an attribute) into the file. If an HDF(4&5) attribute exists in 2183 * the file, this method updates its value. If the attribute does not exist in the file, it creates the attribute in 2184 * the file and attaches it to the object. It will fail to write a new attribute to the object where an attribute 2185 * with the same name already exists. To update the value of an existing attribute in the file, one needs to get the 2186 * instance of the attribute by getMetadata(), change its values, then use writeMetadata() to write the value. 2187 * 2188 * @param info 2189 * the metadata to write. 2190 * @throws Exception 2191 * if the metadata can not be written 2192 */ 2193 @Override 2194 public void writeMetadata(Object info) 2195 throws Exception { 2196 try { 2197 objMetadata.writeMetadata(info); 2198 } 2199 catch (Exception ex) { 2200 log.debug("writeMetadata(): Object not an Attribute"); 2201 } 2202 } 2203 2204 /** 2205 * Deletes an existing piece of metadata from this object. 2206 * 2207 * @param info 2208 * the metadata to delete. 2209 * @throws HDF5Exception 2210 * if the metadata can not be removed 2211 */ 2212 @Override 2213 public void removeMetadata(Object info) 2214 throws HDF5Exception { 2215 try { 2216 objMetadata.removeMetadata(info); 2217 } 2218 catch (Exception ex) { 2219 log.debug("removeMetadata(): Object not an Attribute"); 2220 return; 2221 } 2222 2223 Attribute attr = (Attribute) info; 2224 log.trace("removeMetadata(): {}", attr.getAttributeName()); 2225 long tid = open(); 2226 if (tid >= 0) { 2227 try { 2228 H5.H5Adelete(tid, attr.getAttributeName()); 2229 } 2230 catch (Exception ex) { 2231 log.debug("removeMetadata(): ", ex); 2232 } 2233 finally { 2234 close(tid); 2235 } 2236 } 2237 else { 2238 log.debug("removeMetadata(): failed to open datatype"); 2239 } 2240 } 2241 2242 /** 2243 * Updates an existing piece of metadata attached to this object. 2244 * 2245 * @param info 2246 * the metadata to update. 2247 * @throws HDF5Exception 2248 * if the metadata can not be updated 2249 */ 2250 @Override 2251 public void updateMetadata(Object info) 2252 throws HDF5Exception { 2253 try { 2254 objMetadata.updateMetadata(info); 2255 } 2256 catch (Exception ex) { 2257 log.debug("updateMetadata(): Object not an Attribute"); 2258 return; 2259 } 2260 } 2261 2262 /* 2263 * (non-Javadoc) 2264 * @see hdf.object.HObject#setName(java.lang.String) 2265 */ 2266 @Override 2267 public void setName(String newName) 2268 throws Exception { 2269 if (newName == null) 2270 throw new IllegalArgumentException("The new name is NULL"); 2271 2272 H5File.renameObject(this, newName); 2273 super.setName(newName); 2274 } 2275 2276 @Override 2277 public void setFullname(String newPath, String newName) 2278 throws Exception { 2279 H5File.renameObject(this, newPath, newName); 2280 super.setFullname(newPath, newName); 2281 } 2282 2283 @Override 2284 public boolean isText() { 2285 return (datatypeClass == Datatype.CLASS_STRING); 2286 } 2287 2288 /** 2289 * Checks if this datatype is an object reference type. 2290 * 2291 * @return true if the datatype is an object reference; false otherwise 2292 */ 2293 public boolean isRefObj() { 2294 return isRefObj; 2295 } 2296 2297 /** 2298 * Checks if this datatype is a region reference type. 2299 * 2300 * @return true if the datatype is a region reference; false otherwise 2301 */ 2302 public boolean isRegRef() { 2303 return isRegRef; 2304 } 2305 2306 /** 2307 * Checks if this datatype is a standard reference type. 2308 * 2309 * @return true if the datatype is a standard reference; false otherwise 2310 */ 2311 public boolean isStdRef() { 2312 return isStdRef; 2313 } 2314 2315 /* 2316 * (non-Javadoc) 2317 * @see hdf.object.Datatype#getReferenceType() 2318 */ 2319 @Override 2320 public long getReferenceType() 2321 throws HDF5Exception { 2322 if (isRegRef) 2323 return HDF5Constants.H5T_STD_REF_DSETREG; 2324 if (isRefObj) 2325 return HDF5Constants.H5T_STD_REF_OBJ; 2326 if (isStdRef) 2327 return HDF5Constants.H5T_STD_REF; 2328 return -1; 2329 } 2330 2331 /** 2332 * Describes the dataset object description for a 1.10 reference. 2333 * 2334 * @param container 2335 * the dataset/attribute with the reference 2336 * @param refarr 2337 * the reference datatype data to be checked. 2338 * 2339 * @return the dataset reference object description. 2340 */ 2341 public static String descReferenceObject(long container, byte[] refarr) { 2342 String region_desc = H5.H5Rget_name_string(container, HDF5Constants.H5R_OBJECT, refarr); 2343 region_desc += " H5O_TYPE_OBJ_REF"; 2344 log.trace("descReferenceObject region_desc={}:", region_desc); 2345 return region_desc; 2346 } 2347 2348 /** 2349 * Describes the dataset region description for a 1.10 reference. 2350 * 2351 * @param container 2352 * the dataset/attribute with the reference 2353 * @param refarr 2354 * the reference datatype data to be checked. 2355 * 2356 * @return the dataset region description. 2357 */ 2358 public static String descRegionDataset(long container, byte[] refarr) { 2359 String region_desc = H5.H5Rget_name_string(container, HDF5Constants.H5R_DATASET_REGION, refarr); 2360 log.trace("descRegionDataset region_desc={}:", region_desc); 2361 long new_obj_id = HDF5Constants.H5I_INVALID_HID; 2362 try { 2363 log.trace("descRegionDataset refarr2={}:", refarr); 2364 new_obj_id = H5.H5Rdereference(container, HDF5Constants.H5P_DEFAULT, HDF5Constants.H5R_DATASET_REGION, 2365 refarr); 2366 long new_obj_sid = HDF5Constants.H5I_INVALID_HID; 2367 try { 2368 log.trace("descRegionDataset refarr3={}:", refarr); 2369 new_obj_sid = H5.H5Rget_region(container, HDF5Constants.H5R_DATASET_REGION, refarr); 2370 try { 2371 int region_type = H5.H5Sget_select_type(new_obj_sid); 2372 log.debug("descRegionDataset Reference Region Type {}", region_type); 2373 long reg_ndims = H5.H5Sget_simple_extent_ndims(new_obj_sid); 2374 StringBuilder sb = new StringBuilder(); 2375 if (HDF5Constants.H5S_SEL_POINTS == region_type) { 2376 sb.append(" REGION_TYPE POINT "); 2377 long reg_npoints = H5.H5Sget_select_elem_npoints(new_obj_sid); 2378 long getcoord[] = new long[(int) (reg_ndims * reg_npoints)]; 2379 try { 2380 H5.H5Sget_select_elem_pointlist(new_obj_sid, 0, reg_npoints, getcoord); 2381 } 2382 catch (Exception ex5) { 2383 log.debug("descRegionDataset H5.H5Sget_select_elem_pointlist: ", ex5); 2384 } 2385 sb.append("{ "); 2386 for (int i = 0; i < (int) reg_npoints; i++) { 2387 if (i > 0) 2388 sb.append(" "); 2389 sb.append("("); 2390 for (int j = 0; j < (int) reg_ndims; j++) { 2391 if (j > 0) 2392 sb.append(","); 2393 sb.append(getcoord[i * (int) reg_ndims + j]); 2394 } 2395 sb.append(")"); 2396 } 2397 sb.append(" }"); 2398 region_desc += sb.toString(); 2399 } 2400 else if (HDF5Constants.H5S_SEL_HYPERSLABS == region_type) { 2401 sb.append(" REGION_TYPE BLOCK "); 2402 long reg_nblocks = H5.H5Sget_select_hyper_nblocks(new_obj_sid); 2403 long getblocks[] = new long[(int) (reg_ndims * reg_nblocks) * 2]; 2404 try { 2405 H5.H5Sget_select_hyper_blocklist(new_obj_sid, 0, reg_nblocks, getblocks); 2406 } 2407 catch (Exception ex5) { 2408 log.debug("descRegionDataset H5.H5Sget_select_hyper_blocklist: ", ex5); 2409 } 2410 sb.append("{ "); 2411 for (int i = 0; i < (int) reg_nblocks; i++) { 2412 if (i > 0) 2413 sb.append(" "); 2414 sb.append("("); 2415 for (int j = 0; j < (int) reg_ndims; j++) { 2416 if (j > 0) 2417 sb.append(","); 2418 sb.append(getblocks[i * 2 * (int) reg_ndims + j]); 2419 } 2420 sb.append(")-("); 2421 for (int j = 0; j < (int) reg_ndims; j++) { 2422 if (j > 0) 2423 sb.append(","); 2424 sb.append(getblocks[i * 2 * (int) reg_ndims + (int) reg_ndims + j]); 2425 } 2426 sb.append(")"); 2427 } 2428 sb.append(" }"); 2429 region_desc += sb.toString(); 2430 } 2431 else 2432 region_desc += " REGION_TYPE UNKNOWN"; 2433 } 2434 catch (Exception ex4) { 2435 log.debug("descRegionDataset Region Type", ex4); 2436 } 2437 } 2438 catch (Exception ex3) { 2439 log.debug("descRegionDataset Space Open", ex3); 2440 } 2441 finally { 2442 H5.H5Sclose(new_obj_sid); 2443 } 2444 log.trace("descRegionDataset finish"); 2445 } 2446 catch (Exception ex2) { 2447 log.debug("descRegionDataset ", ex2); 2448 } 2449 finally { 2450 H5.H5Dclose(new_obj_id); 2451 } 2452 return region_desc; 2453 } 2454 2455 /** 2456 * Gets the dataset reference type for a 1.10 reference. 2457 * 2458 * @param container 2459 * the dataset/attribute with the reference 2460 * @param refarr 2461 * the reference datatype data to be checked. 2462 * 2463 * @return the dataset reference type. 2464 */ 2465 public static int typeObjectRef(long container, int obj_type, byte[] refarr) { 2466 int ref_type = -1; 2467 long new_obj_id = HDF5Constants.H5I_INVALID_HID; 2468 try { 2469 log.trace("typeObjectRef refarr2={}:", refarr); 2470 new_obj_id = H5.H5Rdereference(container, HDF5Constants.H5P_DEFAULT, obj_type, refarr); 2471 if (HDF5Constants.H5R_DATASET_REGION == obj_type) { 2472 long new_obj_sid = HDF5Constants.H5I_INVALID_HID; 2473 try { 2474 log.trace("typeObjectRef refarr3={}:", refarr); 2475 new_obj_sid = H5.H5Rget_region(container, HDF5Constants.H5R_DATASET_REGION, refarr); 2476 try { 2477 ref_type = H5.H5Sget_select_type(new_obj_sid); 2478 log.debug("typeObjectRef Reference Region Type {}", ref_type); 2479 } 2480 catch (Exception ex4) { 2481 log.debug("typeObjectRef Region Type", ex4); 2482 } 2483 } 2484 catch (Exception ex3) { 2485 log.debug("typeObjectRef Space Open", ex3); 2486 } 2487 finally { 2488 H5.H5Sclose(new_obj_sid); 2489 } 2490 } 2491 else { 2492 H5O_info_t objInfo; 2493 2494 objInfo = H5.H5Oget_info(new_obj_id); 2495 ref_type = objInfo.type; 2496 } 2497 log.trace("typeObjectRef finish"); 2498 } 2499 catch (Exception ex2) { 2500 log.debug("typeObjectRef ", ex2); 2501 } 2502 finally { 2503 H5.H5Dclose(new_obj_id); 2504 } 2505 return ref_type; 2506 } 2507 2508 /** 2509 * Checks if a reference datatype is all zero. 2510 * 2511 * @param refarr 2512 * the reference datatype data to be checked. 2513 * @return true is the reference datatype data is all zero; otherwise returns false. 2514 */ 2515 public static boolean zeroArrayCheck(final byte[] refarr) { 2516 for (byte b : refarr) { 2517 if (b != 0) 2518 return false; 2519 } 2520 return true; 2521 } 2522 2523 /** 2524 * Gets the string padding. 2525 * 2526 * @return the string padding value 2527 */ 2528 public int getNativeStrPad() { 2529 return nativeStrPad; 2530 } 2531 2532 /** 2533 * Extracts compound information into flat structure. For example, compound datatype "nest" has {nest1{a, b, c}, d, 2534 * e} then extractCompoundInfo() will put the names of nested compound fields into a flat list as 2535 * 2536 * <pre> 2537 * nest.nest1.a 2538 * nest.nest1.b 2539 * nest.nest1.c 2540 * nest.d 2541 * nest.e 2542 * </pre> 2543 * 2544 * @param dtype 2545 * the datatype to extract compound info from 2546 * @param name 2547 * the name of the compound datatype 2548 * @param names 2549 * the list to store the member names of the compound datatype 2550 * @param flatListTypes 2551 * the list to store the nested member names of the compound datatype 2552 */ 2553 public static void extractCompoundInfo(final H5Datatype dtype, String name, List<String> names, 2554 List<Datatype> flatListTypes) { 2555 log.trace("extractCompoundInfo(): start: name={}", name); 2556 2557 if (dtype.isArray()) { 2558 log.trace("extractCompoundInfo(): array type - extracting compound info from base datatype"); 2559 H5Datatype.extractCompoundInfo((H5Datatype) dtype.getDatatypeBase(), name, names, flatListTypes); 2560 } 2561 else if (dtype.isVLEN() 2562 && !dtype.isVarStr()) { 2563 log.trace("extractCompoundInfo(): variable-length type - extracting compound info from base datatype"); 2564 H5Datatype.extractCompoundInfo((H5Datatype) dtype.getDatatypeBase(), name, names, flatListTypes); 2565 } 2566 else if (dtype.isCompound()) { 2567 List<String> compoundMemberNames = dtype.getCompoundMemberNames(); 2568 List<Datatype> compoundMemberTypes = dtype.getCompoundMemberTypes(); 2569 Datatype mtype = null; 2570 String mname = null; 2571 2572 if (compoundMemberNames == null) { 2573 log.debug("extractCompoundInfo(): compoundMemberNames is null"); 2574 return; 2575 } 2576 2577 if (compoundMemberNames.isEmpty()) { 2578 log.debug("extractCompoundInfo(): compound datatype has no members"); 2579 return; 2580 } 2581 2582 log.trace("extractCompoundInfo(): nMembers={}", compoundMemberNames.size()); 2583 2584 for (int i = 0; i < compoundMemberNames.size(); i++) { 2585 log.trace("extractCompoundInfo(): member[{}]:", i); 2586 2587 mtype = compoundMemberTypes.get(i); 2588 2589 log.trace("extractCompoundInfo(): type={} with size={}", mtype.getDescription(), 2590 mtype.getDatatypeSize()); 2591 2592 if (names != null) { 2593 mname = name + compoundMemberNames.get(i); 2594 log.trace("extractCompoundInfo(): mname={}, name={}", mname, name); 2595 } 2596 2597 if (mtype.isCompound()) { 2598 H5Datatype.extractCompoundInfo((H5Datatype) mtype, mname + CompoundDS.SEPARATOR, names, 2599 flatListTypes); 2600 log.trace("extractCompoundInfo(): continue after recursive compound"); 2601 continue; 2602 } 2603 2604 if (names != null) { 2605 names.add(mname); 2606 } 2607 2608 flatListTypes.add(mtype); 2609 2610 /* 2611 * For ARRAY of COMPOUND and VLEN of COMPOUND types, we first add the top-level array or vlen type to 2612 * the list of datatypes, and then follow that with a listing of the datatypes inside the nested 2613 * compound. 2614 */ 2615 /* 2616 * TODO: Don't flatten variable-length types until true variable-length support is implemented. 2617 */ 2618 if (mtype.isArray() /* || (mtype.isVLEN() && !mtype.isVarStr()) */) { 2619 H5Datatype.extractCompoundInfo((H5Datatype) mtype, mname + CompoundDS.SEPARATOR, names, 2620 flatListTypes); 2621 } 2622 } 2623 } 2624 } 2625 2626 /** 2627 * Creates a datatype of a compound with one field. This function is needed to read/write data field by field. 2628 * 2629 * @param memberName 2630 * The name of the datatype 2631 * @return the identifier of the compound datatype. 2632 * @throws HDF5Exception 2633 * If there is an error at the HDF5 library level. 2634 */ 2635 public long createCompoundFieldType(String memberName) 2636 throws HDF5Exception { 2637 log.trace("createCompoundFieldType(): start member_name={}", memberName); 2638 2639 long topTID = HDF5Constants.H5I_INVALID_HID; 2640 long tmpTID1 = HDF5Constants.H5I_INVALID_HID; 2641 2642 try { 2643 if (this.isArray()) { 2644 log.trace("createCompoundFieldType(): array datatype"); 2645 2646 if (baseType != null) { 2647 log.trace("createCompoundFieldType(): creating compound field type from base datatype"); 2648 tmpTID1 = ((H5Datatype) baseType).createCompoundFieldType(memberName); 2649 } 2650 2651 log.trace("createCompoundFieldType(): creating container array datatype"); 2652 topTID = H5.H5Tarray_create(tmpTID1, arrayDims.length, arrayDims); 2653 } 2654 else if (this.isVLEN()) { 2655 log.trace("createCompoundFieldType(): variable-length datatype"); 2656 2657 if (baseType != null) { 2658 log.trace("createCompoundFieldType(): creating compound field type from base datatype"); 2659 tmpTID1 = ((H5Datatype) baseType).createCompoundFieldType(memberName); 2660 } 2661 2662 log.trace("createCompoundFieldType(): creating container variable-length datatype"); 2663 topTID = H5.H5Tvlen_create(tmpTID1); 2664 } 2665 else if (this.isCompound()) { 2666 log.trace("createCompoundFieldType(): compound datatype"); 2667 2668 String insertedName = memberName; 2669 2670 int sep = memberName.indexOf(CompoundDS.SEPARATOR); 2671 if (sep >= 0) { 2672 /* 2673 * If a compound separator character is present in the supplied string, then there is an additional 2674 * level of compound nesting. We will create a compound type to hold the nested compound type. 2675 */ 2676 insertedName = memberName.substring(0, sep); 2677 2678 log.trace("createCompoundFieldType(): member with name {} is nested inside compound", insertedName); 2679 } 2680 2681 /* 2682 * Retrieve the index of the compound member by its name. 2683 */ 2684 int memberIndex = this.compoundMemberNames.indexOf(insertedName); 2685 if (memberIndex >= 0) { 2686 H5Datatype memberType = (H5Datatype) this.compoundMemberTypes.get(memberIndex); 2687 2688 log.trace("createCompoundFieldType(): Member {} is type {} of size={} with baseType={}", 2689 insertedName, memberType.getDescription(), memberType.getDatatypeSize(), 2690 memberType.getDatatypeBase()); 2691 2692 if (sep >= 0) 2693 /* 2694 * Additional compound nesting; create the nested compound type. 2695 */ 2696 tmpTID1 = memberType.createCompoundFieldType(memberName.substring(sep + 1)); 2697 else 2698 tmpTID1 = memberType.createNative(); 2699 2700 log.trace("createCompoundFieldType(): creating container compound datatype"); 2701 topTID = H5.H5Tcreate(HDF5Constants.H5T_COMPOUND, datatypeSize); 2702 2703 log.trace("createCompoundFieldType(): inserting member {} into compound datatype", insertedName); 2704 H5.H5Tinsert(topTID, insertedName, 0, tmpTID1); 2705 2706 /* 2707 * WARNING!!! This step is crucial. Without it, the compound type created might be larger than the 2708 * size of the single datatype field we are inserting. Performing a read with a compound datatype of 2709 * an incorrect size will corrupt JVM memory and cause strange behavior and crashes. 2710 */ 2711 H5.H5Tpack(topTID); 2712 } 2713 else { 2714 log.debug( 2715 "createCompoundFieldType(): member name {} not found in compound datatype's member name list", 2716 memberName); 2717 } 2718 } 2719 } 2720 catch (Exception ex) { 2721 log.debug("createCompoundFieldType(): creation of compound field type failed: ", ex); 2722 topTID = HDF5Constants.H5I_INVALID_HID; 2723 } 2724 finally { 2725 close(tmpTID1); 2726 } 2727 2728 return topTID; 2729 } 2730 2731 private boolean datatypeIsComplex(long tid) { 2732 long tclass = HDF5Constants.H5T_NO_CLASS; 2733 2734 try { 2735 tclass = H5.H5Tget_class(tid); 2736 log.trace("datatypeIsComplex():{}", tclass); 2737 } 2738 catch (Exception ex) { 2739 log.debug("datatypeIsComplex():", ex); 2740 } 2741 2742 boolean retVal = (tclass == HDF5Constants.H5T_COMPOUND); 2743 retVal |= (tclass == HDF5Constants.H5T_ENUM); 2744 retVal |= (tclass == HDF5Constants.H5T_VLEN); 2745 retVal |= (tclass == HDF5Constants.H5T_ARRAY); 2746 2747 return retVal; 2748 } 2749 2750 private boolean datatypeIsReference(long tid) { 2751 long tclass = HDF5Constants.H5T_NO_CLASS; 2752 2753 try { 2754 tclass = H5.H5Tget_class(tid); 2755 log.trace("datatypeIsReference():{}", tclass); 2756 } 2757 catch (Exception ex) { 2758 log.debug("datatypeIsReference():", ex); 2759 } 2760 2761 return (tclass == HDF5Constants.H5T_REFERENCE); 2762 } 2763 2764 private boolean datatypeIsAtomic(long tid) { 2765 boolean retVal = !(datatypeIsComplex(tid) 2766 | datatypeIsReference(tid) | isRef()); 2767 retVal |= isOpaque(); 2768 retVal |= isBitField(); 2769 2770 return retVal; 2771 } 2772 2773 private boolean datatypeClassIsComplex(long tclass) { 2774 boolean retVal = (tclass == HDF5Constants.H5T_COMPOUND); 2775 retVal |= (tclass == HDF5Constants.H5T_ENUM); 2776 retVal |= (tclass == HDF5Constants.H5T_VLEN); 2777 retVal |= (tclass == HDF5Constants.H5T_ARRAY); 2778 2779 return retVal; 2780 } 2781 2782 private boolean datatypeClassIsReference(long tclass) { 2783 return (tclass == HDF5Constants.H5T_REFERENCE); 2784 } 2785 2786 private boolean datatypeClassIsOpaque(long tclass) { 2787 return (tclass == Datatype.CLASS_OPAQUE); 2788 } 2789 2790 private boolean datatypeClassIsAtomic(long tclass) { 2791 boolean retVal = !(datatypeClassIsComplex(tclass) 2792 | datatypeClassIsReference(tclass)); 2793 retVal |= (tclass == Datatype.CLASS_OPAQUE); 2794 retVal |= (tclass == Datatype.CLASS_BITFIELD); 2795 2796 return retVal; 2797 } 2798}