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