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.h4; 016 017import java.io.File; 018import java.lang.reflect.Array; 019import java.util.ArrayList; 020import java.util.Iterator; 021import java.util.LinkedList; 022import java.util.List; 023import java.util.Queue; 024import java.util.Vector; 025 026import hdf.hdflib.HDFConstants; 027import hdf.hdflib.HDFException; 028import hdf.hdflib.HDFLibrary; 029 030import hdf.object.Attribute; 031import hdf.object.Dataset; 032import hdf.object.Datatype; 033import hdf.object.FileFormat; 034import hdf.object.Group; 035import hdf.object.HObject; 036 037/** 038 * This class provides file level APIs. File access APIs include retrieving the 039 * file hierarchy, opening and closing file, and writing file content to disk. 040 * 041 * @version 2.4 9/4/2007 042 * @author Peter X. Cao 043 */ 044public class H4File extends FileFormat { 045 private static final long serialVersionUID = 8985533001471224030L; 046 047 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(H4File.class); 048 049 /** 050 * the file access flag. 051 */ 052 private int flag; 053 054 /** 055 * The root object of this file. 056 */ 057 private HObject rootObject; 058 059 /** 060 * The list of unique (tag, ref) pairs. It is used to avoid duplicate 061 * objects in memory. 062 */ 063 @SuppressWarnings("rawtypes") 064 private List objList; 065 066 /** 067 * The GR interface identifier. The identifier is returned by GRstart(fid), 068 * which initializes the GR interface for the file specified by the 069 * parameter. GRstart(fid) is an expensive call. It should be called only 070 * once. Calling GRstart(fid) in a loop should be avoided. 071 */ 072 private long grid; 073 074 private boolean isNetCDF = false; 075 076 /** 077 * The SDS interface identifier. The identifier is returned by 078 * SDstart(fname, flag), which initializes the SD interface for the file 079 * specified by the parameter. SDstart(fname, flag) is an expensive call. It 080 * should be called only once. Calling SDstart(fname, flag) in a loop should 081 * be avoided. 082 */ 083 private long sdid; 084 085 /** 086 * secret flag: show CDF0.0, etc., to help debug 087 */ 088 private boolean showAll = false; 089 090 /** 091 * Creates an H4File with read write access. 092 */ 093 public H4File() { 094 this("", WRITE); 095 } 096 097 /** 098 * Creates an H4File with read write access. 099 * 100 * @param pathname 101 * The file path string. 102 */ 103 public H4File(String pathname) { 104 this(pathname, WRITE); 105 } 106 107 /** 108 * Creates an H4File instance with specified file name and access. 109 * <p> 110 * The access parameter values and corresponding behaviors: 111 * <ul> 112 * <li>READ: Read-only access; open() will fail if file doesn't exist. 113 * <li>WRITE: Read/Write access; if file doesn't exist, open() will create 114 * it; open() will fail if read/write access not allowed. 115 * <li>CREATE: Read/Write access; create a new file or truncate an existing 116 * one; open() will fail if file can't be created or if file exists but 117 * can't be opened read/write. 118 * </ul> 119 * <p> 120 * This constructor does not open the file for access, nor does it confirm 121 * that the file can later be opened read/write or created. 122 * <p> 123 * The flag returned by {@link #isReadOnly()} is set to true if the access 124 * parameter value is READ, even though the file isn't yet open. 125 * 126 * @param fileName 127 * A valid file name, with a relative or absolute path. 128 * @param access 129 * The file access flag, which determines behavior when file is 130 * opened. Acceptable values are <code> READ, WRITE, </code> and 131 * <code>CREATE</code>. 132 * 133 * @throws NullPointerException 134 * If the <code>fileName</code> argument is <code>null</code>. 135 */ 136 @SuppressWarnings("rawtypes") 137 public H4File(String fileName, int access) { 138 super(fileName); 139 140 isReadOnly = (access == READ); 141 objList = new Vector(); 142 143 this.fid = -1; 144 145 if ((access & FILE_CREATE_OPEN) == FILE_CREATE_OPEN) { 146 File f = new File(fileName); 147 if (f.exists()) { 148 access = WRITE; 149 } 150 else { 151 access = CREATE; 152 } 153 } 154 155 if (access == READ) { 156 flag = HDFConstants.DFACC_READ; 157 } 158 else if (access == WRITE) { 159 flag = HDFConstants.DFACC_WRITE; 160 } 161 else if (access == CREATE) { 162 flag = HDFConstants.DFACC_CREATE; 163 } 164 else { 165 flag = access; 166 } 167 168 if (log != null) log.trace("File: {} isReadOnly={} accessType={}", fileName, isReadOnly, flag); 169 170 String shwAll = System.getProperty("h4showall"); 171 if (shwAll != null) { 172 showAll = true; 173 if (log != null) log.debug("show all is on"); 174 } 175 else { 176 if (log != null) log.debug("show all is off"); 177 } 178 } 179 180 /** 181 * Checks if the given file format is an HDF4 file. 182 * 183 * @param fileformat 184 * the fileformat to be checked. 185 * 186 * @return true if the given file is an HDF4 file; otherwise returns false. 187 */ 188 @Override 189 public boolean isThisType(FileFormat fileformat) { 190 return (fileformat instanceof H4File); 191 } 192 193 /** 194 * Checks if the given file is an HDF4 file or netCDF. HDF4 library supports 195 * netCDF version 2.3.2. It only supports SDS APIs. 196 * 197 * @param filename 198 * the file to be checked. 199 * 200 * @return true if the given file is an HDF4 file; otherwise returns false. 201 */ 202 @Override 203 public boolean isThisType(String filename) { 204 boolean isH4 = false; 205 206 try { 207 isH4 = HDFLibrary.Hishdf(filename); 208 } 209 catch (HDFException ex) { 210 isH4 = false; 211 } 212 213 if (!isH4) { 214 isH4 = isNetCDF(filename); 215 } 216 217 log.trace("isThisType(): isH4={}", isH4); 218 return isH4; 219 } 220 221 /** 222 * Creates an HDF4 file with the specified name and returns a new H4File 223 * instance associated with the file. 224 * 225 * @throws HDFException 226 * If the file cannot be created or if createFlag has unexpected value. 227 * 228 * @see hdf.object.FileFormat#createFile(java.lang.String, int) 229 * @see #H4File(String, int) 230 */ 231 @Override 232 public FileFormat createFile(String filename, int createFlag) 233 throws Exception { 234 // Flag if we need to create or truncate the file. 235 Boolean doCreateFile = true; 236 237 // Won't create or truncate if CREATE_OPEN specified and file exists 238 if (createFlag == FILE_CREATE_OPEN) { 239 File f = new File(filename); 240 if (f.exists()) { 241 doCreateFile = false; 242 } 243 } 244 245 log.trace("createFile(): doCreateFile={}", doCreateFile); 246 247 if (doCreateFile) { 248 long fileid = HDFLibrary.Hopen(filename, HDFConstants.DFACC_CREATE); 249 try { 250 HDFLibrary.Hclose(fileid); 251 } 252 catch (HDFException ex) { 253 log.debug("Hclose failure: ", ex); 254 } 255 } 256 257 return new H4File(filename, WRITE); 258 } 259 260 /** 261 * Creates an H4File instance with specified file name and access. 262 * 263 * @see hdf.object.FileFormat#createInstance(java.lang.String, int) 264 * @see #H4File(String, int) 265 */ 266 @Override 267 public FileFormat createInstance(String filename, int access) 268 throws Exception { 269 return new H4File(filename, access); 270 } 271 272 // Implementing FileFormat 273 @Override 274 public long open() throws Exception { 275 276 if (fid >= 0) { 277 log.trace("open(): File {} already open", fid); 278 return fid; // file is opened already 279 } 280 281 // check for valid file access permission 282 if (flag < 0) { // invalid access id 283 throw new HDFException("Invalid access identifer -- " + flag); 284 } 285 else if (flag == HDFConstants.DFACC_READ) { 286 if (!exists()) { 287 log.debug("File {} does not exist", fullFileName); 288 throw new HDFException("File does not exist -- " + fullFileName); 289 } 290 else if (exists() && !canRead()) { 291 log.debug("Cannot read file {}", fullFileName); 292 throw new HDFException("Cannot read file -- " + fullFileName); 293 } 294 } 295 else if ((flag == HDFConstants.DFACC_WRITE) || (flag == HDFConstants.DFACC_CREATE)) { 296 if (exists() && !canWrite()) { 297 log.debug("Cannot write file {}, try opening as read-only", fullFileName); 298 throw new HDFException("Cannot write file, try opening as read-only -- " + fullFileName); 299 } 300 } 301 302 // Only check for NetCDF if the file exists, else isNetCDF() throws an exception 303 if (exists()) 304 isNetCDF = isNetCDF(fullFileName); 305 if (isNetCDF) 306 isReadOnly = true; // read only for netCDF 307 log.trace("open(): isNetCDF={}", isNetCDF); 308 309 // only support SDS APIs for netCDF 310 if (isNetCDF) { 311 fid = 0; 312 } 313 else { 314 log.trace("HDFLibrary - open({},{})", fullFileName, flag); 315 fid = HDFLibrary.Hopen(fullFileName, flag); 316 HDFLibrary.Vstart(fid); 317 grid = HDFLibrary.GRstart(fid); 318 log.trace("open(): fid:{} grid:{}", fid, grid); 319 } 320 321 try { 322 sdid = HDFLibrary.SDstart(fullFileName, flag & ~HDFConstants.DFACC_CREATE); 323 324 if (sdid < 0) 325 log.debug("open(): SDstart failed!"); 326 } 327 catch (HDFException ex) { 328 log.debug("open(): SDstart failure: ", ex); 329 } 330 331 log.trace("open(): sdid:{}", sdid); 332 333 // load the file hierarchy 334 loadIntoMemory(); 335 336 return fid; 337 } 338 339 // Implementing FileFormat 340 @Override 341 public void close() throws HDFException { 342 // clean unused objects 343 if (rootObject != null) { 344 HObject theObj = null; 345 Iterator<HObject> it = getMembersBreadthFirst(rootObject).iterator(); 346 while (it.hasNext()) { 347 theObj = it.next(); 348 349 if (theObj instanceof Dataset) { 350 ((Dataset) theObj).clearData(); 351 } 352 else if (theObj instanceof Group) { 353 ((Group) theObj).clear(); 354 } 355 } 356 } 357 358 try { 359 HDFLibrary.GRend(grid); 360 } 361 catch (HDFException ex) { 362 log.debug("close(): GRend failure: ", ex); 363 } 364 try { 365 HDFLibrary.SDend(sdid); 366 } 367 catch (HDFException ex) { 368 log.debug("close(): SDend failure: ", ex); 369 } 370 try { 371 HDFLibrary.Vend(fid); 372 } 373 catch (HDFException ex) { 374 log.debug("close(): Vend failure: ", ex); 375 } 376 377 HDFLibrary.Hclose(fid); 378 379 fid = -1; 380 objList = null; 381 } 382 383 // Implementing FileFormat 384 @Override 385 public HObject getRootObject() { 386 return rootObject; 387 } 388 389 @Override 390 public Group createGroup(String name, Group pgroup) throws Exception { 391 return H4Group.create(name, pgroup); 392 } 393 394 @Override 395 public Datatype createDatatype(int tclass, int tsize, int torder, int tsign) throws Exception { 396 return new H4Datatype(tclass, tsize, torder, tsign); 397 } 398 399 @Override 400 public Datatype createDatatype(int tclass, int tsize, int torder, int tsign, Datatype tbase) throws Exception { 401 return new H4Datatype(tclass, tsize, torder, tsign); 402 } 403 404 @Override 405 public Datatype createNamedDatatype(Datatype tnative, String name) throws Exception { 406 throw new UnsupportedOperationException("HDF4 does not support named datatype."); 407 } 408 409 @Override 410 public Dataset createScalarDS(String name, Group pgroup, Datatype type, 411 long[] dims, long[] maxdims, long[] chunks, 412 int gzip, Object fillValue, Object data) throws Exception { 413 return H4SDS.create(name, pgroup, type, dims, maxdims, chunks, gzip, fillValue, data); 414 } 415 416 @Override 417 public Dataset createImage(String name, Group pgroup, Datatype type, 418 long[] dims, long[] maxdims, long[] chunks, 419 int gzip, int ncomp, int interlace, Object data) throws Exception { 420 return H4GRImage.create(name, pgroup, type, dims, maxdims, chunks, gzip, ncomp, interlace, data); 421 } 422 423 /** 424 * Delete an object from the file. 425 * 426 * @param obj 427 * the data object to delete. 428 * 429 * @throws Exception if the object can not be deleted 430 */ 431 @Override 432 public void delete(HObject obj) throws Exception { 433 throw new UnsupportedOperationException("Cannot delete HDF4 object."); 434 } 435 436 /** 437 * Copy an object to a group. 438 * 439 * @param srcObj 440 * the object to copy. 441 * @param dstGroup 442 * the destination group. 443 * 444 * @return the destination group, if the copy was successful, or 445 * null otherwise. 446 * 447 * @throws Exception if the object can not be copied 448 */ 449 @Override 450 public HObject copy(HObject srcObj, Group dstGroup, String dstName) 451 throws Exception { 452 log.trace("copy(): start: srcObj={} dstGroup={} dstName={}", srcObj, dstGroup, dstName); 453 454 if ((srcObj == null) || (dstGroup == null)) { 455 log.debug("copy(): source or destination is null"); 456 return null; 457 } 458 459 if (dstName == null) { 460 dstName = srcObj.getName(); 461 log.trace("copy(): dstName is null, using dstName={}", dstName); 462 } 463 464 HObject newObj = null; 465 if (srcObj instanceof H4SDS) { 466 log.trace("copy(): srcObj instanceof H4SDS"); 467 newObj = ((H4SDS) srcObj).copy(dstGroup, dstName, null, null); 468 } 469 else if (srcObj instanceof H4GRImage) { 470 log.trace("copy(): srcObj instanceof H4GRImage"); 471 newObj = ((H4GRImage) srcObj).copy(dstGroup, dstName, null, null); 472 } 473 else if (srcObj instanceof H4Vdata) { 474 log.trace("copy(): srcObj instanceof H4Vdata"); 475 newObj = ((H4Vdata) srcObj).copy(dstGroup, dstName, null, null); 476 } 477 else if (srcObj instanceof H4Group) { 478 log.trace("copy(): srcObj instanceof H4Group"); 479 newObj = copyGroup((H4Group) srcObj, (H4Group) dstGroup); 480 } 481 482 return newObj; 483 } 484 485 /** 486 * Creates a new attribute and attaches it to the object if the 487 * attribute does not exist. Otherwise, just update the value of 488 * the attribute. 489 * 490 * @param obj 491 * the object which the attribute is to be attached to. 492 * @param attr 493 * the attribute to attach. 494 * @param isSDglobalAttr 495 * The indicator if the given attribute exists. 496 * 497 * @throws HDFException if the attribute can not be written 498 */ 499 @Override 500 public void writeAttribute(HObject obj, Attribute attr, boolean isSDglobalAttr) throws HDFException { 501 log.trace("writeAttribute(): start: obj={} attribute={} isSDglobalAttr={}", obj, attr, isSDglobalAttr); 502 503 String attrName = attr.getName(); 504 long attrType = attr.getDatatype().createNative(); 505 long[] dims = attr.getDims(); 506 int count = 1; 507 if (dims != null) { 508 for (int i = 0; i < dims.length; i++) { 509 count *= (int) dims[i]; 510 } 511 } 512 513 log.trace("writeAttribute(): count={}", count); 514 515 Object attrValue; 516 try { 517 attrValue = attr.getData(); 518 } 519 catch (Exception ex) { 520 attrValue = null; 521 log.trace("writeAttribute(): getData() failure:", ex); 522 } 523 524 if (Array.get(attrValue, 0) instanceof String) { 525 String strValue = (String) Array.get(attrValue, 0); 526 527 if (strValue.length() > count) { 528 // truncate the extra characters 529 strValue = strValue.substring(0, count); 530 Array.set(attrValue, 0, strValue); 531 } 532 else { 533 // pad space to the unused space 534 for (int i = strValue.length(); i < count; i++) { 535 strValue += " "; 536 } 537 } 538 539 byte[] bval = strValue.getBytes(); 540 // add null to the end to get rid of the junks 541 bval[(strValue.length() - 1)] = 0; 542 attrValue = bval; 543 } 544 545 if ((obj instanceof H4Group) && ((H4Group) obj).isRoot()) { 546 if (isSDglobalAttr) { 547 HDFLibrary.SDsetattr(sdid, attrName, attrType, count, attrValue); 548 } 549 else { 550 HDFLibrary.GRsetattr(grid, attrName, attrType, count, attrValue); 551 } 552 log.trace("writeAttribute(): wrote attribute to root H4Group"); 553 return; 554 } 555 556 long id = obj.open(); 557 558 if (id >= 0) { 559 if (obj instanceof H4Group) { 560 HDFLibrary.Vsetattr(id, attrName, attrType, count, attrValue); 561 log.trace("writeAttribute(): wrote attribute to H4Group"); 562 } 563 else if (obj instanceof H4SDS) { 564 HDFLibrary.SDsetattr(id, attrName, attrType, count, attrValue); 565 log.trace("writeAttribute(): wrote attribute to H4SDS"); 566 } 567 else if (obj instanceof H4GRImage) { 568 HDFLibrary.GRsetattr(id, attrName, attrType, count, attrValue); 569 log.trace("writeAttribute(): wrote attribute to H4GRImage"); 570 } 571 else if (obj instanceof H4Vdata) { 572 HDFLibrary.VSsetattr(id, -1, attrName, attrType, count, attrValue); 573 log.trace("writeAttribute(): wrote attribute to H4Vdata"); 574 } 575 576 obj.close(id); 577 } 578 } 579 580 private HObject copyGroup(H4Group srcGroup, H4Group pgroup) 581 throws Exception { 582 log.trace("copyGroup(): start: srcGroup={} parentGroup={}", srcGroup, pgroup); 583 584 H4Group group = null; 585 long srcgid = -1; 586 long dstgid = -1; 587 String gname = null; 588 String path = null; 589 590 dstgid = HDFLibrary.Vattach(fid, -1, "w"); 591 if (dstgid < 0) { 592 log.trace("copyGroup(): Invalid dst Group Id"); 593 return null; 594 } 595 596 gname = srcGroup.getName(); 597 srcgid = srcGroup.open(); 598 599 HDFLibrary.Vsetname(dstgid, gname); 600 int ref = HDFLibrary.VQueryref(dstgid); 601 int tag = HDFLibrary.VQuerytag(dstgid); 602 603 if (pgroup.isRoot()) { 604 path = HObject.SEPARATOR; 605 } 606 else { 607 // add the dataset to the parent group 608 path = pgroup.getPath() + pgroup.getName() + HObject.SEPARATOR; 609 long pid = pgroup.open(); 610 HDFLibrary.Vinsert(pid, dstgid); 611 pgroup.close(pid); 612 } 613 614 // copy attributes 615 int numberOfAttributes = 0; 616 try { 617 numberOfAttributes = HDFLibrary.Vnattrs(srcgid); 618 } 619 catch (Exception ex) { 620 log.debug("copyGroup(): Vnattrs failure: ", ex); 621 numberOfAttributes = 0; 622 } 623 624 String[] attrName = new String[1]; 625 byte[] attrBuff = null; 626 int[] attrInfo = new int[3]; // data_type, count, size 627 for (int i = 0; i < numberOfAttributes; i++) { 628 try { 629 attrName[0] = ""; 630 HDFLibrary.Vattrinfo(srcgid, i, attrName, attrInfo); 631 attrBuff = new byte[attrInfo[2]]; 632 HDFLibrary.Vgetattr(srcgid, i, attrBuff); 633 HDFLibrary.Vsetattr(dstgid, attrName[0], attrInfo[0], 634 attrInfo[2], attrBuff); 635 } 636 catch (Exception ex) { 637 log.trace("copyGroup(): failure: ", ex); 638 } 639 } 640 641 long[] oid = { tag, ref }; 642 group = new H4Group(this, gname, path, pgroup, oid); 643 644 pgroup.addToMemberList(group); 645 646 // copy members of the source group to the new group 647 List<HObject> members = srcGroup.getMemberList(); 648 if ((members != null) && !members.isEmpty()) { 649 Iterator<HObject> iterator = members.iterator(); 650 while (iterator.hasNext()) { 651 HObject mObj = iterator.next(); 652 try { 653 copy(mObj, group, mObj.getName()); 654 } 655 catch (Exception ex) { 656 log.debug("copy(): failure: ", ex); 657 } 658 } 659 } 660 661 srcGroup.close(srcgid); 662 663 if (dstgid >= 0) { 664 try { 665 HDFLibrary.Vdetach(dstgid); 666 } 667 catch (Exception ex) { 668 log.debug("copyGroup(): Vdetach failure: ", ex); 669 } 670 } 671 672 return group; 673 } 674 675 /** 676 * Retrieves the file structure from disk and returns the root object. 677 * <p> 678 * First gets the top level objects or objects that do not belong to any 679 * groups. If a top level object is a group, call the depth_first() to 680 * retrieve the sub-tree of that group, recursively. 681 */ 682 private void loadIntoMemory() { 683 if (fid < 0) { 684 log.debug("loadIntoMemory(): Invalid File Id"); 685 return; 686 } 687 688 int n = 0; 689 int ref = -1; 690 int[] argv = null; 691 692 // get top level VGroup 693 int[] tmpN = new int[1]; 694 int[] refs = null; 695 696 try { 697 // first call to get the number of lone Vgroups 698 log.trace("loadIntoMemory(): first call to Vlone: get number of lone Vgroups"); 699 n = HDFLibrary.Vlone(fid, tmpN, 0); 700 log.trace("loadIntoMemory(): number of lone Vgroups={}", n); 701 refs = new int[n]; 702 703 // second call to get the references of all lone Vgroups 704 log.trace("loadIntoMemory(): second call to Vlone: get references of lone Vgroups"); 705 n = HDFLibrary.Vlone(fid, refs, n); 706 } 707 catch (HDFException ex) { 708 log.trace("loadIntoMemory(): get Vlone failure: ", ex); 709 n = 0; 710 } 711 712 /* 713 * TODO: Root group's name should be changed to 'this.getName()' and all 714 * previous accesses of this field should now use getPath() instead of getName() 715 * to get the root group. The root group actually does have a path of "/". The 716 * depth_first method will have to be changed to setup other object paths 717 * appropriately, as it currently assumes the root path to be null. 718 */ 719 long[] oid = { 0, 0 }; 720 // root object does not have a parent path or a parent object 721 rootObject = new H4Group(this, "/", null, null, oid); 722 723 int i0 = Math.max(0, getStartMembers()); 724 int i1 = getMaxMembers(); 725 if (i1 >= n) { 726 i1 = n; 727 i0 = 0; // load all members 728 } 729 i1 += i0; 730 i1 = Math.min(i1, n); 731 732 // Iterate through the file to see members of the group 733 log.trace("loadIntoMemory(): start={} to last={}", i0, i1); 734 for (int i = i0; i < i1; i++) { 735 ref = refs[i]; 736 log.trace("loadIntoMemory(): Iterate[{}] members of the group ref={}",i,ref); 737 H4Group g = getVGroup(HDFConstants.DFTAG_VG, ref, HObject.SEPARATOR, (H4Group) rootObject, false); 738 739 if (g != null) { 740 ((H4Group) rootObject).addToMemberList(g); 741 742 // recursively get the sub-tree 743 depth_first(g); 744 } 745 } 746 747 // get the top level GR images 748 argv = new int[2]; 749 boolean b = false; 750 try { 751 b = HDFLibrary.GRfileinfo(grid, argv); 752 } 753 catch (HDFException ex) { 754 log.debug("loadIntoMemory(): GRfileinfo failure: ",ex); 755 b = false; 756 } 757 758 if (b) { 759 n = argv[0]; 760 761 for (int i = 0; i < n; i++) { 762 // no duplicate object at top level 763 H4GRImage gr = getGRImage(HDFConstants.DFTAG_RIG, i, HObject.SEPARATOR, false); 764 if (gr != null) { 765 ((H4Group) rootObject).addToMemberList(gr); 766 } 767 } // (int i=0; i<n; i++) 768 } // ( grid!=HDFConstants.FAIL && HDFLibrary.GRfileinfo(grid,argv) ) 769 770 // get top level SDS 771 try { 772 b = HDFLibrary.SDfileinfo(sdid, argv); 773 } 774 catch (HDFException ex) { 775 log.debug("loadIntoMemory(): SDfileinfo failure: ",ex); 776 b = false; 777 } 778 779 if (b) { 780 n = argv[0]; 781 for (int i = 0; i < n; i++) { 782 // no duplicate object at top level 783 H4SDS sds = getSDS(HDFConstants.DFTAG_NDG, i, HObject.SEPARATOR, false); 784 if (sds != null) { 785 ((H4Group) rootObject).addToMemberList(sds); 786 } 787 } 788 } // (HDFLibrary.SDfileinfo(sdid, argv)) 789 790 // get top level VData 791 try { 792 n = HDFLibrary.VSlone(fid, tmpN, 0); 793 log.trace("loadIntoMemory(): number of lone Vdatas={}", n); 794 refs = new int[n]; 795 n = HDFLibrary.VSlone(fid, refs, n); 796 } 797 catch (HDFException ex) { 798 log.debug("loadIntoMemory(): VSlone failure: ",ex); 799 n = 0; 800 } 801 802 for (int i = 0; i < n; i++) { 803 ref = refs[i]; 804 log.trace("loadIntoMemory(): references of Vdata[{}]={}", i, ref); 805 806 // no duplicate object at top level 807 H4Vdata vdata = getVdata(HDFConstants.DFTAG_VS, ref, HObject.SEPARATOR, false); 808 809 if (vdata != null) { 810 ((H4Group) rootObject).addToMemberList(vdata); 811 } 812 } 813 814 if (rootObject != null) { 815 // retrieve file annotation, GR and SDS global attributes 816 @SuppressWarnings("rawtypes") 817 List attributeList = null; 818 try { 819 attributeList = ((H4Group) rootObject).getMetadata(); 820 } 821 catch (HDFException ex) { 822 log.debug("loadIntoMemory(): getMetadata failure: ", ex); 823 } 824 825 try { 826 getFileAnnotation(fid, attributeList); 827 } 828 catch (HDFException ex) { 829 log.debug("loadIntoMemory(): getFileAnnotation failure: ", ex); 830 } 831 try { 832 getGRglobalAttribute(grid, attributeList); 833 } 834 catch (HDFException ex) { 835 log.debug("loadIntoMemory(): getGRglobalAttribute failure: ", ex); 836 } 837 try { 838 getSDSglobalAttribute(sdid, attributeList); 839 } 840 catch (HDFException ex) { 841 log.debug("loadIntoMemory(): getSDglobalAttribute failure: ", ex); 842 } 843 } 844 845 } 846 847 /** 848 * Retrieves the tree structure of the file by depth-first order. The 849 * current implementation only retrieves groups and datasets. It does not 850 * include named datatypes and soft links. 851 * 852 * @param parentObject 853 * the parent object. 854 */ 855 private void depth_first(HObject parentObj) { 856 log.trace("depth_first(pobj = {})", parentObj); 857 858 if (parentObj == null) { 859 log.debug("depth_first(): Parent object is null"); 860 return; 861 } 862 863 int nelems = 0; 864 int ref = -1; 865 int tag = -1; 866 int index = -1; 867 int[] tags = null; 868 int[] refs = null; 869 870 H4Group parentGroup = (H4Group) parentObj; 871 872 String fullPath = parentGroup.getPath() + parentGroup.getName() + HObject.SEPARATOR; 873 long gid = parentGroup.open(); 874 if (gid == HDFConstants.FAIL) { 875 log.debug("depth_first(): Invalid Parent group ID"); 876 return; 877 } 878 879 try { 880 nelems = HDFLibrary.Vntagrefs(gid); 881 tags = new int[nelems]; 882 refs = new int[nelems]; 883 nelems = HDFLibrary.Vgettagrefs(gid, tags, refs, nelems); 884 } 885 catch (HDFException ex) { 886 log.debug("depth_first(): failure: ", ex); 887 nelems = 0; 888 } 889 finally { 890 parentGroup.close(gid); 891 } 892 893 int i0 = Math.max(0, getStartMembers()); 894 int i1 = getMaxMembers(); 895 if (i1 >= nelems) { 896 i1 = nelems; 897 i0 = 0; // load all members 898 } 899 i1 += i0; 900 i1 = Math.min(i1, nelems); 901 902 // Iterate through the file to see members of the group 903 for (int i = i0; i < i1; i++) { 904 tag = tags[i]; 905 ref = refs[i]; 906 907 switch (tag) { 908 case HDFConstants.DFTAG_RIG: 909 case HDFConstants.DFTAG_RI: 910 case HDFConstants.DFTAG_RI8: 911 try { 912 index = HDFLibrary.GRreftoindex(grid, (short) ref); 913 } 914 catch (HDFException ex) { 915 index = HDFConstants.FAIL; 916 } 917 if (index != HDFConstants.FAIL) { 918 H4GRImage gr = getGRImage(tag, index, fullPath, true); 919 parentGroup.addToMemberList(gr); 920 } 921 break; 922 case HDFConstants.DFTAG_SD: 923 case HDFConstants.DFTAG_SDG: 924 case HDFConstants.DFTAG_NDG: 925 try { 926 index = HDFLibrary.SDreftoindex(sdid, ref); 927 } 928 catch (HDFException ex) { 929 index = HDFConstants.FAIL; 930 } 931 if (index != HDFConstants.FAIL) { 932 H4SDS sds = getSDS(tag, index, fullPath, true); 933 parentGroup.addToMemberList(sds); 934 } 935 break; 936 case HDFConstants.DFTAG_VH: 937 case HDFConstants.DFTAG_VS: 938 H4Vdata vdata = getVdata(tag, ref, fullPath, true); 939 parentGroup.addToMemberList(vdata); 940 break; 941 case HDFConstants.DFTAG_VG: 942 H4Group vgroup = getVGroup(tag, ref, fullPath, parentGroup, true); 943 parentGroup.addToMemberList(vgroup); 944 if ((vgroup != null) && (parentGroup != null)) { 945 // check for loops 946 boolean looped = false; 947 H4Group theGroup = parentGroup; 948 while ((theGroup != null) && !looped) { 949 long[] oid = { tag, ref }; 950 if (theGroup.equalsOID(oid)) { 951 looped = true; 952 } 953 else { 954 theGroup = (H4Group) theGroup.getParent(); 955 } 956 } 957 if (!looped) { 958 depth_first(vgroup); 959 } 960 } 961 break; 962 default: 963 break; 964 } // switch 965 966 } // (int i=0; i<nelms; i++) 967 } // private depth_first() 968 969 /** 970 * Returns a list of all the members of this H4File in a 971 * breadth-first ordering that are rooted at the specified 972 * object. 973 */ 974 private static List<HObject> getMembersBreadthFirst(HObject obj) { 975 List<HObject> allMembers = new ArrayList<>(); 976 Queue<HObject> queue = new LinkedList<>(); 977 HObject currentObject = obj; 978 979 queue.add(currentObject); 980 981 while(!queue.isEmpty()) { 982 currentObject = queue.remove(); 983 allMembers.add(currentObject); 984 985 if(currentObject instanceof Group) { 986 queue.addAll(((Group) currentObject).getMemberList()); 987 } 988 } 989 990 return allMembers; 991 } 992 993 /** 994 * Retrieve a GR image for the given GR image identifier and index. 995 * 996 * @param tag 997 * the reference tag of the GR image. 998 * @param index 999 * the index of the image. 1000 * @param path 1001 * the path of the image. 1002 * @param copyAllowed 1003 * The indicator if multiple copies of an object is allowed. 1004 * 1005 * @return the new H5GRImage if successful; otherwise returns null. 1006 */ 1007 @SuppressWarnings("unchecked") 1008 private final H4GRImage getGRImage(int tag, int index, String path, boolean copyAllowed) { 1009 log.trace("getGRImage(): start: tag={} index={} path={} copyAllowed={}", tag, index, path, copyAllowed); 1010 1011 long id = -1; 1012 int ref = -1; 1013 H4GRImage gr = null; 1014 String[] objName = { "" }; 1015 int[] imgInfo = new int[4]; 1016 int[] dimSizes = { 0, 0 }; 1017 1018 try { 1019 id = HDFLibrary.GRselect(grid, index); 1020 ref = HDFLibrary.GRidtoref(id); 1021 log.trace("getGRImage(): GRselect:{} GRidtoref:{}",id,ref); 1022 HDFLibrary.GRgetiminfo(id, objName, imgInfo, dimSizes); 1023 } 1024 catch (HDFException ex) { 1025 log.debug("getGRImage(): failure: ", ex); 1026 id = HDFConstants.FAIL; 1027 } 1028 finally { 1029 if (id >= 0) { 1030 try { 1031 HDFLibrary.GRendaccess(id); 1032 } 1033 catch (HDFException ex) { 1034 log.debug("getGRImage(): GRendaccess failure: ", ex); 1035 } 1036 } 1037 } 1038 1039 if (id != HDFConstants.FAIL) { 1040 long[] oid = { tag, ref }; 1041 1042 if (copyAllowed) { 1043 objList.add(oid); 1044 } 1045 else if (find(oid)) { 1046 log.trace("getGRImage(): Image found in memory with OID:({}, {})", oid[0], oid[1]); 1047 return null; 1048 } 1049 1050 gr = new H4GRImage(this, objName[0], path, oid); 1051 } 1052 1053 return gr; 1054 } 1055 1056 /** 1057 * Retrieve a SDS for the given sds identifier and index. 1058 * 1059 * @param tag 1060 * the reference tag of the group (DFTAG_SD, DFTAG_SDG, DFTAG_NDG). 1061 * @param index 1062 * the index of the SDS. 1063 * @param path 1064 * the path of the SDS. 1065 * @param copyAllowed 1066 * The indicator if multiple copies of an object is allowed. 1067 * 1068 * @return the new H4SDS if successful; otherwise returns null. 1069 */ 1070 @SuppressWarnings("unchecked") 1071 private final H4SDS getSDS(int tag, int index, String path, boolean copyAllowed) { 1072 log.trace("getSDS(): start: tag={} index={} path={} copyAllowed={}", tag, index, path, copyAllowed); 1073 1074 long id = -1; 1075 int ref = -1; 1076 H4SDS sds = null; 1077 String[] objName = { "" }; 1078 int[] tmpInfo = new int[HDFConstants.MAX_VAR_DIMS]; 1079 int[] sdInfo = { 0, 0, 0 }; 1080 1081 boolean isCoordvar = false; 1082 try { 1083 id = HDFLibrary.SDselect(sdid, index); 1084 if (isNetCDF) { 1085 ref = index; // HDFLibrary.SDidtoref(id) fails for netCDF 1086 tag = H4SDS.DFTAG_NDG_NETCDF; 1087 } 1088 else { 1089 ref = HDFLibrary.SDidtoref(id); 1090 } 1091 log.trace("getSDS(): SDselect id={} with ref={} isNetCDF={}", id, ref, isNetCDF); 1092 1093 HDFLibrary.SDgetinfo(id, objName, tmpInfo, sdInfo); 1094 log.trace("getSDS(): SDselect id={} with objName={}: rank={}, numberType={}, nAttributes={}", id, objName, sdInfo[0], sdInfo[1], sdInfo[2]); 1095 1096 try { 1097 isCoordvar = HDFLibrary.SDiscoordvar(id); 1098 } 1099 catch (Exception ex) { 1100 log.debug("getSDS(): SDiscoordvar failure: ", ex); 1101 } 1102 } 1103 catch (HDFException ex) { 1104 log.debug("getSDS(): failure: ", ex); 1105 id = HDFConstants.FAIL; 1106 } 1107 finally { 1108 if (id >= 0) { 1109 try { 1110 HDFLibrary.SDendaccess(id); 1111 } 1112 catch (HDFException ex) { 1113 log.debug("getSDS(): SDendaccess failure: ", ex); 1114 } 1115 } 1116 } 1117 1118 // check if the given SDS has dimension metadata 1119 // Coordinate variables are not displayed. They are created to store 1120 // metadata associated with dimensions. To ensure compatibility with 1121 // netCDF, coordinate variables are implemented as data sets 1122 1123 if (isCoordvar) { 1124 objName[0] += " (dimension)"; 1125 } 1126 1127 if (id != HDFConstants.FAIL) { // && !isCoordvar) 1128 long[] oid = { tag, ref }; 1129 1130 if (copyAllowed) { 1131 objList.add(oid); 1132 } 1133 else if (find(oid)) { 1134 log.trace("getSDS(): SDS found in memory with OID:({}, {})", oid[0], oid[1]); 1135 return null; 1136 } 1137 1138 sds = new H4SDS(this, objName[0], path, oid); 1139 } 1140 1141 return sds; 1142 } 1143 1144 /** 1145 * Retrieve a Vdata for the given Vdata identifier and index. 1146 * 1147 * @param tag 1148 * the reference tag of the Vdata. 1149 * @param ref 1150 * the reference identifier of the Vdata. 1151 * @param path 1152 * the path of the Vdata. 1153 * @param copyAllowed 1154 * The indicator if multiple copies of an object is allowed. 1155 * 1156 * @return the new H4Vdata if successful; otherwise returns null. 1157 */ 1158 @SuppressWarnings("unchecked") 1159 private final H4Vdata getVdata(int tag, int ref, String path, boolean copyAllowed) { 1160 log.trace("getVdata(): start: tag={} ref={} path={} copyAllowed={}", tag, ref, path, copyAllowed); 1161 1162 long id = -1; 1163 H4Vdata vdata = null; 1164 String[] objName = { "" }; 1165 String[] vClass = { "" }; 1166 long[] oid = { tag, ref }; 1167 1168 if (copyAllowed) { 1169 objList.add(oid); 1170 } 1171 else if (find(oid)) { 1172 log.trace("getVdata(): VData found in memory with OID:({}, {})", oid[0], oid[1]); 1173 return null; 1174 } 1175 1176 try { 1177 id = HDFLibrary.VSattach(fid, ref, "r"); 1178 HDFLibrary.VSgetclass(id, vClass); 1179 vClass[0] = vClass[0].trim(); 1180 HDFLibrary.VSgetname(id, objName); 1181 } 1182 catch (HDFException ex) { 1183 log.trace("getVData(): failure: ", ex); 1184 id = HDFConstants.FAIL; 1185 } 1186 finally { 1187 if (id >= 0) { 1188 try { 1189 HDFLibrary.VSdetach(id); 1190 } 1191 catch (HDFException ex) { 1192 log.debug("getVData(): VSdetach failure: ", ex); 1193 } 1194 } 1195 } 1196 1197 if (showAll || 1198 ((id != HDFConstants.FAIL) 1199 && !vClass[0].equalsIgnoreCase(HDFConstants.HDF_ATTRIBUTE) // do not display Vdata named "Attr0.0" // commented out for bug 1737 1200 && !vClass[0].startsWith(HDFConstants.HDF_CHK_TBL) // do not display internal Vdata, "_HDF_CHK_TBL_" 1201 && !vClass[0].startsWith(HDFConstants.HDF_SDSVAR) // do not display attributes 1202 && !vClass[0].startsWith(HDFConstants.HDF_CRDVAR) 1203 && !vClass[0].startsWith(HDFConstants.DIM_VALS) 1204 && !vClass[0].startsWith(HDFConstants.DIM_VALS01) 1205 && !vClass[0].startsWith(HDFConstants.RIGATTRCLASS) 1206 && !vClass[0].startsWith(HDFConstants.RIGATTRNAME) 1207 && !vClass[0].equalsIgnoreCase(HDFConstants.HDF_CDF))) // do not display internal vdata for CDF, "CDF0.0" 1208 { 1209 vdata = new H4Vdata(this, objName[0], path, oid); 1210 } 1211 1212 return vdata; 1213 } 1214 1215 /** 1216 * Retrieve a VGroup for the given VGroup identifier and index. 1217 * 1218 * @param tag 1219 * the reference tag of the VGroup. 1220 * @param ref 1221 * the reference identifier of the VGroup. 1222 * @param path 1223 * the path of the VGroup. 1224 * @param pgroup 1225 * the parent group. 1226 * @param copyAllowed 1227 * The indicator if multiple copies of an object is allowed. 1228 * 1229 * @return the new H4VGroup if successful; otherwise returns null. 1230 */ 1231 @SuppressWarnings("unchecked") 1232 private final H4Group getVGroup(int tag, int ref, String path, H4Group pgroup, boolean copyAllowed) { 1233 log.trace("getVGroup(): start: tag={}, ref={} path={} pgroup={} copyAllowed={}", tag, ref, path, pgroup, copyAllowed); 1234 1235 long id = -1; 1236 H4Group vgroup = null; 1237 String[] objName = { "" }; 1238 String[] vClass = { "" }; 1239 long[] oid = { tag, ref }; 1240 1241 if (ref <= 0) { 1242 log.trace("getVGroup(): Skipping dummy root group with ref={}", ref); 1243 return null; 1244 } 1245 1246 if (copyAllowed) { 1247 objList.add(oid); 1248 } 1249 else if (find(oid)) { 1250 log.trace("getVGroup(): VGroup found in memory with OID:({}, {})", oid[0], oid[1]); 1251 return null; 1252 } 1253 1254 try { 1255 id = HDFLibrary.Vattach(fid, ref, "r"); 1256 log.trace("getVGroup(): Vattach fid={} id={}", fid, id); 1257 HDFLibrary.Vgetclass(id, vClass); 1258 vClass[0] = vClass[0].trim(); 1259 HDFLibrary.Vgetname(id, objName); 1260 } 1261 catch (HDFException ex) { 1262 log.debug("getVGroup(): failure: ",ex); 1263 id = HDFConstants.FAIL; 1264 } 1265 finally { 1266 if (id >= 0) { 1267 try { 1268 HDFLibrary.Vdetach(id); 1269 } 1270 catch (HDFException ex) { 1271 log.debug("getVGroup(): Vdetach failure: ", ex); 1272 } 1273 } 1274 } 1275 1276 // ignore the Vgroups created by the GR interface 1277 if (showAll || ((id != HDFConstants.FAIL) 1278 && !vClass[0].equalsIgnoreCase(HDFConstants.GR_NAME) // do not display Vdata named "Attr0.0" 1279 && !vClass[0].equalsIgnoreCase(HDFConstants.RI_NAME) 1280 && !vClass[0].equalsIgnoreCase(HDFConstants.RIGATTRNAME) 1281 && !vClass[0].equalsIgnoreCase(HDFConstants.RIGATTRCLASS) 1282 && !vClass[0].equalsIgnoreCase(HDFConstants.HDF_CDF))) 1283 { 1284 vgroup = new H4Group(this, objName[0], path, pgroup, oid); 1285 } 1286 1287 return vgroup; 1288 } 1289 1290 /** 1291 * Check if object already exists in memory by matching the (tag, ref) pairs. 1292 */ 1293 @SuppressWarnings("unchecked") 1294 private final boolean find(long[] oid) { 1295 log.trace("find(): start: oid({}, {})", oid[0], oid[1]); 1296 1297 boolean existed = false; 1298 1299 if (objList == null) { 1300 log.debug("find(): objList is null"); 1301 return false; 1302 } 1303 1304 int n = objList.size(); 1305 long[] theOID = null; 1306 1307 for (int i = 0; i < n; i++) { 1308 theOID = (long[]) objList.get(i); 1309 if ((theOID[0] == oid[0]) && (theOID[1] == oid[1])) { 1310 log.trace("find(): matched object in objList"); 1311 existed = true; 1312 break; 1313 } 1314 } 1315 1316 if (!existed) { 1317 objList.add(oid); 1318 } 1319 1320 return existed; 1321 } 1322 1323 /** 1324 * Returns the GR identifier, which is returned from GRstart(fid). 1325 * 1326 * @return the identifier. 1327 */ 1328 long getGRAccessID() { 1329 return grid; 1330 } 1331 1332 /** 1333 * Returns the SDS identifier, which is returned from SDstart(fname, flag). 1334 * 1335 * @return the identifier. 1336 */ 1337 long getSDAccessID() { 1338 return sdid; 1339 } 1340 1341 /** 1342 * Reads HDF file annotation (file labels and descriptions) into memory. 1343 * The file annotation is stored as an attribute of the root group. 1344 * 1345 * @param fid 1346 * the file identifier. 1347 * @param attrList 1348 * the list of attributes. 1349 * 1350 * @return the updated attribute list. 1351 * 1352 * @throws Exception if the annotation can not be read 1353 */ 1354 @SuppressWarnings({"rawtypes", "unchecked"}) 1355 private List getFileAnnotation(long fid, List attrList) throws HDFException { 1356 log.trace("getFileAnnotation(): start: FID={}", fid); 1357 1358 if (fid < 0) { 1359 log.debug("getFileAnnotation(): Invalid FID"); 1360 return attrList; 1361 } 1362 1363 long anid = HDFConstants.FAIL; 1364 try { 1365 anid = HDFLibrary.ANstart(fid); 1366 // fileInfo[0] = n_file_label, fileInfo[1] = n_file_desc, 1367 // fileInfo[2] = n_data_label, fileInfo[3] = n_data_desc 1368 int[] fileInfo = new int[4]; 1369 HDFLibrary.ANfileinfo(anid, fileInfo); 1370 1371 if (fileInfo[0] + fileInfo[1] <= 0) { 1372 try { 1373 HDFLibrary.ANend(anid); 1374 } 1375 catch (HDFException ex) { 1376 log.debug("getFileAnnotation(): ANend failure: ", ex); 1377 } 1378 1379 log.debug("getFileAnnotation(): n_file_labels + n_file_descriptions <= 0"); 1380 return attrList; 1381 } 1382 1383 if (attrList == null) { 1384 attrList = new Vector(fileInfo[0] + fileInfo[1], 5); 1385 } 1386 1387 // load file labels and descriptions 1388 long id = -1; 1389 int[] annTypes = { HDFConstants.AN_FILE_LABEL, 1390 HDFConstants.AN_FILE_DESC }; 1391 for (int j = 0; j < 2; j++) { 1392 String annName = null; 1393 if (j == 0) { 1394 annName = "File Label"; 1395 } 1396 else { 1397 annName = "File Description"; 1398 } 1399 1400 for (int i = 0; i < fileInfo[j]; i++) { 1401 try { 1402 id = HDFLibrary.ANselect(anid, i, annTypes[j]); 1403 } 1404 catch (HDFException ex) { 1405 log.debug("getFileAnnotation(): ANselect failure: ", ex); 1406 id = HDFConstants.FAIL; 1407 } 1408 1409 if (id == HDFConstants.FAIL) { 1410 log.trace("getFileAnnotation(): ANselect({}, {}, {}) failure", anid, i, annTypes[j]); 1411 try { 1412 HDFLibrary.ANendaccess(id); 1413 } 1414 catch (HDFException ex) { 1415 log.debug("getFileAnnotation(): ANendaccess failure: ", ex); 1416 } 1417 continue; 1418 } 1419 1420 int length = 0; 1421 try { 1422 length = HDFLibrary.ANannlen(id) + 1; 1423 } 1424 catch (HDFException ex) { 1425 log.debug("getFileAnnotation(): ANannlen failure: ", ex); 1426 length = 0; 1427 } 1428 1429 if (length > 0) { 1430 boolean b = false; 1431 String[] str = { "" }; 1432 try { 1433 b = HDFLibrary.ANreadann(id, str, length); 1434 } 1435 catch (HDFException ex) { 1436 log.debug("getFileAnnotation(): ANreadann failure: ", ex); 1437 b = false; 1438 } 1439 1440 if (b && (str[0].length() > 0)) { 1441 long[] attrDims = { str.length }; 1442 Datatype attrType = null; 1443 try { 1444 attrType = new H4Datatype(HDFConstants.DFNT_CHAR); 1445 } 1446 catch (Exception ex) { 1447 log.debug("getFileAnnotation(): failed to create datatype for attribute: ", ex); 1448 } 1449 Attribute newAttr = new Attribute(getRootObject(), annName + " #" + i, attrType, attrDims); 1450 attrList.add(newAttr); 1451 newAttr.setData(str); 1452 } 1453 } 1454 1455 try { 1456 HDFLibrary.ANendaccess(id); 1457 } 1458 catch (HDFException ex) { 1459 log.debug("getFileAnnotation(): ANendaccess failure: ", ex); 1460 } 1461 } // (int i=0; i < fileInfo[annTYpe]; i++) 1462 } // (int annType=0; annType<2; annType++) 1463 } 1464 finally { 1465 if (anid >= 0) { 1466 try { 1467 HDFLibrary.ANend(anid); 1468 } 1469 catch (HDFException ex) { 1470 log.debug("getFileAnnotation(): ANend failure: ", ex); 1471 } 1472 } 1473 } 1474 1475 return attrList; 1476 } 1477 1478 /** 1479 * Reads GR global attributes into memory. The attributes are stored as 1480 * attributes of the root group. 1481 * 1482 * @param grid 1483 * the GR identifier. 1484 * @param attrList 1485 * the list of attributes. 1486 * 1487 * @return the updated attribute list. 1488 * 1489 * @throws HDFException if the GR attributes can not be read 1490 */ 1491 @SuppressWarnings({"rawtypes", "unchecked"}) 1492 private List getGRglobalAttribute(long grid, List attrList) 1493 throws HDFException { 1494 log.trace("getGRglobalAttribute(): start: GRID={}", grid); 1495 1496 if (grid == HDFConstants.FAIL) { 1497 log.debug("getGRglobalAttribute(): Invalid GRID"); 1498 return attrList; 1499 } 1500 1501 int[] attrInfo = { 0, 0 }; 1502 HDFLibrary.GRfileinfo(grid, attrInfo); 1503 int numberOfAttributes = attrInfo[1]; 1504 1505 if (numberOfAttributes > 0) { 1506 if (attrList == null) { 1507 attrList = new Vector(numberOfAttributes, 5); 1508 } 1509 1510 String[] attrName = new String[1]; 1511 for (int i = 0; i < numberOfAttributes; i++) { 1512 attrName[0] = ""; 1513 boolean b = false; 1514 try { 1515 b = HDFLibrary.GRattrinfo(grid, i, attrName, attrInfo); 1516 // mask off the litend bit 1517 attrInfo[0] = attrInfo[0] & (~HDFConstants.DFNT_LITEND); 1518 } 1519 catch (HDFException ex) { 1520 log.debug("getGRglobalAttribute(): GRattrinfo failure: ", ex); 1521 b = false; 1522 } 1523 1524 if (!b) { 1525 continue; 1526 } 1527 1528 long[] attrDims = { attrInfo[1] }; 1529 1530 Object buf = null; 1531 try { 1532 buf = H4Datatype.allocateArray(attrInfo[0], attrInfo[1]); 1533 } 1534 catch (OutOfMemoryError e) { 1535 log.debug("getGRglobalAttribute(): out of memory: ", e); 1536 buf = null; 1537 } 1538 1539 try { 1540 HDFLibrary.GRgetattr(grid, i, buf); 1541 } 1542 catch (HDFException ex) { 1543 log.debug("getGRglobalAttribute(): GRgetattr failure: ", ex); 1544 buf = null; 1545 } 1546 1547 if ((buf != null) && ((attrInfo[0] == HDFConstants.DFNT_CHAR) || (attrInfo[0] == HDFConstants.DFNT_UCHAR8))) { 1548 buf = Dataset.byteToString((byte[]) buf, attrInfo[1]); 1549 attrDims[0] = ((String[]) buf).length; 1550 } 1551 1552 Datatype attrType = null; 1553 try { 1554 attrType = new H4Datatype(attrInfo[0]); 1555 } 1556 catch (Exception ex) { 1557 log.debug("getGRglobalAttribute(): failed to create datatype for attribute: ", ex); 1558 } 1559 1560 Attribute attr = new Attribute(getRootObject(), attrName[0], attrType, attrDims, buf); 1561 attrList.add(attr); 1562 } // (int i=0; i<numberOfAttributes; i++) 1563 } // (b && numberOfAttributes>0) 1564 1565 return attrList; 1566 } 1567 1568 /** 1569 * Reads SDS global attributes into memory. The attributes are stored as 1570 * attributes of the root group. 1571 * 1572 * @param sdid 1573 * the SD identifier. 1574 * @param attrList 1575 * the list of attributes. 1576 * 1577 * @return the updated attribute list. 1578 * 1579 * @throws HDFException if the SDS attributes can not be read 1580 */ 1581 @SuppressWarnings({"rawtypes", "unchecked"}) 1582 private List getSDSglobalAttribute(long sdid, List attrList) 1583 throws HDFException { 1584 log.trace("getSDSglobalAttribute(): start: SDID:{}", sdid); 1585 1586 if (sdid == HDFConstants.FAIL) { 1587 log.debug("getSDSglobalAttribute(): Invalid SDID"); 1588 return attrList; 1589 } 1590 1591 int[] attrInfo = { 0, 0 }; 1592 HDFLibrary.SDfileinfo(sdid, attrInfo); 1593 1594 int numberOfAttributes = attrInfo[1]; 1595 if (numberOfAttributes > 0) { 1596 if (attrList == null) { 1597 attrList = new Vector(numberOfAttributes, 5); 1598 } 1599 1600 String[] attrName = new String[1]; 1601 for (int i = 0; i < numberOfAttributes; i++) { 1602 attrName[0] = ""; 1603 boolean b = false; 1604 try { 1605 b = HDFLibrary.SDattrinfo(sdid, i, attrName, attrInfo); 1606 // mask off the litend bit 1607 attrInfo[0] = attrInfo[0] & (~HDFConstants.DFNT_LITEND); 1608 } 1609 catch (HDFException ex) { 1610 log.debug("getSDSglobalAttribute(): SDattrinfo failure: ", ex); 1611 b = false; 1612 } 1613 1614 if (!b) { 1615 continue; 1616 } 1617 1618 long[] attrDims = { attrInfo[1] }; 1619 1620 Object buf = null; 1621 try { 1622 buf = H4Datatype.allocateArray(attrInfo[0], attrInfo[1]); 1623 } 1624 catch (OutOfMemoryError e) { 1625 log.debug("getSDSglobalAttribute(): out of memory: ", e); 1626 buf = null; 1627 } 1628 1629 try { 1630 HDFLibrary.SDreadattr(sdid, i, buf); 1631 } 1632 catch (HDFException ex) { 1633 log.debug("getSDSglobalAttribute(): SDreadattr failure: ", ex); 1634 buf = null; 1635 } 1636 1637 if ((buf != null) && ((attrInfo[0] == HDFConstants.DFNT_CHAR) || (attrInfo[0] == HDFConstants.DFNT_UCHAR8))) { 1638 buf = Dataset.byteToString((byte[]) buf, attrInfo[1]); 1639 attrDims[0] = ((String[]) buf).length; 1640 } 1641 1642 Datatype attrType = null; 1643 try { 1644 attrType = new H4Datatype(attrInfo[0]); 1645 } 1646 catch (Exception ex) { 1647 log.debug("getSDSglobalAttribute(): failed to create datatype for attribute: ", ex); 1648 } 1649 1650 Attribute attr = new Attribute(getRootObject(), attrName[0], attrType, attrDims, buf); 1651 attrList.add(attr); 1652 } // (int i=0; i<numberOfAttributes; i++) 1653 } // (b && numberOfAttributes>0) 1654 1655 return attrList; 1656 } 1657 1658 /** 1659 * Returns the version of the HDF4 library. 1660 */ 1661 @Override 1662 public String getLibversion() { 1663 int[] vers = new int[3]; 1664 String ver = "HDF "; 1665 String[] verStr = { "" }; 1666 1667 try { 1668 HDFLibrary.Hgetlibversion(vers, verStr); 1669 } 1670 catch (HDFException ex) { 1671 log.debug("getLibVersion(): Hgetlibversion failure: ", ex); 1672 } 1673 1674 ver += vers[0] + "." + vers[1] + "." + vers[2]; 1675 log.debug("getLibversion(): libversion is {}", ver); 1676 1677 return ver; 1678 } 1679 1680 /** HDF4 library supports netCDF version 2.3.2. It only supports SDS APIs. */ 1681 private boolean isNetCDF(String filename) { 1682 log.trace("isNetCDF(): start: filename={}", filename); 1683 1684 boolean isnetcdf = false; 1685 1686 try (java.io.RandomAccessFile raf = new java.io.RandomAccessFile(filename, "r")) { 1687 byte[] header = new byte[4]; 1688 raf.read(header); 1689 // netCDF 1690 if (((header[0] == 67) && (header[1] == 68) && (header[2] == 70) && (header[3] == 1))) { 1691 isnetcdf = true; 1692 } 1693 else { 1694 isnetcdf = false; 1695 } 1696 } 1697 catch (Exception ex) { 1698 log.debug("RandomAccessFile {}", filename, ex); 1699 } 1700 1701 return isnetcdf; 1702 } 1703 1704 /** 1705 * Get an individual HObject with a given path. It does not load the whole 1706 * file structure. 1707 * 1708 * @param path the path of the object 1709 * 1710 * @throws Exception if the object cannot be found 1711 */ 1712 @Override 1713 @SuppressWarnings("rawtypes") 1714 public HObject get(String path) throws Exception { 1715 log.trace("get(): start: path={}", path); 1716 1717 if (objList == null) { 1718 objList = new Vector(); 1719 } 1720 1721 if ((path == null) || (path.length() <= 0)) { 1722 log.debug("get(): path is null or invalid path length"); 1723 return null; 1724 } 1725 1726 path = path.replace('\\', '/'); 1727 if (!path.startsWith("/")) { 1728 path = "/" + path; 1729 } 1730 1731 String name = null; 1732 String pPath = null; 1733 boolean isRoot = false; 1734 1735 if (path.equals("/")) { 1736 name = "/"; // the root 1737 isRoot = true; 1738 } 1739 else { 1740 if (path.endsWith("/")) { 1741 path = path.substring(0, path.length() - 2); 1742 } 1743 int idx = path.lastIndexOf('/'); 1744 name = path.substring(idx + 1); 1745 if (idx == 0) { 1746 pPath = "/"; 1747 } 1748 else { 1749 pPath = path.substring(0, idx); 1750 } 1751 } 1752 1753 log.trace("get(): isRoot={}", isRoot); 1754 1755 HObject obj = null; 1756 isReadOnly = false; 1757 1758 if (fid < 0) { 1759 fid = HDFLibrary.Hopen(fullFileName, HDFConstants.DFACC_WRITE); 1760 if (fid < 0) { 1761 isReadOnly = true; 1762 fid = HDFLibrary.Hopen(fullFileName, HDFConstants.DFACC_READ); 1763 } 1764 HDFLibrary.Vstart(fid); 1765 grid = HDFLibrary.GRstart(fid); 1766 sdid = HDFLibrary.SDstart(fullFileName, flag); 1767 } 1768 1769 if (isRoot) { 1770 obj = getRootGroup(); 1771 } 1772 else { 1773 obj = getAttachedObject(pPath, name); 1774 } 1775 1776 return obj; 1777 } 1778 1779 /** Get the root group and all the alone objects */ 1780 private H4Group getRootGroup() { 1781 1782 long[] oid = { 0, 0 }; 1783 int n = 0; 1784 int ref = -1; 1785 int[] argv = null; 1786 1787 H4Group rootGroup = new H4Group(this, "/", null, null, oid); 1788 1789 // get top level VGroup 1790 int[] tmpN = new int[1]; 1791 int[] refs = null; 1792 try { 1793 // first call to get the number of lone Vgroups 1794 log.trace("getRootGroup(): first call to Vlone, get number of lone Vgroups"); 1795 n = HDFLibrary.Vlone(fid, tmpN, 0); 1796 log.trace("getRootGroup(): number of lone Vgroups={}", n); 1797 refs = new int[n]; 1798 // second call to get the references of all lone Vgroups 1799 log.trace("getRootGroup(): second call to Vlone, get references of lone Vgroups"); 1800 n = HDFLibrary.Vlone(fid, refs, n); 1801 } 1802 catch (HDFException ex) { 1803 log.debug("getRootGroup(): Vlone failure: ", ex); 1804 n = 0; 1805 } 1806 1807 // Iterate through the file to see members of the group 1808 for (int i = 0; i < n; i++) { 1809 ref = refs[i]; 1810 H4Group g = getVGroup(HDFConstants.DFTAG_VG, ref, 1811 HObject.SEPARATOR, rootGroup, false); 1812 if (g != null) { 1813 rootGroup.addToMemberList(g); 1814 } 1815 } 1816 1817 // get the top level GR images 1818 argv = new int[2]; 1819 boolean b = false; 1820 try { 1821 b = HDFLibrary.GRfileinfo(grid, argv); 1822 } 1823 catch (HDFException ex) { 1824 log.debug("getRootGroup(): GRfileinfo failure: ", ex); 1825 b = false; 1826 } 1827 1828 if (b) { 1829 n = argv[0]; 1830 for (int i = 0; i < n; i++) { 1831 // no duplicate object at top level 1832 H4GRImage gr = getGRImage(HDFConstants.DFTAG_RIG, i, 1833 HObject.SEPARATOR, false); 1834 if (gr != null) { 1835 rootGroup.addToMemberList(gr); 1836 } 1837 } 1838 } // ( HDFLibrary.GRfileinfo(grid, argv) ) 1839 1840 // get top level SDS 1841 try { 1842 b = HDFLibrary.SDfileinfo(sdid, argv); 1843 } 1844 catch (HDFException ex) { 1845 log.debug("getRootGroup(): SDfileinfo failure: ", ex); 1846 b = false; 1847 } 1848 1849 if (b) { 1850 n = argv[0]; 1851 1852 for (int i = 0; i < n; i++) { 1853 // no duplicate object at top level 1854 H4SDS sds = getSDS(HDFConstants.DFTAG_NDG, i, 1855 HObject.SEPARATOR, false); 1856 if (sds != null) { 1857 rootGroup.addToMemberList(sds); 1858 } 1859 } 1860 } // (HDFLibrary.SDfileinfo(sdid, argv)) 1861 1862 // get top level VData 1863 try { 1864 log.trace("getRootGroup(): first call to VSlone, get number of lone VDatas"); 1865 n = HDFLibrary.VSlone(fid, tmpN, 0); 1866 log.trace("getRootGroup(): number of lone Vdatas={}", n); 1867 refs = new int[n]; 1868 log.trace("getRootGroup(): second call to VSlone, get references of lone VDatas"); 1869 n = HDFLibrary.VSlone(fid, refs, n); 1870 } 1871 catch (HDFException ex) { 1872 log.debug("getRootGroup(): VSlone failure: ex"); 1873 n = 0; 1874 } 1875 1876 for (int i = 0; i < n; i++) { 1877 ref = refs[i]; 1878 1879 // no duplicate object at top level 1880 H4Vdata vdata = getVdata(HDFConstants.DFTAG_VS, ref, HObject.SEPARATOR, false); 1881 1882 if (vdata != null) { 1883 rootGroup.addToMemberList(vdata); 1884 } 1885 } 1886 1887 if (rootGroup != null) { 1888 // retrieve file annotation, GR and SDS globle attributes 1889 @SuppressWarnings("rawtypes") 1890 List attributeList = null; 1891 try { 1892 attributeList = rootGroup.getMetadata(); 1893 } 1894 catch (HDFException ex) { 1895 log.debug("getRootGroup(): getMetadata() failure: ", ex); 1896 } 1897 1898 if (attributeList != null) { 1899 try { 1900 getFileAnnotation(fid, attributeList); 1901 } 1902 catch (HDFException ex) { 1903 log.debug("getRootGroup(): getFileAnnotation() failure: ", ex); 1904 } 1905 try { 1906 getGRglobalAttribute(grid, attributeList); 1907 } 1908 catch (HDFException ex) { 1909 log.debug("getRootGroup(): getGRglobalAttribute() failure: ", ex); 1910 } 1911 try { 1912 getSDSglobalAttribute(sdid, attributeList); 1913 } 1914 catch (HDFException ex) { 1915 log.debug("getRootGroup(): getSDSglobalAttribute() failure: ", ex); 1916 } 1917 } 1918 } 1919 1920 return rootGroup; 1921 } 1922 1923 /** Get the object attached to a vgroup */ 1924 private HObject getAttachedObject(String path, String name) { 1925 if ((name == null) || (name.length() <= 0)) { 1926 log.debug("getAttachedObject(): name is null or invalid name length"); 1927 return null; 1928 } 1929 1930 // get top level VGroup 1931 String[] objName = { "" }; 1932 // check if it is an image 1933 int idx = -1; 1934 try { 1935 idx = HDFLibrary.GRnametoindex(grid, name); 1936 } 1937 catch (HDFException ex) { 1938 log.debug("getAttachedObject(): GRnametoindex failure: ", ex); 1939 idx = -1; 1940 } 1941 1942 if (idx >= 0) { 1943 H4GRImage img = getGRImage(HDFConstants.DFTAG_RIG, idx, HObject.SEPARATOR, false); 1944 return img; 1945 } 1946 1947 // get top level SDS 1948 try { 1949 idx = HDFLibrary.SDnametoindex(sdid, name); 1950 } 1951 catch (HDFException ex) { 1952 log.debug("getAttachedObject(): SDnametoindex failure: ", ex); 1953 idx = -1; 1954 } 1955 1956 if (idx >= 0) { 1957 H4SDS sds = getSDS(HDFConstants.DFTAG_NDG, idx, HObject.SEPARATOR, false); 1958 return sds; 1959 } 1960 1961 int ref = 0; 1962 try { 1963 ref = HDFLibrary.Vfind(fid, name); 1964 } 1965 catch (HDFException ex) { 1966 log.debug("getAttachedObject(): Vfind failure: ", ex); 1967 ref = -1; 1968 } 1969 1970 if (ref > 0) { 1971 long oid[] = { HDFConstants.DFTAG_VG, ref }; 1972 H4Group g = new H4Group(this, objName[0], path, null, oid); 1973 depth_first(g); 1974 return g; 1975 } 1976 1977 // get top level VData 1978 try { 1979 ref = HDFLibrary.VSfind(fid, name); 1980 } 1981 catch (HDFException ex) { 1982 log.debug("getAttachedObject(): VSfind failure: ", ex); 1983 ref = -1; 1984 } 1985 1986 if (ref > 0) { 1987 H4Vdata vdata = getVdata(HDFConstants.DFTAG_VS, ref, HObject.SEPARATOR, false); 1988 return vdata; 1989 } 1990 1991 log.debug("getAttachedObject(): Object not found"); 1992 return null; 1993 } 1994 1995 @Override 1996 public void setNewLibBounds(String lowStr, String highStr) throws Exception { 1997 // HDF4 does not have this feature 1998 } 1999 2000 @Override 2001 public int getIndexType(String strtype) { 2002 return -1; 2003 } 2004 2005 @Override 2006 public void setIndexType(int indexType) { 2007 // HDF4 does not have this feature 2008 } 2009 2010 @Override 2011 public int getIndexOrder(String strorder) { 2012 return -1; 2013 } 2014 2015 @Override 2016 public void setIndexOrder(int indexOrder) { 2017 // HDF4 does not have this feature 2018 } 2019 2020}