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; 018 019import java.util.ArrayList; 020import java.util.Arrays; 021import java.util.Collection; 022import java.util.HashMap; 023import java.util.Iterator; 024import java.util.List; 025import java.util.Map; 026import java.util.Vector; 027import java.util.regex.Pattern; 028 029import hdf.hdf5lib.H5; 030import hdf.hdf5lib.HDF5Constants; 031 032import hdf.object.Datatype; 033import hdf.object.FileFormat; 034 035/** 036 * This class defines HDF5 reference characteristics and APIs for a data type of H5T_STD_REF. 037 * 038 * This class provides convenient functions to access H5T_STD_REF type information. 039 */ 040public class H5ReferenceType extends H5Datatype 041{ 042 private static final long serialVersionUID = -3360885430038261178L; 043 044 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(H5ReferenceType.class); 045 046 /** 047 * The memory buffer that holds the raw data array of the reference. 048 */ 049 protected transient ArrayList<H5ReferenceData> refdata; 050 051 /** Flag to indicate if data values are loaded into memory. */ 052 protected boolean isDataLoaded = false; 053 054 /** Flag to indicate if this dataset has been initialized */ 055 protected boolean inited = false; 056 057 /** The current array size of the reference. */ 058 protected long refsize; 059 060 /** 061 * The data buffer that contains the raw data directly reading from file 062 * (before any data conversion). 063 */ 064 protected transient Object originalRefBuf = null; 065 066 /** 067 * Constructs an named HDF5 data type reference for a given file, dataset name and group path. 068 * 069 * The datatype object represents an existing named datatype in file. For example, 070 * 071 * <pre> 072 * new H5ReferenceType(file, "dtype1", "/g0") 073 * </pre> 074 * 075 * constructs a datatype object that corresponds to the dataset,"dset1", at group "/g0". 076 * 077 * @param theFile 078 * the file that contains the datatype. 079 * @param theName 080 * the name of the dataset such as "dset1". 081 * @param thePath 082 * the group path to the dataset such as "/g0/". 083 */ 084 public H5ReferenceType(FileFormat theFile, String theName, String thePath) { 085 this(theFile, theName, thePath, null); 086 } 087 088 /** 089 * @deprecated Not for public use in the future. <br> 090 * Using {@link #H5ReferenceType(FileFormat, String, String)} 091 * 092 * @param theFile 093 * the file that contains the datatype. 094 * @param theName 095 * the name of the dataset such as "dset1". 096 * @param thePath 097 * the group path to the dataset such as "/g0/". 098 * @param oid 099 * the oid of the dataset. 100 */ 101 @Deprecated 102 public H5ReferenceType(FileFormat theFile, String theName, String thePath, long[] oid) { 103 super(theFile, theName, thePath, oid); 104 105 log.trace("constructor theName {}", theName); 106 refdata = null; 107 } 108 109 /** 110 * Constructs a H5ReferenceType with specified class, size, byte order and sign. 111 * 112 * @param tclass 113 * the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc. 114 * @param tsize 115 * the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4. 116 * Valid values are NATIVE or a positive value. For string datatypes, -1 is also 117 * a valid value (to create a variable-length string). 118 * @param torder 119 * the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX, 120 * ORDER_NONE and NATIVE. 121 * @param tsign 122 * the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE. 123 * 124 * @throws Exception 125 * if there is an error 126 */ 127 public H5ReferenceType(int tclass, int tsize, int torder, int tsign) throws Exception { 128 this(tclass, tsize, torder, tsign, null); 129 } 130 131 /** 132 * Constructs a H5ReferenceType with specified class, size, byte order and sign. 133 * 134 * @param tclass 135 * the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc. 136 * @param tsize 137 * the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4. 138 * Valid values are NATIVE or a positive value. For string datatypes, -1 is also 139 * a valid value (to create a variable-length string). 140 * @param torder 141 * the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX, 142 * ORDER_NONE and NATIVE. 143 * @param tsign 144 * the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE. 145 * @param tbase 146 * the base datatype of the new datatype 147 * 148 * @throws Exception 149 * if there is an error 150 */ 151 public H5ReferenceType(int tclass, int tsize, int torder, int tsign, Datatype tbase) throws Exception { 152 this(tclass, tsize, torder, tsign, tbase, null); 153 } 154 155 /** 156 * Constructs a H5ReferenceType with specified class, size, byte order and sign. 157 * 158 * @param tclass 159 * the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc. 160 * @param tsize 161 * the size of the datatype in bytes, e.g. for a 32-bit integer, the 162 * size is 4. Valid values are NATIVE or a positive value. For string 163 * datatypes, -1 is also a valid value (to create a variable-length 164 * string). 165 * @param torder 166 * the byte order of the datatype. Valid values are ORDER_LE, 167 * ORDER_BE, ORDER_VAX, ORDER_NONE and NATIVE. 168 * @param tsign 169 * the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and 170 * NATIVE. 171 * @param tbase 172 * the base datatype of the new datatype 173 * @param pbase 174 * the parent datatype of the new datatype 175 * 176 * @throws Exception 177 * if there is an error 178 */ 179 public H5ReferenceType(int tclass, int tsize, int torder, int tsign, Datatype tbase, Datatype pbase) throws Exception { 180 super(tclass, tsize, torder, tsign, tbase, pbase); 181 182 log.trace("constructor tsize {}", tsize); 183 refdata = null; 184 } 185 186 /** 187 * Constructs a H5ReferenceType with a given native datatype identifier. 188 * 189 * For example, if the datatype identifier is a 32-bit unsigned integer created from HDF5, 190 * 191 * <pre> 192 * int tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_UNINT32); 193 * Datatype dtype = new Datatype(tid); 194 * </pre> 195 * 196 * will construct a datatype equivalent to new Datatype(Datatype.CLASS_INTEGER, 4, Datatype.NATIVE, Datatype.SIGN_NONE); 197 * 198 * @see #fromNative(long nativeID) 199 * 200 * @param theFile 201 * the file that contains the datatype. 202 * @param theSize 203 * the size of the datatype in bytes, e.g. for a 32-bit integer, the 204 * size is 4. Valid values are NATIVE or a positive value. For string 205 * datatypes, -1 is also a valid value (to create a variable-length 206 * string). 207 * @param nativeID 208 * the native datatype identifier. 209 * 210 * @throws Exception 211 * if there is an error 212 */ 213 public H5ReferenceType(FileFormat theFile, long theSize, long nativeID) throws Exception { 214 this(theFile, theSize, nativeID, null); 215 } 216 217 /** 218 * Constructs a H5ReferenceType with a given native datatype identifier. 219 * 220 * For example, if the datatype identifier is a 32-bit unsigned integer created from HDF5, 221 * 222 * <pre> 223 * int tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_UNINT32); 224 * Datatype dtype = new Datatype(tid); 225 * </pre> 226 * 227 * will construct a datatype equivalent to new Datatype(Datatype.CLASS_INTEGER, 4, Datatype.NATIVE, Datatype.SIGN_NONE); 228 * 229 * @see #fromNative(long nativeID) 230 * 231 * @param theFile 232 * the file that contains the datatype. 233 * @param theSize 234 * the size of the datatype in bytes, e.g. for a 32-bit integer, the 235 * size is 4. Valid values are NATIVE or a positive value. For string 236 * datatypes, -1 is also a valid value (to create a variable-length 237 * string). 238 * @param nativeID 239 * the native datatype identifier. 240 * @param pbase 241 * the parent datatype of the new datatype 242 * 243 * @throws Exception 244 * if there is an error 245 */ 246 public H5ReferenceType(FileFormat theFile, long theSize, long nativeID, Datatype pbase) throws Exception { 247 super(theFile, nativeID, pbase); 248 249 log.trace("constructor theSize {}", theSize); 250 refsize = theSize; 251 refdata = new ArrayList<H5ReferenceData>((int)theSize); 252 } 253 254 /** 255 * Clears memory held by the reference, such as the data buffer. 256 */ 257 @SuppressWarnings("rawtypes") 258 public void clear() { 259 if (refdata != null) { 260 if (refdata instanceof List) 261 ((List) refdata).clear(); 262 originalRefBuf = null; 263 } 264 isDataLoaded = false; 265 } 266 267 /** 268 * Writes the memory buffer of this reference to file. 269 * 270 * @throws Exception if buffer can not be written 271 */ 272 public final void write() throws Exception { 273 log.trace("H5ReferenceType: write enter"); 274 if (refdata != null) { 275 log.trace("H5ReferenceType: write data"); 276 //write(refdata); 277 } 278 } 279 280 /** 281 * The status of initialization for this object 282 * 283 * @return true if the data has been initialized 284 */ 285 public final boolean isInited() { 286 return inited; 287 } 288 289 /** 290 * setData() loads the reference raw data into the buffer. This 291 * buffer will be accessed to get the reference strings and data. 292 * Once the references are destroyed, the refdata can only be used 293 * to retrieve existing data. 294 * 295 * @param theData 296 * the data to write. 297 */ 298 public void setData(Object theData) { 299 log.trace("setData(): refsize={} theData={}", refsize, theData); 300 originalRefBuf = theData; 301 for (int i = 0; i < (int)refsize; i++) { 302 int refIndex = HDF5Constants.H5R_REF_BUF_SIZE * i; 303 byte[] refarr = new byte[(int) HDF5Constants.H5R_REF_BUF_SIZE]; 304 System.arraycopy((byte[])theData, refIndex, refarr, 0, (int)HDF5Constants.H5R_REF_BUF_SIZE); 305 log.trace("setData(): refarr={}", refarr); 306 H5ReferenceData rf = new H5ReferenceData(refarr); 307 refdata.add(rf); 308 } 309 isDataLoaded = true; 310 init(); 311 } 312 313 /** 314 * Returns the data buffer of the reference in memory. 315 * 316 * If data is already loaded into memory, returns the data; otherwise, calls 317 * read() to read data from file into a memory buffer and returns the memory 318 * buffer. 319 * 320 * By default, the whole reference is read into memory. 321 * 322 * @return the memory buffer of the reference. 323 * 324 * @throws Exception if object can not be read 325 * @throws OutOfMemoryError if memory is exhausted 326 */ 327 public Object getData() throws Exception, OutOfMemoryError { 328 log.trace("getData(): isDataLoaded={}", isDataLoaded); 329 if (!isDataLoaded) { 330 //refdata = read(); // load the data 331 log.trace("getData(): size={} refdata={}", refdata.size(), refdata); 332 if (refdata != null) { 333 refsize = refdata.size(); 334 originalRefBuf = refdata; 335 isDataLoaded = true; 336 } 337 } 338 339 return refdata; 340 } 341 342 /** 343 * Clears the current data buffer in memory and forces the next read() to load 344 * the data from file. 345 * 346 * The function read() loads data from file into memory only if the data is 347 * not read. If data is already in memory, read() just returns the memory 348 * buffer. Sometimes we want to force read() to re-read data from file. For 349 * example, when the selection is changed, we need to re-read the data. 350 * 351 * @see #getData() 352 */ 353 public void clearData() { 354 isDataLoaded = false; 355 } 356 357 /** 358 * Returns the array size of the reference. 359 * 360 * @return the array size of the reference. 361 */ 362 public final long getRefSize() { 363 if (!inited) 364 init(); 365 366 return refsize; 367 } 368 369 /** 370 * Sets the array size of the reference. 371 * 372 * @param current_size 373 * the array size of the current reference. 374 */ 375 public final void setRefSize(long current_size) { 376 refsize = current_size; 377 } 378 379 /** 380 * Retrieves reference information from file into memory. 381 */ 382 public void init() { 383 if (inited) { 384 log.trace("init(): H5ReferenceType already inited"); 385 return; 386 } 387 388 log.trace("init(): refsize={}", refsize); 389 for (int i = 0; i < (int)refsize; i++) { 390 H5ReferenceData rf = refdata.get(i); 391 log.trace("init(): rf.ref_array={}", rf.ref_array); 392 byte[] refarr = new byte[(int) HDF5Constants.H5R_REF_BUF_SIZE]; 393 System.arraycopy(rf.ref_array, 0, refarr, 0, (int)HDF5Constants.H5R_REF_BUF_SIZE); 394 395 if (zeroArrayCheck(refarr)) { 396 log.trace("init(): refarr is zero"); 397 rf.file_fullpath = "NULL"; 398 rf.file_name = "NULL"; 399 rf.obj_name = "NULL"; 400 rf.attr_name = "NULL"; 401 rf.region_type = "NULL"; 402 rf.region_desc = "NULL"; 403 } 404 else { 405 log.trace("init(): refarr={}", refarr); 406 try { 407 rf.file_fullpath = "NULL"; 408 rf.file_name = "NULL"; 409 rf.obj_name = "NULL"; 410 rf.attr_name = "NULL"; 411 try { 412 rf.file_fullpath = H5.H5Rget_file_name(refarr); 413 log.trace("Reference Full File Path {}", rf.file_fullpath); 414 String[] split = rf.file_fullpath.split( Pattern.quote("/") ); 415 rf.file_name = split[split.length-1]; 416 log.trace("Reference File Name {}", rf.file_name); 417 rf.obj_name = H5.H5Rget_obj_name(refarr, HDF5Constants.H5P_DEFAULT); 418 log.trace("Reference Object Name {}", rf.obj_name); 419 420 if (H5.H5Rget_type(refarr) == HDF5Constants.H5R_ATTR) 421 rf.attr_name = H5.H5Rget_attr_name(refarr); 422 else 423 rf.attr_name = "NULL"; 424 log.trace("Reference Attribute Name {}", rf.attr_name); 425 } 426 catch (Exception ex) { 427 log.debug("Reference H5Rget_*_name", ex); 428 } 429 initReferenceRegion(i, refarr, false); 430 } 431 catch (Exception ex) { 432 log.debug("Reference Init", ex); 433 } 434 finally { 435 H5.H5Rdestroy(refarr); 436 log.trace("Reference H5Rdestroy"); 437 } 438 } 439 } 440 log.trace("init(): finished"); 441 inited = true; 442 } 443 444 private void initReferenceRegion(int refndx, byte[] refarr, boolean showData) { 445 H5ReferenceData rf = refdata.get(refndx); 446 rf.ref_type = HDF5Constants.H5R_BADTYPE; 447 rf.obj_type = HDF5Constants.H5O_TYPE_UNKNOWN; 448 rf.region_type = "NULL"; 449 rf.region_desc = "NULL"; 450 log.trace("initReferenceRegion start not null"); 451 try { 452 rf.ref_type = (int)H5.H5Rget_type(refarr); 453 log.debug("initReferenceRegion ref_type={}", rf.ref_type); 454 try { 455 rf.obj_type = H5.H5Rget_obj_type3(refarr, HDF5Constants.H5P_DEFAULT); 456 log.debug("initReferenceRegion obj_type={}", rf.obj_type); 457 } 458 catch (Exception ex2) { 459 log.debug("initReferenceRegion H5Rget_obj_type3", ex2); 460 } 461 } 462 catch (Exception ex1) { 463 log.debug("initReferenceRegion H5Rget_type", ex1); 464 } 465 466 if (rf.ref_type > HDF5Constants.H5R_BADTYPE) { 467 if (rf.ref_type == HDF5Constants.H5R_OBJECT1) { 468 log.trace("initReferenceRegion H5R_OBJECT1"); 469 if (rf.obj_type == HDF5Constants.H5O_TYPE_DATASET) { 470 initRegionDataset(refndx, refarr); 471 } //obj_type == HDF5Constants.H5O_TYPE_DATASET 472 else { 473 /* Object references -- show the type and OID of the referenced object. */ 474 rf.region_type = "H5O_TYPE_OBJ_REF"; 475// H5O_info2_t oi; 476// char * obj_tok_str = NULL; 477// H5Oget_info3(new_obj_id, &oi, H5O_INFO_BASIC); 478// HDsprintf(this_str, "%u-", (unsigned)oi.type); 479// H5Otoken_to_str(new_obj_id, &oi.token, &obj_tok_str); 480// /* Print OID */ 481// { 482// char *token_str; 483// 484// H5Otoken_to_str(tid, &oi.token, &token_str); 485// 486// if (NULL == (this_str = (char *)HDmalloc(64 + strlen(token_str) + 1))) 487// H5_OUT_OF_MEMORY_ERROR( 488// ENVONLY, "h5str_sprintf: failed to allocate string buffer"); 489// if (HDsprintf(this_str, "%lu:%s", oi.fileno, token_str) < 0) 490// H5_JNI_FATAL_ERROR(ENVONLY, "h5str_sprintf: HDsprintf failure"); 491// H5free_memory(token_str); 492// } 493 } 494 } 495 else if (rf.ref_type == HDF5Constants.H5R_DATASET_REGION1) { 496 log.trace("initReferenceRegion H5R_DATASET_REGION1"); 497 initRegionDataset(refndx, refarr); 498 } 499 else if (rf.ref_type == HDF5Constants.H5R_OBJECT2) { 500 log.trace("initReferenceRegion H5R_OBJECT2"); 501 rf.region_type = "H5O_TYPE_OBJ_REF"; 502 } 503 else if (rf.ref_type == HDF5Constants.H5R_DATASET_REGION2) { 504 log.trace("initReferenceRegion H5R_DATASET_REGION2"); 505 initRegionDataset(refndx, refarr); 506 } 507 else if (rf.ref_type == HDF5Constants.H5R_ATTR) { 508 log.trace("initReferenceRegion H5R_ATTR"); 509 rf.region_type = "H5R_ATTR"; 510 initRegionAttribute(refndx, refarr); 511 } 512 else { 513 log.trace("initReferenceRegion OTHER"); 514 rf.region_type = "UNKNOWN"; 515 } 516 } 517 log.trace("initReferenceRegion finish"); 518 } 519 520 private void initRegionAttribute(int refndx, byte[] refarr) { 521 H5ReferenceData rf = refdata.get(refndx); 522 long new_obj_id = HDF5Constants.H5I_INVALID_HID; 523 try { 524 log.trace("initRegionAttribute refarr2={}:", refarr); 525 new_obj_id = H5.H5Ropen_attr(refarr, HDF5Constants.H5P_DEFAULT, HDF5Constants.H5P_DEFAULT); 526 long new_obj_sid = HDF5Constants.H5I_INVALID_HID; 527 try { 528 new_obj_sid = H5.H5Aget_space(new_obj_id); 529 long reg_ndims = H5.H5Sget_simple_extent_ndims(new_obj_sid); 530 //rf.region_desc = dump_region_attrs(regStr, new_obj_id); 531 } 532 catch (Exception ex3) { 533 log.debug("initRegionAttribute Space Open", ex3); 534 } 535 finally { 536 H5.H5Sclose(new_obj_sid); 537 } 538 log.trace("initRegionAttribute finish"); 539 } 540 catch (Exception ex2) { 541 log.debug("initRegionAttribute ", ex2); 542 } 543 finally { 544 H5.H5Aclose(new_obj_id); 545 } 546 } 547 548 private void initRegionDataset(int refndx, byte[] refarr) { 549 H5ReferenceData rf = refdata.get(refndx); 550 long new_obj_id = HDF5Constants.H5I_INVALID_HID; 551 try { 552 log.trace("initRegionDataset refarr2={}:", refarr); 553 new_obj_id = H5.H5Ropen_object(refarr, HDF5Constants.H5P_DEFAULT, HDF5Constants.H5P_DEFAULT); 554 long new_obj_sid = HDF5Constants.H5I_INVALID_HID; 555 try { 556 log.trace("initRegionDataset refarr3={}:", refarr); 557 new_obj_sid = H5.H5Ropen_region(refarr, HDF5Constants.H5P_DEFAULT, HDF5Constants.H5P_DEFAULT); 558 try { 559 int region_type = H5.H5Sget_select_type(new_obj_sid); 560 log.debug("Reference Region Type {}", region_type); 561 long reg_ndims = H5.H5Sget_simple_extent_ndims(new_obj_sid); 562 StringBuilder sb = new StringBuilder(); 563 if (HDF5Constants.H5S_SEL_POINTS == region_type) { 564 rf.region_type = "REGION_TYPE POINT"; 565 long reg_npoints = H5.H5Sget_select_elem_npoints(new_obj_sid); 566 long getcoord[] = new long[(int)(reg_ndims * reg_npoints)]; 567 try { 568 H5.H5Sget_select_elem_pointlist(new_obj_sid, 0, reg_npoints, getcoord); 569 } 570 catch (Exception ex5) { 571 log.debug("initRegionDataset H5.H5Sget_select_elem_pointlist: ", ex5); 572 } 573 sb.append("{ "); 574 for (int i = 0; i < (int)reg_npoints; i++) { 575 if (i > 0) 576 sb.append(" "); 577 sb.append("("); 578 for (int j = 0; j < (int)reg_ndims; j++) { 579 if (j > 0) 580 sb.append(","); 581 sb.append(getcoord[i * (int)reg_ndims + j]); 582 } 583 sb.append(")"); 584 } 585 sb.append(" }"); 586 rf.region_desc = sb.toString(); 587 } 588 else if (HDF5Constants.H5S_SEL_HYPERSLABS == region_type) { 589 rf.region_type = "REGION_TYPE BLOCK"; 590 long reg_nblocks = H5.H5Sget_select_hyper_nblocks(new_obj_sid); 591 long getblocks[] = new long[(int)(reg_ndims * reg_nblocks) * 2]; 592 try { 593 H5.H5Sget_select_hyper_blocklist(new_obj_sid, 0, reg_nblocks, getblocks); 594 } 595 catch (Exception ex5) { 596 log.debug("initRegionDataset H5.H5Sget_select_hyper_blocklist: ", ex5); 597 } 598 sb.append("{ "); 599 for (int i = 0; i < (int)reg_nblocks; i++) { 600 if (i > 0) 601 sb.append(" "); 602 sb.append("("); 603 for (int j = 0; j < (int)reg_ndims; j++) { 604 if (j > 0) 605 sb.append(","); 606 sb.append(getblocks[i * 2 * (int)reg_ndims + j]); 607 } 608 sb.append(")-("); 609 for (int j = 0; j < (int)reg_ndims; j++) { 610 if (j > 0) 611 sb.append(","); 612 sb.append(getblocks[i * 2 * (int)reg_ndims + (int)reg_ndims + j]); 613 } 614 sb.append(")"); 615 } 616 sb.append(" }"); 617 rf.region_desc = sb.toString(); 618 } 619 else 620 rf.region_type = "REGION_TYPE UNKNOWN"; 621 } 622 catch (Exception ex4) { 623 log.debug("initRegionDataset Region Type", ex4); 624 } 625 } 626 catch (Exception ex3) { 627 log.debug("initRegionDataset Space Open", ex3); 628 } 629 finally { 630 H5.H5Sclose(new_obj_sid); 631 } 632 log.trace("initRegionDataset finish"); 633 } 634 catch (Exception ex2) { 635 log.debug("initRegionDataset ", ex2); 636 } 637 finally { 638 H5.H5Dclose(new_obj_id); 639 } 640 } 641 642 /** 643 * Checks if a reference datatype is all zero. 644 * 645 * @param refarr 646 * the reference datatype data to be checked. 647 * 648 * @return true is the reference datatype data is all zero; otherwise returns false. 649 */ 650 public static final boolean zeroArrayCheck(final byte[] refarr) { 651 for (byte b : refarr) { 652 if (b != 0) 653 return false; 654 } 655 return true; 656 } 657 658 /** 659 * Get the reference datatype reference name. 660 * 661 * @param refarr 662 * the reference datatype data to be queried. 663 * 664 * @return the reference datatype name string, null otherwise. 665 */ 666 public final String getObjectReferenceName(byte[] refarr) { 667 if (!inited) 668 init(); 669 670 // find the index that matches refarr and ref_array 671 H5ReferenceData rf = null; 672 for (int i = 0; i < (int)refsize; i++) { 673 byte[] theref = refdata.get(i).ref_array; 674 if (Arrays.equals(theref, refarr)) { 675 rf = refdata.get(i); 676 break; 677 } 678 } 679 if (rf == null) 680 return null; 681 682 StringBuilder sb = new StringBuilder(); 683 if (!rf.obj_name.equals("NULL")) { 684 sb.append(rf.obj_name); 685 } 686 if (!rf.attr_name.equals("NULL")) { 687 if (sb.length() > 0) 688 sb.append("/"); 689 sb.append(rf.attr_name); 690 } 691 if (!rf.region_desc.equals("NULL")) { 692 if (sb.length() > 0) 693 sb.append(" "); 694 sb.append(rf.region_desc); 695 } 696 log.debug("Reference Object Name {}", sb); 697 return sb.toString(); 698 } 699 700 /** 701 * Get the reference datatype reference name. 702 * 703 * @param refarr 704 * the reference datatype data to be queried. 705 * 706 * @return the reference datatype name string, null otherwise. 707 */ 708 public final String getFullReferenceName(byte[] refarr) { 709 if (!inited) 710 init(); 711 712 // find the index that matches refarr and ref_array 713 H5ReferenceData rf = null; 714 for (int i = 0; i < (int)refsize; i++) { 715 byte[] theref = refdata.get(i).ref_array; 716 if (Arrays.equals(theref, refarr)) { 717 rf = refdata.get(i); 718 break; 719 } 720 } 721 if (rf == null) 722 return null; 723 724 StringBuilder sb = new StringBuilder(); 725 if (!rf.file_name.equals("NULL")) 726 sb.append(rf.file_name); 727 if (!rf.obj_name.equals("NULL")) { 728 if (sb.length() > 0) 729 sb.append("/"); 730 sb.append(rf.obj_name); 731 } 732 if (!rf.attr_name.equals("NULL")) { 733 if (sb.length() > 0) 734 sb.append("/"); 735 sb.append(rf.attr_name); 736 } 737 if (!rf.region_desc.equals("NULL")) { 738 if (sb.length() > 0) 739 sb.append(" "); 740 sb.append(rf.region_desc); 741 } 742 log.debug("Full Reference Name {}", sb); 743 return sb.toString(); 744 } 745 746 747 /** 748 * Get the reference datatype dataset region reference as string. 749 * 750 * @param refarr 751 * the reference datatype data to be queried. 752 * 753 * @return the reference datatype name string, null otherwise. 754 */ 755 public final String getRegionDataset(byte[] refarr) { 756 if (!inited) 757 init(); 758 759 // find the index that matches refarr and ref_array 760 H5ReferenceData rf = null; 761 for (int i = 0; i < (int)refsize; i++) { 762 byte[] theref = refdata.get(i).ref_array; 763 if (Arrays.equals(theref, refarr)) { 764 rf = refdata.get(i); 765 break; 766 } 767 } 768 if (rf == null) 769 return null; 770 771 StringBuilder sb = new StringBuilder(); 772 sb.append(rf.region_type); 773 if (!rf.region_desc.equals("NULL")) { 774 if (sb.length() > 0) 775 sb.append(" "); 776 sb.append(rf.region_desc); 777 } 778 log.debug("getRegionDataset Value {}", sb); 779 return sb.toString(); 780 } 781 782 /** 783 * Get the reference datatype data. 784 * 785 * @param refarr 786 * the reference datatype data to be queried. 787 * 788 * @return the reference datatype data. 789 */ 790 public final H5ReferenceData getReferenceData(byte[] refarr) { 791 if (!inited) 792 init(); 793 794 // find the index that matches refarr and ref_array 795 H5ReferenceData rf = null; 796 for (int i = 0; i < (int)refsize; i++) { 797 byte[] theref = refdata.get(i).ref_array; 798 if (Arrays.equals(theref, refarr)) { 799 rf = refdata.get(i); 800 break; 801 } 802 } 803 return rf; 804 } 805 806 /** 807 * Get the reference datatype region reference as string. 808 * 809 * @param refarr 810 * the reference datatype data to be queried. 811 * @param showData 812 * show the reference region dims 813 * 814 * @return the reference datatype name string, null otherwise. 815 */ 816 public final String getReferenceRegion(byte[] refarr, boolean showData) { 817 if (!inited) 818 init(); 819 820 // find the index that matches refarr and ref_array 821 H5ReferenceData rf = null; 822 for (int i = 0; i < (int)refsize; i++) { 823 byte[] theref = refdata.get(i).ref_array; 824 if (Arrays.equals(theref, refarr)) { 825 rf = refdata.get(i); 826 break; 827 } 828 } 829 if (rf == null) 830 return null; 831 832 StringBuilder objsb = new StringBuilder(); 833 if (!rf.file_name.equals("NULL")) 834 objsb.append(rf.file_name); 835 if (!rf.obj_name.equals("NULL")) { 836 objsb.append(rf.obj_name); 837 } 838 if (!rf.attr_name.equals("NULL")) { 839 if (objsb.length() > 0) 840 objsb.append("/"); 841 objsb.append(rf.attr_name); 842 } 843 log.debug("getReferenceRegion Region Name {}", objsb); 844 845 StringBuilder regsb = new StringBuilder(); 846 if (!rf.region_type.equals("NULL")) 847 regsb.append(rf.region_type); 848 if (!rf.region_desc.equals("NULL")) { 849 if (regsb.length() > 0) 850 regsb.append(" "); 851 regsb.append(rf.region_desc); 852 } 853 log.debug("getReferenceRegion Region Type {}", regsb); 854 StringBuilder sb = new StringBuilder(objsb); 855 if (regsb.length() > 0) { 856 sb.append(" "); 857 sb.append(regsb); 858 } 859 if (sb.length() > 0) 860 return sb.toString(); 861 else 862 return "NULL"; 863 } 864 865 /** 866 * Returns a string representation of the data value. For 867 * example, "0, 255". 868 * 869 * For a compound datatype, it will be a 1D array of strings with field 870 * members separated by the delimiter. For example, 871 * "{0, 10.5}, {255, 20.0}, {512, 30.0}" is a compound attribute of {int, 872 * float} of three data points. 873 * 874 * @param delimiter 875 * The delimiter used to separate individual data points. It 876 * can be a comma, semicolon, tab or space. For example, 877 * toString(",") will separate data by commas. 878 * 879 * @return the string representation of the data values. 880 */ 881 public String toString(String delimiter) { 882 return toString(delimiter, -1); 883 } 884 885 /** 886 * Returns a string representation of the data value. 887 * 888 * @param delimiter 889 * The delimiter used to separate individual data points. It 890 * can be a comma, semicolon, tab or space. For example, 891 * toString(",") will separate data by commas. 892 * @param maxItems 893 * The maximum number of Array values to return 894 * 895 * @return the string representation of the data values. 896 */ 897 public String toString(String delimiter, int maxItems) { 898 Object theData = originalRefBuf; 899 if (theData == null) { 900 log.debug("toString: value is null"); 901 return null; 902 } 903 904 if (theData instanceof List<?>) { 905 log.trace("toString: value is list"); 906 return null; 907 } 908 909 Class<? extends Object> valClass = theData.getClass(); 910 911 if (!valClass.isArray()) { 912 log.trace("toString: finish - not array"); 913 String strValue = theData.toString(); 914 if (maxItems > 0 && strValue.length() > maxItems) 915 // truncate the extra characters 916 strValue = strValue.substring(0, maxItems); 917 return strValue; 918 } 919 920 // value is an array 921 StringBuilder sb = new StringBuilder(); 922 log.trace("toString: refsize={} isStdRef={} Array.getLength={}", refsize, isStdRef(), Array.getLength(theData)); 923 if (isStdRef()) { 924 String cname = valClass.getName(); 925 char dname = cname.charAt(cname.lastIndexOf('[') + 1); 926 log.trace("toString: isStdRef with cname={} dname={}", cname, dname); 927 for (int i = 0; i < (int)refsize; i++) { 928 int refIndex = HDF5Constants.H5R_REF_BUF_SIZE * i; 929 byte[] refarr = new byte[(int) HDF5Constants.H5R_REF_BUF_SIZE]; 930 System.arraycopy((byte[])theData, refIndex, refarr, 0, (int)HDF5Constants.H5R_REF_BUF_SIZE); 931 log.trace("toString: refarr[{}]={}", i, refarr); 932 StringBuilder ref_str = new StringBuilder(getReferenceRegion(refarr, false)); 933 if ((maxItems > 0) && (ref_str.length() > maxItems)) { 934 ref_str.setLength(maxItems); 935 } 936 log.trace("toString: ref_str[{}]={}", i, ref_str); 937 if (i > 0) 938 sb.append(", "); 939 sb.append(ref_str); 940 } 941 return sb.toString(); 942 } 943 return toString(delimiter, maxItems); 944 } 945 946 /** 947 * The individual reference data for a given object. 948 */ 949 public static class H5ReferenceData 950 { 951 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(H5ReferenceData.class); 952 953 /** The reference array raw data */ 954 public byte[] ref_array = new byte[(int) HDF5Constants.H5R_REF_BUF_SIZE]; 955 956 /** The the full file path referenced */ 957 public String file_fullpath; 958 959 /** The file name referenced */ 960 public String file_name; 961 962 /** The object name referenced */ 963 public String obj_name; 964 965 /** The attribute name referenced */ 966 public String attr_name; 967 968 /** The type of region referenced */ 969 public String region_type; 970 971 /** The point/block description of region referenced */ 972 public String region_desc; 973 974 /** The default type of region referenced */ 975 public int ref_type = HDF5Constants.H5R_BADTYPE; 976 977 /** The default type of object referenced */ 978 public int obj_type = HDF5Constants.H5O_TYPE_UNKNOWN; 979 980 /** 981 * Copy the individual reference array for further processing 982 * 983 * @param theArray 984 * the reference datatype data to be copied. 985 */ 986 H5ReferenceData(byte[] theArray) 987 { 988 System.arraycopy(theArray, 0, ref_array, 0, (int)HDF5Constants.H5R_REF_BUF_SIZE); 989 } 990 } 991}