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