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