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