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