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.HashMap; 019import java.util.Iterator; 020import java.util.List; 021import java.util.Map.Entry; 022import java.util.Objects; 023import java.util.Vector; 024 025import hdf.hdf5lib.H5; 026import hdf.hdf5lib.HDF5Constants; 027import hdf.hdf5lib.HDFNativeData; 028import hdf.hdf5lib.exceptions.HDF5Exception; 029import hdf.hdf5lib.exceptions.HDF5LibraryException; 030import hdf.hdf5lib.structs.H5O_info_t; 031import hdf.object.Attribute; 032import hdf.object.CompoundDS; 033import hdf.object.Datatype; 034import hdf.object.FileFormat; 035 036/** 037 * This class defines HDF5 datatype characteristics and APIs for a data type. 038 * <p> 039 * This class provides several methods to convert an HDF5 datatype identifier to a datatype object, and vice versa. A 040 * datatype object is described by four basic fields: datatype class, size, byte order, and sign, while an HDF5 datatype 041 * is presented by a datatype identifier. 042 * 043 * @version 1.1 9/4/2007 044 * @author Peter X. Cao 045 */ 046public class H5Datatype extends Datatype { 047 private static final long serialVersionUID = -750546422258749792L; 048 049 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(H5Datatype.class); 050 051 /** 052 * The list of attributes of this data object. 053 */ 054 private List<Attribute> attributeList; 055 056 /** Flag to indicate if this datatype is a named datatype */ 057 private boolean isNamed = false; 058 059 private boolean is_ref_obj = false; 060 061 private boolean is_reg_ref = false; 062 063 private int nAttributes = -1; 064 065 private H5O_info_t obj_info; 066 067 /** 068 * The native class of the datatype. 069 */ 070 private int nativeClass = -1; 071 072 private int nativeStrPad = -1; 073 074 /** 075 * The tag for an opaque datatype. 076 */ 077 private String opaqueTag = null; 078 079 /** 080 * Constructs an named HDF5 data type object for a given file, dataset name and group path. 081 * <p> 082 * The datatype object represents an existing named datatype in file. For example, 083 * 084 * <pre> 085 * new H5Datatype(file, "dtype1", "/g0") 086 * </pre> 087 * 088 * constructs a datatype object that corresponds to the dataset,"dset1", at group "/g0". 089 * 090 * @param theFile 091 * the file that contains the dataset. 092 * @param name 093 * the name of the dataset such as "dset1". 094 * @param path 095 * the group path to the dataset such as "/g0/". 096 */ 097 public H5Datatype(FileFormat theFile, String name, String path) { 098 this(theFile, name, path, null); 099 } 100 101 /** 102 * @deprecated Not for public use in the future. <br> 103 * Using {@link #H5Datatype(FileFormat, String, String)} 104 * 105 * @param theFile 106 * the file that contains the dataset. 107 * @param name 108 * the name of the dataset such as "dset1". 109 * @param path 110 * the group path to the dataset such as "/g0/". 111 * @param oid 112 * the oid of the dataset. 113 */ 114 @Deprecated 115 public H5Datatype(FileFormat theFile, String name, String path, long[] oid) { 116 super(theFile, name, path, oid); 117 obj_info = new H5O_info_t(-1L, -1L, 0, 0, -1L, 0L, 0L, 0L, 0L, null, null, null); 118 119 if ((oid == null) && (theFile != null)) { 120 // retrieve the object ID 121 try { 122 byte[] ref_buf = H5.H5Rcreate(theFile.getFID(), this.getFullName(), HDF5Constants.H5R_OBJECT, -1); 123 this.oid = new long[1]; 124 this.oid[0] = HDFNativeData.byteToLong(ref_buf, 0); 125 } 126 catch (Exception ex) { 127 log.debug("constructor ID {} for {} failed H5Rcreate", theFile.getFID(), this.getFullName()); 128 } 129 } 130 131 long tid = -1; 132 try { 133 tid = H5.H5Topen(theFile.getFID(), this.getFullName(), HDF5Constants.H5P_DEFAULT); 134 fromNative(tid); 135 } 136 catch (Exception ex) { 137 log.debug("constructor H5Topen() failure"); 138 } 139 finally { 140 close(tid); 141 } 142 } 143 144 /** 145 * Constructs a Datatype with specified class, size, byte order and sign. 146 * <p> 147 * The following is a list of a few example of H5Datatype. 148 * <ol> 149 * <li>to create unsigned native integer<br> 150 * H5Datatype type = new H5Dataype(CLASS_INTEGER, NATIVE, NATIVE, SIGN_NONE); 151 * <li>to create 16-bit signed integer with big endian<br> 152 * H5Datatype type = new H5Dataype(CLASS_INTEGER, 2, ORDER_BE, NATIVE); 153 * <li>to create native float<br> 154 * H5Datatype type = new H5Dataype(CLASS_FLOAT, NATIVE, NATIVE, -1); 155 * <li>to create 64-bit double<br> 156 * H5Datatype type = new H5Dataype(CLASS_FLOAT, 8, NATIVE, -1); 157 * </ol> 158 * 159 * @param tclass 160 * the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc. 161 * @param tsize 162 * the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4. 163 * @param torder 164 * the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX and ORDER_NONE 165 * @param tsign 166 * the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and MSGN 167 */ 168 public H5Datatype(int tclass, int tsize, int torder, int tsign) { 169 this(tclass, tsize, torder, tsign, null); 170 } 171 172 /** 173 * Constructs a Datatype with specified class, size, byte order and sign. 174 * <p> 175 * The following is a list of a few example of H5Datatype. 176 * <ol> 177 * <li>to create unsigned native integer<br> 178 * H5Datatype type = new H5Dataype(CLASS_INTEGER, NATIVE, NATIVE, SIGN_NONE); 179 * <li>to create 16-bit signed integer with big endian<br> 180 * H5Datatype type = new H5Dataype(CLASS_INTEGER, 2, ORDER_BE, NATIVE); 181 * <li>to create native float<br> 182 * H5Datatype type = new H5Dataype(CLASS_FLOAT, NATIVE, NATIVE, -1); 183 * <li>to create 64-bit double<br> 184 * H5Datatype type = new H5Dataype(CLASS_FLOAT, 8, NATIVE, -1); 185 * </ol> 186 * 187 * @param tclass 188 * the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc. 189 * @param tsize 190 * the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4. 191 * @param torder 192 * the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX and ORDER_NONE 193 * @param tsign 194 * the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and MSGN 195 * @param tbase 196 * the base datatype of the new datatype 197 */ 198 public H5Datatype(int tclass, int tsize, int torder, int tsign, Datatype tbase) { 199 this(tclass, tsize, torder, tsign, tbase, 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 example of H5Datatype. 206 * <ol> 207 * <li>to create unsigned native integer<br> 208 * H5Datatype type = new H5Dataype(CLASS_INTEGER, NATIVE, NATIVE, SIGN_NONE); 209 * <li>to create 16-bit signed integer with big endian<br> 210 * H5Datatype type = new H5Dataype(CLASS_INTEGER, 2, ORDER_BE, NATIVE); 211 * <li>to create native float<br> 212 * H5Datatype type = new H5Dataype(CLASS_FLOAT, NATIVE, NATIVE, -1); 213 * <li>to create 64-bit double<br> 214 * H5Datatype type = new H5Dataype(CLASS_FLOAT, 8, NATIVE, -1); 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 * @param torder 222 * the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX and 223 * ORDER_NONE 224 * @param tsign 225 * the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and MSGN 226 * @param tbase 227 * the base datatype of the new datatype 228 * @param pbase 229 * the parent datatype of the new datatype 230 */ 231 public H5Datatype(int tclass, int tsize, int torder, int tsign, Datatype tbase, Datatype pbase) { 232 this(tclass, tsize, torder, tsign, tbase, pbase, null); 233 } 234 235 /** 236 * Constructs a Datatype with specified class, size, byte order and sign. 237 * <p> 238 * The following is a list of a few example of H5Datatype. 239 * <ol> 240 * <li>to create unsigned native integer<br> 241 * H5Datatype type = new H5Dataype(CLASS_INTEGER, NATIVE, NATIVE, SIGN_NONE); 242 * <li>to create 16-bit signed integer with big endian<br> 243 * H5Datatype type = new H5Dataype(CLASS_INTEGER, 2, ORDER_BE, NATIVE); 244 * <li>to create native float<br> 245 * H5Datatype type = new H5Dataype(CLASS_FLOAT, NATIVE, NATIVE, -1); 246 * <li>to create 64-bit double<br> 247 * H5Datatype type = new H5Dataype(CLASS_FLOAT, 8, NATIVE, -1); 248 * </ol> 249 * 250 * @param tclass 251 * the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc. 252 * @param tsize 253 * the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4. 254 * @param torder 255 * the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX and 256 * ORDER_NONE 257 * @param tsign 258 * the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and MSGN 259 * @param tbase 260 * the base datatype of the new datatype 261 * @param pbase 262 * the parent datatype of the new datatype 263 * @param members 264 * the list of member datatypes 265 */ 266 public H5Datatype(int tclass, int tsize, int torder, int tsign, Datatype tbase, Datatype pbase, List<H5Datatype> members) { 267 super(tclass, tsize, torder, tsign, tbase, pbase); 268 if (members == null) { 269 compoundMemberTypes = new Vector<>(); 270 } 271 else { 272 compoundMemberTypes = new Vector<>(members.size()); 273 compoundMemberTypes.addAll(members); 274 } 275 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(CLASS_INTEGER, 4, NATIVE, SIGN_NONE); 290 * 291 * @see #fromNative(long nativeID) 292 * 293 * @param nativeID 294 * the native datatype identifier. 295 */ 296 public H5Datatype(long nativeID) { 297 this(nativeID, null); 298 } 299 300 /** 301 * Constructs a Datatype with a given native datatype identifier. 302 * <p> 303 * For example, if the datatype identifier is a 32-bit unsigned integer created from HDF5, 304 * 305 * <pre> 306 * int tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_UNINT32); 307 * Datatype dtype = new Datatype(tid); 308 * </pre> 309 * 310 * will construct a datatype equivalent to new Datatype(CLASS_INTEGER, 4, NATIVE, SIGN_NONE); 311 * 312 * @see #fromNative(long nativeID) 313 * 314 * @param nativeID 315 * the native datatype identifier. 316 * @param pbase 317 * the parent datatype of the new datatype 318 */ 319 public H5Datatype(long nativeID, Datatype pbase) { 320 super(nativeID, pbase); 321 fromNative(nativeID); 322 datatypeDescription = getDescription(); 323 } 324 325 /** 326 * Opens access to a named datatype. 327 * <p> 328 * It calls H5.H5Topen(loc, name). 329 * 330 * @return the datatype identifier if successful; otherwise returns negative value. 331 * 332 * @see hdf.hdf5lib.H5#H5Topen(long, String, long) 333 */ 334 @Override 335 public long open() { 336 log.trace("open(): start"); 337 long tid = -1; 338 339 try { 340 tid = H5.H5Topen(getFID(), getPath() + getName(), HDF5Constants.H5P_DEFAULT); 341 } 342 catch (HDF5Exception ex) { 343 tid = -1; 344 } 345 346 log.trace("open(): finish"); 347 return tid; 348 } 349 350 /** 351 * Closes a datatype identifier. 352 * <p> 353 * It calls H5.H5close(tid). 354 * 355 * @param tid 356 * the datatype ID to close 357 */ 358 @Override 359 public void close(long tid) { 360 if (tid >= 0) { 361 try { 362 H5.H5Tclose(tid); 363 } 364 catch (HDF5Exception ex) { 365 log.debug("close(): H5Tclose(tid {}) failure: ", tid, ex); 366 } 367 } 368 } 369 370 /* 371 * (non-Javadoc) 372 * 373 * @see hdf.object.DataFormat#hasAttribute() 374 */ 375 @Override 376 public boolean hasAttribute() { 377 obj_info.num_attrs = nAttributes; 378 379 if (obj_info.num_attrs < 0) { 380 long tid = -1; 381 try { 382 tid = H5.H5Topen(getFID(), getPath() + getName(), HDF5Constants.H5P_DEFAULT); 383 fromNative(tid); 384 obj_info = H5.H5Oget_info(tid); 385 isNamed = true; 386 } 387 catch (Exception ex) { 388 obj_info.num_attrs = 0; 389 } 390 finally { 391 close(tid); 392 } 393 } 394 395 log.trace("hasAttribute(): nAttributes={}", obj_info.num_attrs); 396 397 return (obj_info.num_attrs > 0); 398 } 399 400 /** 401 * Converts values in an Enumeration Datatype to names. 402 * <p> 403 * This method searches the identified enumeration datatype for the values appearing in 404 * <code>inValues</code> and returns the names corresponding to those values. If a given value is 405 * not found in the enumeration datatype, the name corresponding to that value will be set to 406 * <code>"ENUM ERR value"</code> in the string array that is returned. 407 * <p> 408 * If the method fails in general, null will be returned instead of a String array. An empty 409 * <code>inValues</code> parameter would cause general failure. 410 * 411 * @param inValues 412 * The array of enumerations values to be converted. 413 * 414 * @return The string array of names if successful; otherwise return null. 415 * 416 * @throws HDF5Exception 417 * If there is an error at the HDF5 library level. 418 * 419 */ 420 public String[] convertEnumValueToName(Object inValues) throws HDF5Exception { 421 log.trace("convertEnumValueToName() inValues={} start", inValues); 422 int inSize = 0; 423 String[] outNames = null; 424 String cName = inValues.getClass().getName(); 425 boolean isArray = cName.lastIndexOf("[") >= 0; 426 if (isArray) { 427 inSize = Array.getLength(inValues); 428 } 429 else { 430 inSize = 1; 431 } 432 433 if ((inValues == null) || (inSize <= 0)) { 434 log.debug("convertEnumValueToName() failure: in values null or inSize length invalid"); 435 log.debug("convertEnumValueToName(): inValues={} inSize={}", inValues, inSize); 436 log.trace("convertEnumValueToName(): finish"); 437 return null; 438 } 439 440 if (enumMembers == null || enumMembers.size() <= 0) { 441 log.debug("convertEnumValueToName(): no members"); 442 log.trace("convertEnumValueToName(): finish"); 443 return null; 444 } 445 446 log.trace("convertEnumValueToName(): inSize={} nMembers={} enums={}", inSize, enumMembers.size(), enumMembers); 447 outNames = new String[inSize]; 448 for (int i = 0; i < inSize; i++) { 449 if (isArray) { 450 if (enumMembers.containsKey(String.valueOf(Array.get(inValues, i)))) { 451 outNames[i] = enumMembers.get(String.valueOf(Array.get(inValues, i))); 452 } 453 else { 454 outNames[i] = "**ENUM ERR " + String.valueOf(Array.get(inValues, i)) + "**"; 455 } 456 } 457 else { 458 if (enumMembers.containsKey(String.valueOf(inValues))) { 459 outNames[i] = enumMembers.get(String.valueOf(inValues)); 460 } 461 else { 462 outNames[i] = "**ENUM ERR " + String.valueOf(inValues) + "**"; 463 } 464 } 465 } 466 467 log.trace("convertEnumValueToName(): finish"); 468 return outNames; 469 } 470 471 /** 472 * Converts names in an Enumeration Datatype to values. 473 * <p> 474 * This method searches the identified enumeration datatype for the names appearing in 475 * <code>inValues</code> and returns the values corresponding to those names. 476 * 477 * @param in 478 * The array of enumerations names to be converted. 479 * 480 * @return The int array of values if successful; otherwise return null. 481 * 482 * @throws HDF5Exception 483 * If there is an error at the HDF5 library level. 484 * 485 */ 486 public Object[] convertEnumNameToValue(String[] in) throws HDF5Exception { 487 log.trace("convertEnumNameToValue() start"); 488 int size = 0; 489 490 if ((in == null) || ((size = Array.getLength(in)) <= 0)) { 491 log.debug("convertEnumNameToValue() failure: in values null or in size not valid"); 492 log.debug("convertEnumNameToValue(): in={} inSize={}", in.toString(), in.length); 493 log.trace("convertEnumNameToValue(): finish"); 494 return null; 495 } 496 497 if (enumMembers == null || enumMembers.size() <= 0) { 498 log.debug("convertEnumNameToValue(): no members"); 499 log.trace("convertEnumNameToValue(): finish"); 500 return null; 501 } 502 503 Object[] out = null; 504 if (datatypeSize == 1) { 505 out = new Byte[size]; 506 } 507 else if (datatypeSize == 2) { 508 out = new Short[size]; 509 } 510 else if (datatypeSize == 4) { 511 out = new Integer[size]; 512 } 513 else if (datatypeSize == 8) { 514 out = new Long[size]; 515 } 516 else { 517 out = new Object[size]; 518 } 519 520 for (int i = 0; i < size; i++) { 521 if (in[i] == null || in[i].length() <= 0) 522 continue; 523 524 for (Entry<String, String> entry : enumMembers.entrySet()) { 525 if (Objects.equals(in[i], entry.getValue())) { 526 if (datatypeSize == 1) { 527 log.trace("convertEnumNameToValue(): ENUM is H5T_NATIVE_INT8"); 528 out[i] = Byte.parseByte(entry.getKey()); 529 } 530 else if (datatypeSize == 2) { 531 log.trace("convertEnumNameToValue(): CLASS_INT-ENUM is H5T_NATIVE_INT16"); 532 out[i] = Short.parseShort(entry.getKey()); 533 } 534 else if (datatypeSize == 4) { 535 log.trace("convertEnumNameToValue(): CLASS_INT-ENUM is H5T_NATIVE_INT32"); 536 out[i] = Integer.parseInt(entry.getKey()); 537 } 538 else if (datatypeSize == 8) { 539 log.trace("convertEnumNameToValue(): CLASS_INT-ENUM is H5T_NATIVE_INT64"); 540 out[i] = Long.parseLong(entry.getKey()); 541 } 542 else { 543 log.debug("convertEnumNameToValue(): enum datatypeSize incorrect"); 544 out[i] = -1; 545 } 546 break; 547 } 548 } 549 } 550 551 log.trace("convertEnumNameToValue(): finish"); 552 return out; 553 } 554 555 /* 556 * (non-Javadoc) 557 * 558 * @see hdf.object.Datatype#fromNative(int) 559 */ 560 @Override 561 public void fromNative(long tid) { 562 log.trace("fromNative(): start: tid={}", tid); 563 long tsize = -1; 564 int torder = -1; 565 boolean isChar = false, isUchar = false; 566 567 if (tid < 0) { 568 datatypeClass = CLASS_NO_CLASS; 569 } 570 else { 571 try { 572 nativeClass = H5.H5Tget_class(tid); 573 tsize = H5.H5Tget_size(tid); 574 torder = H5.H5Tget_order(tid); 575 is_variable_str = H5.H5Tis_variable_str(tid); 576 is_VLEN = false; 577 log.trace("fromNative(): tclass={}, tsize={}, torder={}, isVLEN={}", nativeClass, tsize, torder, is_VLEN); 578 } 579 catch (Exception ex) { 580 log.debug("fromNative(): failure: ", ex); 581 datatypeClass = CLASS_NO_CLASS; 582 } 583 584 datatypeOrder = (torder == HDF5Constants.H5T_ORDER_BE) ? ORDER_BE : ORDER_LE; 585 586 try { 587 isUchar = H5.H5Tequal(tid, HDF5Constants.H5T_NATIVE_UCHAR); 588 isChar = (H5.H5Tequal(tid, HDF5Constants.H5T_NATIVE_CHAR) || isUchar); 589 } 590 catch (Exception ex) { 591 log.debug("fromNative(): native char type failure: ", ex); 592 } 593 594 datatypeSign = NSGN; // default 595 if (nativeClass == HDF5Constants.H5T_ARRAY) { 596 long tmptid = -1; 597 datatypeClass = CLASS_ARRAY; 598 try { 599 int ndims = H5.H5Tget_array_ndims(tid); 600 arrayDims = new long[ndims]; 601 H5.H5Tget_array_dims(tid, arrayDims); 602 tmptid = H5.H5Tget_super(tid); 603 baseType = new H5Datatype(tmptid); 604 datatypeSign = baseType.getDatatypeSign(); 605 } 606 catch (Exception ex) { 607 log.debug("fromNative(): array type failure: ", ex); 608 } 609 finally { 610 close(tmptid); 611 } 612 log.trace("fromNative(): array type finish"); 613 } 614 else if (nativeClass == HDF5Constants.H5T_COMPOUND) { 615 datatypeClass = CLASS_COMPOUND; 616 617 try { 618 int nMembers = H5.H5Tget_nmembers(tid); 619 compoundMemberNames = new Vector<>(nMembers); 620 compoundMemberTypes = new Vector<>(nMembers); 621 compoundMemberOffsets = new Vector<>(nMembers); 622 log.trace("fromNative(): compound type nMembers={} start", nMembers); 623 624 for (int i = 0; i < nMembers; i++) { 625 String memberName = H5.H5Tget_member_name(tid, i); 626 log.trace("fromNative(): compound type [{}] name={} start", i, memberName); 627 long memberOffset = H5.H5Tget_member_offset(tid, i); 628 long memberID = -1; 629 H5Datatype membertype = null; 630 try { 631 memberID = H5.H5Tget_member_type(tid, i); 632 membertype = new H5Datatype(memberID, this); 633 } 634 catch (Exception ex1) { 635 log.debug("fromNative(): compound type failure: ", ex1); 636 } 637 finally { 638 close(memberID); 639 } 640 641 compoundMemberNames.add(i, memberName); 642 compoundMemberOffsets.add(i, memberOffset); 643 compoundMemberTypes.add(i, membertype); 644 log.trace("fromNative(): compound type [{}] name={} finish", i, memberName); 645 } 646 } 647 catch (HDF5LibraryException ex) { 648 log.debug("fromNative(): compound type failure: ", ex); 649 } 650 log.trace("fromNative(): compound type finish"); 651 } 652 else if (nativeClass == HDF5Constants.H5T_INTEGER) { 653 datatypeClass = CLASS_INTEGER; 654 try { 655 log.trace("fromNative(): integer type"); 656 int tsign = H5.H5Tget_sign(tid); 657 datatypeSign = (tsign == HDF5Constants.H5T_SGN_NONE) ? SIGN_NONE : SIGN_2; 658 } 659 catch (Exception ex) { 660 log.debug("fromNative(): int type failure: ", ex); 661 } 662 } 663 else if (nativeClass == HDF5Constants.H5T_FLOAT) { 664 datatypeClass = CLASS_FLOAT; 665 } 666 else if (isChar) { 667 datatypeClass = CLASS_CHAR; 668 datatypeSign = (isUchar) ? SIGN_NONE : SIGN_2; 669 } 670 else if (nativeClass == HDF5Constants.H5T_STRING) { 671 datatypeClass = CLASS_STRING; 672 try { 673 is_VLEN = H5.H5Tdetect_class(tid, HDF5Constants.H5T_VLEN) || is_variable_str; 674 log.trace("fromNative(): var str type={}", is_VLEN); 675 nativeStrPad = H5.H5Tget_strpad(tid); 676 } 677 catch (Exception ex) { 678 log.debug("fromNative(): var str type failure: ", ex); 679 } 680 } 681 else if (nativeClass == HDF5Constants.H5T_REFERENCE) { 682 datatypeClass = CLASS_REFERENCE; 683 log.trace("fromNative(): reference type"); 684 try { 685 is_reg_ref = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF_DSETREG); 686 } 687 catch (Exception ex) { 688 log.debug("fromNative(): H5T_STD_REF_DSETREG: ", ex); 689 } 690 try { 691 is_ref_obj = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF_OBJ); 692 } 693 catch (Exception ex) { 694 log.debug("fromNative(): H5T_STD_REF_OBJ: ", ex); 695 } 696 } 697 else if (nativeClass == HDF5Constants.H5T_ENUM) { 698 datatypeClass = CLASS_ENUM; 699 long tmptid = -1; 700 long basetid = -1; 701 try { 702 log.trace("fromNative(): enum type"); 703 basetid = H5.H5Tget_super(tid); 704 tmptid = basetid; 705 basetid = H5.H5Tget_native_type(tmptid); 706 log.trace("fromNative(): enum type basetid={}", basetid); 707 if (basetid >= 0) { 708 baseType = new H5Datatype(tmptid, this); 709 datatypeSign = baseType.getDatatypeSign(); 710 } 711 } 712 catch (Exception ex) { 713 log.debug("fromNative(): enum type failure: ", ex); 714 } 715 finally { 716 close(tmptid); 717 close(basetid); 718 } 719 try { 720 int enumMemberCount = H5.H5Tget_nmembers(tid); 721 String name = null; 722 String enumStr = null; 723 byte[] val = new byte[(int)tsize]; 724 enumMembers = new HashMap<>(); 725 for (int i = 0; i < enumMemberCount; i++) { 726 name = H5.H5Tget_member_name(tid, i); 727 H5.H5Tget_member_value(tid, i, val); 728 switch ((int)H5.H5Tget_size(tid)) { 729 case 1: 730 enumStr = Byte.toString((HDFNativeData.byteToByte(val[0]))[0]); 731 break; 732 case 2: 733 enumStr = Short.toString((HDFNativeData.byteToShort(val))[0]); 734 break; 735 case 4: 736 enumStr = Integer.toString((HDFNativeData.byteToInt(val))[0]); 737 break; 738 case 8: 739 enumStr = Long.toString((HDFNativeData.byteToLong(val))[0]); 740 break; 741 default: 742 enumStr = "-1"; 743 break; 744 } 745 enumMembers.put(enumStr, name); 746 } 747 } 748 catch (Exception ex) { 749 log.debug("fromNative(): enum type failure: ", ex); 750 } 751 } 752 else if (nativeClass == HDF5Constants.H5T_VLEN) { 753 long tmptid = -1; 754 datatypeClass = CLASS_VLEN; 755 is_VLEN = true; 756 try { 757 log.trace("fromNative(): vlen type"); 758 tmptid = H5.H5Tget_super(tid); 759 baseType = new H5Datatype(tmptid); 760 datatypeSign = baseType.getDatatypeSign(); 761 } 762 catch (Exception ex) { 763 log.debug("fromNative(): vlen type failure: ", ex); 764 } 765 finally { 766 close(tmptid); 767 } 768 } 769 else if (nativeClass == HDF5Constants.H5T_BITFIELD) { 770 datatypeClass = CLASS_BITFIELD; 771 } 772 else if (nativeClass == HDF5Constants.H5T_OPAQUE) { 773 datatypeClass = CLASS_OPAQUE; 774 775 try { 776 opaqueTag = H5.H5Tget_tag(tid); 777 } 778 catch (Exception ex) { 779 log.debug("fromNative(): opaque type tag retrieval failed: ", ex); 780 opaqueTag = null; 781 } 782 } 783 else { 784 log.debug("fromNative(): datatypeClass is unknown"); 785 } 786 787 datatypeSize = (is_VLEN && !is_variable_str) ? HDF5Constants.H5T_VL_T : tsize; 788 } 789 log.trace("fromNative(): datatypeClass={} baseType={} datatypeSize={}", datatypeClass, baseType, datatypeSize); 790 log.trace("fromNative(): finish"); 791 } 792 793 /** 794 * @param tid 795 * the datatype identification disk. 796 * 797 * @return the memory datatype identifier if successful, and negative otherwise. 798 */ 799 public static long toNative(long tid) { 800 // data type information 801 log.trace("toNative(): tid={} start", tid); 802 long native_id = -1; 803 804 try { 805 native_id = H5.H5Tget_native_type(tid); 806 } 807 catch (Exception ex) { 808 log.debug("toNative(): H5Tget_native_type(tid {}) failure: ", tid, ex); 809 } 810 811 try { 812 if (H5.H5Tis_variable_str(tid)) 813 H5.H5Tset_size(native_id, HDF5Constants.H5T_VARIABLE); 814 } 815 catch (Exception ex) { 816 log.debug("toNative(): var str type size failure: ", ex); 817 } 818 819 return native_id; 820 } 821 822 /* 823 * (non-Javadoc) 824 * 825 * @see hdf.object.Datatype#createNative() 826 */ 827 @SuppressWarnings("rawtypes") 828 @Override 829 public long createNative() { 830 log.trace("createNative(): start"); 831 832 long tid = -1; 833 long tmptid = -1; 834 835 if (isNamed) { 836 try { 837 tid = H5.H5Topen(getFID(), getPath() + getName(), HDF5Constants.H5P_DEFAULT); 838 } 839 catch (Exception ex) { 840 log.debug("createNative(): name {} H5Topen failure: ", getPath() + getName(), ex); 841 } 842 } 843 844 if (tid >= 0) { 845 log.trace("createNative(): tid >= 0"); 846 log.trace("createNative(): finish"); 847 return tid; 848 } 849 850 // figure the datatype 851 try { 852 log.trace("createNative(): datatypeClass={} datatypeSize={} baseType={}", datatypeClass, datatypeSize, baseType); 853 switch (datatypeClass) { 854 case CLASS_ARRAY: 855 if (baseType != null) { 856 if ((tmptid = baseType.createNative()) >= 0) { 857 try { 858 tid = H5.H5Tarray_create(tmptid, arrayDims.length, arrayDims); 859 } 860 finally { 861 close(tmptid); 862 } 863 } 864 } 865 else { 866 log.debug("createNative(): CLASS_ARRAY base type is NULL"); 867 } 868 break; 869 case CLASS_COMPOUND: 870 try { 871 tid = H5.H5Tcreate(CLASS_COMPOUND, datatypeSize); 872 873 for (int i = 0; i < compoundMemberTypes.size(); i++) { 874 H5Datatype memberType = null; 875 String memberName = null; 876 long memberOffset = -1; 877 878 try { 879 memberType = (H5Datatype) compoundMemberTypes.get(i); 880 } 881 catch (Exception ex) { 882 log.debug("createNative(): get compound member[{}] type failure: ", i, ex); 883 memberType = null; 884 } 885 886 try { 887 memberName = compoundMemberNames.get(i); 888 } 889 catch (Exception ex) { 890 log.debug("createNative(): get compound member[{}] name failure: ", i, ex); 891 memberName = null; 892 } 893 894 try { 895 memberOffset = compoundMemberOffsets.get(i); 896 } 897 catch (Exception ex) { 898 log.debug("createNative(): get compound member[{}] offset failure: ", i, ex); 899 memberOffset = -1; 900 } 901 902 long memberID = -1; 903 try { 904 memberID = memberType.createNative(); 905 log.trace("createNative(): {} member[{}] with offset={} ID={}: ", memberName, i, memberOffset, memberID); 906 907 H5.H5Tinsert(tid, memberName, memberOffset, memberID); 908 } 909 catch (Exception ex) { 910 log.debug("createNative(): compound type member[{}] insertion failure: ", i, ex); 911 } 912 finally { 913 close(memberID); 914 } 915 } 916 } 917 catch (Exception ex) { 918 log.debug("createNative(): failure: ", ex); 919 } 920 break; 921 case CLASS_INTEGER: 922 case CLASS_ENUM: 923 if (datatypeSize == 1) { 924 log.trace("createNative(): CLASS_INT-ENUM is H5T_NATIVE_INT8"); 925 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT8); 926 } 927 else if (datatypeSize == 2) { 928 log.trace("createNative(): CLASS_INT-ENUM is H5T_NATIVE_INT16"); 929 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT16); 930 } 931 else if (datatypeSize == 4) { 932 log.trace("createNative(): CLASS_INT-ENUM is H5T_NATIVE_INT32"); 933 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT32); 934 } 935 else if (datatypeSize == 8) { 936 log.trace("createNative(): CLASS_INT-ENUM is H5T_NATIVE_INT64"); 937 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT64); 938 } 939 else { 940 log.trace("createNative(): CLASS_INT-ENUM is H5T_NATIVE_INT"); 941 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT); 942 } 943 944 if (datatypeOrder == Datatype.ORDER_BE) { 945 log.trace("createNative(): CLASS_INT-ENUM order is H5T_ORDER_BE"); 946 H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE); 947 } 948 else if (datatypeOrder == Datatype.ORDER_LE) { 949 log.trace("createNative(): CLASS_INT-ENUM order is H5T_ORDER_LE"); 950 H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE); 951 } 952 953 if (datatypeSign == Datatype.SIGN_NONE) { 954 log.trace("createNative(): CLASS_INT-ENUM is H5T_SGN_NONE"); 955 H5.H5Tset_sign(tid, HDF5Constants.H5T_SGN_NONE); 956 } 957 break; 958 case CLASS_FLOAT: 959 tid = H5.H5Tcopy((datatypeSize == 8) ? HDF5Constants.H5T_NATIVE_DOUBLE : HDF5Constants.H5T_NATIVE_FLOAT); 960 961 if (datatypeOrder == Datatype.ORDER_BE) { 962 H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE); 963 } 964 else if (datatypeOrder == Datatype.ORDER_LE) { 965 H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE); 966 } 967 968 break; 969 case CLASS_CHAR: 970 tid = H5.H5Tcopy((datatypeSign == Datatype.SIGN_NONE) ? HDF5Constants.H5T_NATIVE_UCHAR : HDF5Constants.H5T_NATIVE_CHAR); 971 break; 972 case CLASS_STRING: 973 tid = H5.H5Tcopy(HDF5Constants.H5T_C_S1); 974 H5.H5Tset_size(tid, (is_VLEN || datatypeSize < 0) ? HDF5Constants.H5T_VARIABLE : datatypeSize); 975 976 log.trace("createNative(): isVlenStr={}", is_VLEN); 977 978 H5.H5Tset_strpad(tid, (nativeStrPad >= 0) ? nativeStrPad : HDF5Constants.H5T_STR_NULLTERM); 979 980 break; 981 case CLASS_REFERENCE: 982 long obj_ref_type_size = H5.H5Tget_size(HDF5Constants.H5T_STD_REF_OBJ); 983 tid = H5.H5Tcopy((datatypeSize > obj_ref_type_size) ? HDF5Constants.H5T_STD_REF_DSETREG : HDF5Constants.H5T_STD_REF_OBJ); 984 break; 985 case CLASS_VLEN: 986 if (baseType != null) { 987 if ((tmptid = baseType.createNative()) >= 0) { 988 try { 989 tid = H5.H5Tvlen_create(tmptid); 990 } 991 finally { 992 close(tmptid); 993 } 994 } 995 } 996 else { 997 log.debug("createNative(): CLASS_VLEN base type is NULL"); 998 } 999 break; 1000 case CLASS_BITFIELD: 1001 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B8); 1002 1003 log.trace("createNative(): CLASS_BITFIELD size is " + datatypeSize); 1004 if (datatypeSize > 0) H5.H5Tset_size(tid, datatypeSize); 1005 1006 if (datatypeOrder == Datatype.ORDER_BE) { 1007 log.trace("createNative(): CLASS_BITFIELD-OPAQUE order is H5T_ORDER_BE"); 1008 H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE); 1009 } 1010 else if (datatypeOrder == Datatype.ORDER_LE) { 1011 log.trace("createNative(): CLASS_BITFIELD-OPAQUE order is H5T_ORDER_LE"); 1012 H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE); 1013 } 1014 1015 break; 1016 case CLASS_OPAQUE: 1017 tid = H5.H5Tcreate(HDF5Constants.H5T_OPAQUE, datatypeSize); 1018 1019 if (opaqueTag != null) { 1020 H5.H5Tset_tag(tid, opaqueTag); 1021 } 1022 1023 break; 1024 default: 1025 log.debug("createNative(): Unknown class"); 1026 break; 1027 } // switch (tclass) 1028 } 1029 catch (Exception ex) { 1030 log.debug("createNative(): Error figuring the datatype: ", ex); 1031 tid = -1; 1032 } 1033 1034 // set up enum members 1035 if (datatypeClass == CLASS_ENUM) { 1036 long ptid = tid; 1037 try { 1038 tid = H5.H5Tenum_create(ptid); 1039 datatypeSize = H5.H5Tget_size(tid); 1040 } 1041 catch (Exception ex) { 1042 log.debug("createNative(): create members failure: ", ex); 1043 tid = -1; 1044 } 1045 1046 try { 1047 String memstr, memname; 1048 byte[] memval = null; 1049 if (datatypeSize == 1) { 1050 memval = HDFNativeData.byteToByte(new Byte((byte) 0)); 1051 } 1052 else if (datatypeSize == 2) { 1053 memval = HDFNativeData.shortToByte(new Short((short) 0)); 1054 } 1055 else if (datatypeSize == 4) { 1056 memval = HDFNativeData.intToByte(new Integer(0)); 1057 } 1058 else if (datatypeSize == 8) { 1059 memval = HDFNativeData.longToByte(new Long(0)); 1060 } 1061 1062 // using "0" and "1" as default 1063 if (enumMembers == null) { 1064 enumMembers = new HashMap<>(); 1065 enumMembers.put("1", "0"); 1066 enumMembers.put("2", "1"); 1067 log.trace("createNative(): default string"); 1068 } 1069 Iterator entries = enumMembers.entrySet().iterator(); 1070 while (entries.hasNext()) { 1071 Entry thisEntry = (Entry) entries.next(); 1072 memstr = (String) thisEntry.getKey(); 1073 memname = (String) thisEntry.getValue(); 1074 1075 if (datatypeSize == 1) { 1076 log.trace("createNative(): CLASS_INT-ENUM is H5T_NATIVE_INT8"); 1077 Byte tval = Byte.parseByte(memstr); 1078 memval = HDFNativeData.byteToByte(tval); 1079 } 1080 else if (datatypeSize == 2) { 1081 log.trace("createNative(): CLASS_INT-ENUM is H5T_NATIVE_INT16"); 1082 Short tval = Short.parseShort(memstr); 1083 memval = HDFNativeData.shortToByte(tval); 1084 } 1085 else if (datatypeSize == 4) { 1086 log.trace("createNative(): CLASS_INT-ENUM is H5T_NATIVE_INT32"); 1087 Integer tval = Integer.parseInt(memstr); 1088 memval = HDFNativeData.intToByte(tval); 1089 } 1090 else if (datatypeSize == 8) { 1091 log.trace("createNative(): CLASS_INT-ENUM is H5T_NATIVE_INT64"); 1092 Long tval = Long.parseLong(memstr); 1093 memval = HDFNativeData.longToByte(tval); 1094 } 1095 else { 1096 log.debug("createNative(): enum datatypeSize incorrect"); 1097 } 1098 log.trace("createNative(): H5Tenum_insert {} {}", memname, memval); 1099 H5.H5Tenum_insert(tid, memname, memval); 1100 } 1101 } 1102 catch (Exception ex) { 1103 log.debug("createNative(): set up enum members failure: ", ex); 1104 } 1105 finally { 1106 close(ptid); 1107 } 1108 } // if (datatypeClass == CLASS_ENUM) { 1109 1110 try { 1111 tmptid = tid; 1112 tid = H5.H5Tget_native_type(tmptid); 1113 } 1114 catch (HDF5Exception ex) { 1115 log.debug("createNative(): H5Tget_native_type{} failure: ", tmptid, ex); 1116 } 1117 finally { 1118 close(tmptid); 1119 } 1120 1121 return tid; 1122 } 1123 1124 /** 1125 * Allocates a one-dimensional array of byte, short, int, long, float, double, 1126 * or String to store data in memory. 1127 * 1128 * For example, 1129 * 1130 * <pre> 1131 * long tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT32); 1132 * int[] data = (int[]) allocateArray(100); 1133 * </pre> 1134 * 1135 * returns a 32-bit integer array of size 100. 1136 * 1137 * @param spaceSize 1138 * the total number of data points of the array. 1139 * 1140 * @return the array object if successful; otherwise, return null. 1141 * 1142 * @throws OutOfMemoryError 1143 * If there is a failure. 1144 */ 1145 public Object allocateArray(int spaceSize) throws OutOfMemoryError { 1146 log.trace("allocateArray(): start: spaceSize={}", spaceSize); 1147 Object data = null; 1148 1149 if (spaceSize < 0) { 1150 log.debug("allocateArray(): spaceSize < 0"); 1151 log.trace("allocateArray(): finish"); 1152 return null; 1153 } 1154 1155 // Scalar members have dimensionality zero, i.e. size =0 1156 // what can we do about it, set the size to 1 1157 if (spaceSize == 0) { 1158 spaceSize = 1; 1159 } 1160 1161 log.trace("allocateArray(): tclass={} : tsize={}", nativeClass, datatypeSize); 1162 1163 if (is_variable_str || is_VLEN || is_reg_ref) { 1164 log.trace("allocateArray(): is_variable_str={} || isVL={} || is_reg_ref={}", is_variable_str, is_VLEN, is_reg_ref); 1165 data = new String[spaceSize]; 1166 for (int i = 0; i < spaceSize; i++) { 1167 ((String[]) data)[i] = ""; 1168 } 1169 } 1170 else if (nativeClass == HDF5Constants.H5T_INTEGER) { 1171 log.trace("allocateArray(): class.H5T_INTEGER={}", nativeClass); 1172 if (datatypeSize == 1) { 1173 data = new byte[spaceSize]; 1174 } 1175 else if (datatypeSize == 2) { 1176 data = new short[spaceSize]; 1177 } 1178 else if (datatypeSize == 4) { 1179 data = new int[spaceSize]; 1180 } 1181 else if (datatypeSize == 8) { 1182 data = new long[spaceSize]; 1183 } 1184 } 1185 else if (nativeClass == HDF5Constants.H5T_ENUM) { 1186 log.trace("allocateArray(): class.H5T_ENUM={}", nativeClass); 1187 if (baseType != null) 1188 data = ((H5Datatype) baseType).allocateArray(spaceSize); 1189 else 1190 data = new byte[(int) (spaceSize * datatypeSize)]; 1191 } 1192 else if (nativeClass == HDF5Constants.H5T_COMPOUND) { 1193 log.trace("allocateArray(): class.H5T_COMPOUND={}", nativeClass); 1194 if (baseType != null) 1195 data = ((H5Datatype) baseType).allocateArray((spaceSize)); 1196 else 1197 data = new byte[(int) (spaceSize * datatypeSize)]; 1198 } 1199 else if (nativeClass == HDF5Constants.H5T_FLOAT) { 1200 log.trace("allocateArray(): class.H5T_FLOAT={}", nativeClass); 1201 if (datatypeSize == 4) { 1202 data = new float[spaceSize]; 1203 } 1204 else if (datatypeSize == 8) { 1205 data = new double[spaceSize]; 1206 } 1207 } 1208 else if ((nativeClass == HDF5Constants.H5T_STRING) || (nativeClass == HDF5Constants.H5T_REFERENCE)) { 1209 log.trace("allocateArray(): class.H5T_STRING || H5T_REFERENCE={}", nativeClass); 1210 data = new byte[(int) (spaceSize * datatypeSize)]; 1211 } 1212 else if (nativeClass == HDF5Constants.H5T_ARRAY) { 1213 // use the base datatype to define the array 1214 try { 1215 log.trace("allocateArray(): ArrayRank={}", arrayDims.length); 1216 int asize = spaceSize; 1217 for (int j = 0; j < arrayDims.length; j++) { 1218 log.trace("allocateArray(): ArrayRank={} : dims[{}]={}", arrayDims.length, j, arrayDims[j]); 1219 asize *= arrayDims[j]; 1220 } 1221 log.trace("allocateArray(): class.H5T_ARRAY={} : members={} : asize={} : datatypeSize={}", nativeClass, arrayDims.length, asize, datatypeSize); 1222 1223 if (baseType != null) { 1224 // data = new byte[(int) (size * asize * datatypeSize)]; 1225 data = ((H5Datatype) baseType).allocateArray(asize); 1226 } 1227 } 1228 catch (Exception ex) { 1229 log.debug("allocateArray(): H5T_ARRAY class failure: ", ex); 1230 } 1231 } 1232 else if ((nativeClass == HDF5Constants.H5T_OPAQUE) || (nativeClass == HDF5Constants.H5T_BITFIELD)) { 1233 log.trace("allocateArray(): class.H5T_OPAQUE || H5T_BITFIELD={}", nativeClass); 1234 data = new byte[(int) (spaceSize * datatypeSize)]; 1235 } 1236 else { 1237 log.debug("allocateArray(): class.????={}", nativeClass); 1238 data = null; 1239 } 1240 1241 return data; 1242 } 1243 1244 /** 1245 * Returns the size (in bytes) of a given datatype identifier. 1246 * <p> 1247 * It basically just calls H5Tget_size(tid). 1248 * 1249 * @param tid 1250 * The datatype identifier. 1251 * 1252 * @return The size of the datatype in bytes. 1253 * 1254 * @see hdf.hdf5lib.H5#H5Tget_size(long) 1255 */ 1256 public static final long getDatatypeSize(long tid) { 1257 // data type information 1258 long tsize = -1; 1259 1260 try { 1261 tsize = H5.H5Tget_size(tid); 1262 } 1263 catch (Exception ex) { 1264 tsize = -1; 1265 } 1266 1267 return tsize; 1268 } 1269 1270 /* 1271 * (non-Javadoc) 1272 * 1273 * @see hdf.object.Datatype#getDescription() 1274 */ 1275 @Override 1276 public String getDescription() { 1277 log.trace("getDescription(): start"); 1278 1279 if (datatypeDescription != null) { 1280 log.trace("getDescription(): finish"); 1281 return datatypeDescription; 1282 } 1283 1284 String description = null; 1285 long tid = -1; 1286 1287 switch (datatypeClass) { 1288 case CLASS_CHAR: 1289 description = "8-bit " + (isUnsigned() ? "unsigned " : "") + "integer"; 1290 break; 1291 case CLASS_INTEGER: 1292 description = String.valueOf(datatypeSize * 8) + "-bit " + (isUnsigned() ? "unsigned " : "") + "integer"; 1293 break; 1294 case CLASS_FLOAT: 1295 description = String.valueOf(datatypeSize * 8) + "-bit floating-point"; 1296 break; 1297 case CLASS_STRING: 1298 description = "String, length = " + (isVarStr() ? "variable" : datatypeSize); 1299 1300 try { 1301 tid = createNative(); 1302 if (tid >= 0) { 1303 String strPadType; 1304 int strPad = H5.H5Tget_strpad(tid); 1305 1306 if (strPad == HDF5Constants.H5T_STR_NULLTERM) 1307 strPadType = "H5T_STR_NULLTERM"; 1308 else if (strPad == HDF5Constants.H5T_STR_NULLPAD) 1309 strPadType = "H5T_STR_NULLPAD"; 1310 else if (strPad == HDF5Constants.H5T_STR_SPACEPAD) 1311 strPadType = "H5T_STR_SPACEPAD"; 1312 else 1313 strPadType = null; 1314 1315 if (strPadType != null) 1316 description += ", string padding = " + strPadType; 1317 } 1318 else { 1319 log.debug("createNative() failure"); 1320 } 1321 } 1322 catch (Exception ex) { 1323 log.debug("H5Tget_strpad failure: ", ex); 1324 } 1325 finally { 1326 close(tid); 1327 } 1328 break; 1329 case CLASS_BITFIELD: 1330 description = String.valueOf(datatypeSize * 8) + "-bit bitfield"; 1331 break; 1332 case CLASS_OPAQUE: 1333 description = String.valueOf(datatypeSize) + "-byte Opaque"; 1334 1335 if (opaqueTag != null) { 1336 description += ", tag = " + opaqueTag; 1337 } 1338 1339 break; 1340 case CLASS_COMPOUND: 1341 description = "Compound"; 1342 1343 if ((compoundMemberTypes != null) && (compoundMemberTypes.size() > 0)) { 1344 Iterator<String> member_names = null; 1345 Iterator<Datatype> member_types = compoundMemberTypes.iterator(); 1346 1347 if (compoundMemberNames != null) 1348 member_names = compoundMemberNames.iterator(); 1349 1350 description += " {"; 1351 1352 while (member_types.hasNext()) { 1353 if (member_names != null && member_names.hasNext()) { 1354 description += member_names.next() + " = "; 1355 } 1356 1357 description += member_types.next().getDescription(); 1358 1359 if (member_types.hasNext()) 1360 description += ", "; 1361 } 1362 1363 description += "}"; 1364 } 1365 1366 break; 1367 case CLASS_REFERENCE: 1368 description = "Reference"; 1369 1370 try { 1371 boolean is_reg_ref = false; 1372 1373 tid = createNative(); 1374 if (tid >= 0) { 1375 is_reg_ref = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF_DSETREG); 1376 1377 if (is_reg_ref) { 1378 description = "Dataset region reference"; 1379 } 1380 else { 1381 description = "Object reference"; 1382 } 1383 } 1384 } 1385 catch (Exception ex) { 1386 log.debug("H5.H5Tequal failure: ", ex); 1387 } 1388 finally { 1389 close(tid); 1390 } 1391 1392 break; 1393 case CLASS_ENUM: 1394 description = String.valueOf(datatypeSize * 8) + "-bit enum"; 1395 1396 String members = getEnumMembersAsString(); 1397 if (members != null) 1398 description += " (" + members + ")"; 1399 1400 break; 1401 case CLASS_VLEN: 1402 description = "Variable-length"; 1403 1404 if (baseType != null) { 1405 description += " of " + baseType.getDescription(); 1406 } 1407 1408 break; 1409 case CLASS_ARRAY: 1410 description = "Array"; 1411 1412 if (baseType != null) { 1413 description += " of " + baseType.getDescription(); 1414 } 1415 1416 if (arrayDims != null) { 1417 description += " ["; 1418 for (int i = 0; i < arrayDims.length; i++) { 1419 description += arrayDims[i]; 1420 if (i < arrayDims.length - 1) 1421 description += " x "; 1422 } 1423 description += "]"; 1424 } 1425 1426 break; 1427 default: 1428 description = "Unknown"; 1429 break; 1430 } 1431 1432 log.trace("getDescription(): finish"); 1433 return description; 1434 } 1435 1436 /** 1437 * Checks if a datatype specified by the identifier is an unsigned integer. 1438 * 1439 * @param tid 1440 * the datatype ID to be checked. 1441 * 1442 * @return true is the datatype is an unsigned integer; otherwise returns false. 1443 */ 1444 public static final boolean isUnsigned(long tid) { 1445 boolean unsigned = false; 1446 1447 if (tid >= 0) { 1448 try { 1449 int tclass = H5.H5Tget_class(tid); 1450 log.trace("isUnsigned(): tclass = {}", tclass); 1451 if (tclass != HDF5Constants.H5T_FLOAT && tclass != HDF5Constants.H5T_STRING 1452 && tclass != HDF5Constants.H5T_REFERENCE && tclass != HDF5Constants.H5T_BITFIELD 1453 && tclass != HDF5Constants.H5T_OPAQUE && tclass != HDF5Constants.H5T_VLEN 1454 && tclass != HDF5Constants.H5T_COMPOUND && tclass != HDF5Constants.H5T_ARRAY) { 1455 int tsign = H5.H5Tget_sign(tid); 1456 if (tsign == HDF5Constants.H5T_SGN_NONE) { 1457 unsigned = true; 1458 } 1459 else { 1460 log.trace("isUnsigned(): not unsigned"); 1461 } 1462 } 1463 else { 1464 log.trace("isUnsigned(): tclass not integer type"); 1465 } 1466 } 1467 catch (Exception ex) { 1468 log.debug("isUnsigned(): Datatype {} failure", tid, ex); 1469 unsigned = false; 1470 } 1471 } 1472 else { 1473 log.trace("isUnsigned(): not a valid datatype"); 1474 } 1475 1476 return unsigned; 1477 } 1478 1479 /* 1480 * (non-Javadoc) 1481 * 1482 * @see hdf.object.Datatype#getMetadata() 1483 */ 1484 @Override 1485 public List<Attribute> getMetadata() throws HDF5Exception { 1486 return this.getMetadata(fileFormat.getIndexType(null), fileFormat.getIndexOrder(null)); 1487 } 1488 1489 /* 1490 * (non-Javadoc) 1491 * 1492 * @see hdf.object.DataFormat#getMetadata(int...) 1493 */ 1494 public List<Attribute> getMetadata(int... attrPropList) throws HDF5Exception { 1495 log.trace("getMetadata(): start"); 1496 // load attributes first 1497 if (attributeList == null) { 1498 int indxType = fileFormat.getIndexType(null); 1499 int order = fileFormat.getIndexOrder(null); 1500 1501 if (attrPropList.length > 0) { 1502 indxType = attrPropList[0]; 1503 if (attrPropList.length > 1) { 1504 order = attrPropList[1]; 1505 } 1506 } 1507 1508 try { 1509 attributeList = H5File.getAttribute(this, indxType, order); 1510 } 1511 catch (Exception ex) { 1512 log.debug("getMetadata(): H5File.getAttribute failure: ", ex); 1513 } 1514 } // if (attributeList == null) 1515 1516 try { 1517 this.linkTargetObjName = H5File.getLinkTargetName(this); 1518 } 1519 catch (Exception ex) { 1520 log.debug("getMetadata(): H5File.linkTargetObjName failure: ", ex); 1521 } 1522 1523 log.trace("getMetadata(): finish"); 1524 return attributeList; 1525 } 1526 1527 /* 1528 * (non-Javadoc) 1529 * 1530 * @see hdf.object.Datatype#writeMetadata(java.lang.Object) 1531 */ 1532 @Override 1533 public void writeMetadata(Object info) throws Exception { 1534 log.trace("writeMetadata(): start"); 1535 1536 // only attribute metadata is supported. 1537 if (!(info instanceof Attribute)) { 1538 log.debug("writeMetadata(): Object not an Attribute"); 1539 log.trace("writeMetadata(): finish"); 1540 return; 1541 } 1542 1543 boolean attrExisted = false; 1544 Attribute attr = (Attribute) info; 1545 1546 if (attributeList == null) { 1547 this.getMetadata(); 1548 } 1549 1550 if (attributeList != null) 1551 attrExisted = attributeList.contains(attr); 1552 1553 getFileFormat().writeAttribute(this, attr, attrExisted); 1554 1555 // add the new attribute into attribute list 1556 if (!attrExisted) { 1557 attributeList.add(attr); 1558 nAttributes = attributeList.size(); 1559 } 1560 log.trace("writeMetadata(): finish"); 1561 } 1562 1563 /* 1564 * (non-Javadoc) 1565 * 1566 * @see hdf.object.Datatype#removeMetadata(java.lang.Object) 1567 */ 1568 @Override 1569 public void removeMetadata(Object info) throws HDF5Exception { 1570 log.trace("removeMetadata(): start"); 1571 1572 // only attribute metadata is supported. 1573 if (!(info instanceof Attribute)) { 1574 log.debug("removeMetadata(): Object not an attribute"); 1575 log.trace("removeMetadata(): finish"); 1576 return; 1577 } 1578 1579 Attribute attr = (Attribute) info; 1580 long tid = open(); 1581 try { 1582 H5.H5Adelete(tid, attr.getName()); 1583 List<Attribute> attrList = getMetadata(); 1584 attrList.remove(attr); 1585 nAttributes = attributeList.size(); 1586 } 1587 catch (Exception ex) { 1588 log.debug("removeMetadata(): ", ex); 1589 } 1590 finally { 1591 close(tid); 1592 } 1593 log.trace("removeMetadata(): finish"); 1594 } 1595 1596 @Override 1597 public void setName(String newName) throws Exception { 1598 H5File.renameObject(this, newName); 1599 super.setName(newName); 1600 } 1601 1602 @Override 1603 public boolean isText() { 1604 return (datatypeClass == Datatype.CLASS_STRING); 1605 } 1606 1607 public boolean isRefObj() { 1608 return is_ref_obj; 1609 } 1610 1611 public boolean isRegRef() { 1612 return is_reg_ref; 1613 } 1614 1615 public int getNativeStrPad() { 1616 return nativeStrPad; 1617 } 1618 1619 /** 1620 * Extracts compound information into flat structure. 1621 * <p> 1622 * For example, compound datatype "nest" has {nest1{a, b, c}, d, e} then extractCompoundInfo() will 1623 * put the names of nested compound fields into a flat list as 1624 * 1625 * <pre> 1626 * nest.nest1.a 1627 * nest.nest1.b 1628 * nest.nest1.c 1629 * nest.d 1630 * nest.e 1631 * </pre> 1632 * 1633 * @param name 1634 * the name of the compound datatype 1635 * @param names 1636 * the list to store the member names of the compound datatype 1637 * @param flatListTypes 1638 * the list to store the nested member names of the compound datatype 1639 */ 1640 public void extractCompoundInfo(String name, List<String> names, List<Datatype> flatListTypes) { 1641 log.trace("extractCompoundInfo(): start: name={}", name); 1642 1643 if (isArray() || isVLEN()) { 1644 log.trace("extractCompoundInfo(): top-level types is ARRAY or VLEN; extracting compound info from base type"); 1645 ((H5Datatype) getDatatypeBase()).extractCompoundInfo(name, names, flatListTypes); 1646 } 1647 else { 1648 if (compoundMemberNames == null) { 1649 log.debug("extractCompoundInfo(): compoundMemberNames is null"); 1650 log.trace("extractCompoundInfo(): finish"); 1651 return; 1652 } 1653 1654 Datatype mtype = null; 1655 String mname = null; 1656 1657 log.trace("extractCompoundInfo(): nMembers={}", compoundMemberNames.size()); 1658 1659 if (compoundMemberNames.size() <= 0) { 1660 log.debug("extractCompoundInfo(): datatype has no members"); 1661 log.trace("extractCompoundInfo(): finish"); 1662 return; 1663 } 1664 1665 for (int i = 0; i < compoundMemberNames.size(); i++) { 1666 log.trace("extractCompoundInfo(): nMembers[{}]", i); 1667 1668 mtype = compoundMemberTypes.get(i); 1669 log.trace("extractCompoundInfo():[{}] mtype={} with size={}", i, mtype.getDescription(), mtype.getDatatypeSize()); 1670 1671 if (names != null) { 1672 mname = name + compoundMemberNames.get(i); 1673 log.trace("extractCompoundInfo():[{}] mname={}, name={}", i, mname, name); 1674 } 1675 1676 if (mtype.isCompound()) { 1677 ((H5Datatype) mtype).extractCompoundInfo(mname + CompoundDS.separator, names, flatListTypes); 1678 log.debug("extractCompoundInfo(): continue after recursive H5T_COMPOUND[{}]:", i); 1679 continue; 1680 } 1681 1682 if (names != null) { 1683 names.add(mname); 1684 } 1685 flatListTypes.add(mtype); 1686 1687 } // for (int i=0; i<nMembers; i++) 1688 } 1689 1690 log.trace("extractCompoundInfo(): finish"); 1691 } // extractCompoundInfo 1692 1693 /** 1694 * Creates a datatype of a compound with one field. 1695 * <p> 1696 * This function is needed to read/write data field by field. 1697 * 1698 * @param member_name 1699 * The name of the datatype 1700 * 1701 * @return the identifier of the compound datatype. 1702 * 1703 * @throws HDF5Exception 1704 * If there is an error at the HDF5 library level. 1705 */ 1706 public long createCompoundFieldType(String member_name) throws HDF5Exception { 1707 log.trace("createCompoundFieldType(): start member_name={}", member_name); 1708 long nested_tid = -1; 1709 long tmp_tid1 = -1; 1710 try { 1711 log.trace("createCompoundFieldType(): {} Member is type {} of size={} with baseType={}", member_name, getDescription(), getDatatypeSize(), getDatatypeBase()); 1712 tmp_tid1 = createNative(); 1713 1714 /* 1715 * If this member is nested inside a compound, keep inserting 1716 * it into a newly-created compound datatype until we reach 1717 * the top-level compound type. 1718 */ 1719 int sep = member_name.lastIndexOf(CompoundDS.separator); 1720 while (sep > 0) { 1721 String theName = member_name.substring(sep + 1); 1722 1723 log.trace("createCompoundFieldType(): member with name {} is nested inside compound", theName); 1724 1725 nested_tid = H5.H5Tcreate(HDF5Constants.H5T_COMPOUND, datatypeSize); 1726 H5.H5Tinsert(nested_tid, theName, 0, tmp_tid1); 1727 close(tmp_tid1); 1728 tmp_tid1 = nested_tid; 1729 member_name = member_name.substring(0, sep); 1730 sep = member_name.lastIndexOf(CompoundDS.separator); 1731 } 1732 1733 nested_tid = H5.H5Tcreate(HDF5Constants.H5T_COMPOUND, datatypeSize); 1734 1735 H5.H5Tinsert(nested_tid, member_name, 0, tmp_tid1); 1736 } 1737 finally { 1738 close(tmp_tid1); 1739 } 1740 1741 log.trace("createCompoundFieldType(): finish"); 1742 return nested_tid; 1743 } 1744}