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.util.List; 018import java.util.Vector; 019 020import org.slf4j.Logger; 021import org.slf4j.LoggerFactory; 022 023import hdf.hdflib.HDFChunkInfo; 024import hdf.hdflib.HDFCompInfo; 025import hdf.hdflib.HDFConstants; 026import hdf.hdflib.HDFDeflateCompInfo; 027import hdf.hdflib.HDFException; 028import hdf.hdflib.HDFJPEGCompInfo; 029import hdf.hdflib.HDFLibrary; 030import hdf.hdflib.HDFNBITCompInfo; 031import hdf.hdflib.HDFSKPHUFFCompInfo; 032import hdf.hdflib.HDFSZIPCompInfo; 033 034import hdf.object.Attribute; 035import hdf.object.Dataset; 036import hdf.object.Datatype; 037import hdf.object.FileFormat; 038import hdf.object.Group; 039import hdf.object.HObject; 040import hdf.object.ScalarDS; 041import hdf.object.MetaDataContainer; 042 043import hdf.object.h4.H4ScalarAttribute; 044 045/** 046 * H4SDS describes HDF4 Scientific Data Sets (SDS) and operations performed on 047 * the SDS. A SDS is a group of data structures used to store and describe 048 * multidimensional arrays of scientific data. 049 * 050 * The data contained in an SDS array has a data type associated with it. The 051 * standard data types supported by the SD interface include 32- and 64-bit 052 * floating-point numbers, 8-, 16- and 32-bit signed integers, 8-, 16- and 053 * 32-bit unsigned integers, and 8-bit characters. 054 * 055 * <b>How to Select a Subset</b> 056 * 057 * Dataset defines APIs for reading, writing and subsetting a dataset. No function 058 * is defined to select a subset of a data array. The selection is done in an implicit 059 * way. Function calls to dimension information such as getSelectedDims() return an array 060 * of dimension values, which is a reference to the array in the dataset object. 061 * Changes of the array outside the dataset object directly change the values of 062 * the array in the dataset object. It is like pointers in C. 063 * 064 * The following is an example of how to make a subset. In the example, the dataset 065 * is a 4-dimension with size of [200][100][50][10], i.e. 066 * dims[0]=200; dims[1]=100; dims[2]=50; dims[3]=10; <br> 067 * We want to select every other data point in dims[1] and dims[2] 068 * <pre> 069 int rank = dataset.getRank(); // number of dimensions of the dataset 070 long[] dims = dataset.getDims(); // the dimension sizes of the dataset 071 long[] selected = dataset.getSelectedDims(); // the selected size of the dataet 072 long[] start = dataset.getStartDims(); // the offset of the selection 073 long[] stride = dataset.getStride(); // the stride of the dataset 074 int[] selectedIndex = dataset.getSelectedIndex(); // the selected dimensions for display 075 076 // select dim1 and dim2 as 2D data for display,and slice through dim0 077 selectedIndex[0] = 1; 078 selectedIndex[1] = 2; 079 selectedIndex[1] = 0; 080 081 // reset the selection arrays 082 for (int i=0; i<rank; i++) { 083 start[i] = 0; 084 selected[i] = 1; 085 stride[i] = 1; 086 } 087 088 // set stride to 2 on dim1 and dim2 so that every other data point is selected. 089 stride[1] = 2; 090 stride[2] = 2; 091 092 // set the selection size of dim1 and dim2 093 selected[1] = dims[1]/stride[1]; 094 selected[2] = dims[1]/stride[2]; 095 096 // when dataset.read() is called, the slection above will be used since 097 // the dimension arrays is passed by reference. Changes of these arrays 098 // outside the dataset object directly change the values of these array 099 // in the dataset object. 100 101 * </pre> 102 * 103 * @version 1.1 9/4/2007 104 * @author Peter X. Cao 105 */ 106public class H4SDS extends ScalarDS implements MetaDataContainer 107{ 108 private static final long serialVersionUID = 2557157923292438696L; 109 110 private static final Logger log = LoggerFactory.getLogger(H4SDS.class); 111 112 /** tag for netCDF datasets. 113 * HDF4 library supports netCDF version 2.3.2. It only supports SDS APIs. 114 */ 115 // magic number for netCDF: "C(67) D(68) F(70) '\001'" 116 public static final int DFTAG_NDG_NETCDF = 67687001; 117 118 /** 119 * The list of attributes of this data object. Members of the list are 120 * instance of Attribute. 121 */ 122 @SuppressWarnings("rawtypes") 123 private List attributeList; 124 125 /** 126 * The SDS interface identifier obtained from SDstart(filename, access) 127 */ 128 private long sdid; 129 130 /** the datatype identifier */ 131 private long datatypeID = -1; 132 133 /** the number of attributes */ 134 private int nAttributes = -1; 135 136 /** 137 * Creates an H4SDS object with specific name and path. 138 * 139 * @param theFile 140 * the HDF file. 141 * @param name 142 * the name of this H4SDS. 143 * @param path 144 * the full path of this H4SDS. 145 */ 146 public H4SDS(FileFormat theFile, String name, String path) { 147 this(theFile, name, path, null); 148 } 149 150 /** 151 * Creates an H4SDS object with specific name, path and oid. 152 * 153 * @param theFile 154 * the HDF file. 155 * @param name 156 * the name of this H4SDS. 157 * @param path 158 * the full path of this H4SDS. 159 * @param oid 160 * the unique identifier of this data object. 161 */ 162 @SuppressWarnings("deprecation") 163 public H4SDS(FileFormat theFile, String name, String path, long[] oid) { 164 super(theFile, name, path, oid); 165 unsignedConverted = false; 166 sdid = ((H4File)getFileFormat()).getSDAccessID(); 167 } 168 169 /* 170 * (non-Javadoc) 171 * @see hdf.object.DataFormat#hasAttribute() 172 */ 173 @Override 174 public boolean hasAttribute() { 175 if (nAttributes < 0) { 176 sdid = ((H4File)getFileFormat()).getSDAccessID(); 177 178 long id = open(); 179 180 if (id >= 0) { 181 try { // retrieve attributes of the dataset 182 String[] objName = {""}; 183 int[] sdInfo = {0, 0, 0}; 184 int[] tmpDim = new int[HDFConstants.MAX_VAR_DIMS]; 185 HDFLibrary.SDgetinfo(id, objName, tmpDim, sdInfo); 186 nAttributes = sdInfo[2]; 187 } 188 catch (Exception ex) { 189 log.debug("hasAttribute(): failure: ", ex); 190 nAttributes=0; 191 } 192 193 log.trace("hasAttribute(): nAttributes={}", nAttributes); 194 195 close(id); 196 } 197 } 198 199 return (nAttributes>0); 200 } 201 202 // implementing Dataset 203 /** 204 * Returns the datatype of the data object. 205 * 206 * @return the datatype of the data object. 207 */ 208 @Override 209 public Datatype getDatatype() { 210 if (!inited) 211 init(); 212 213 if (datatype == null) { 214 try { 215 datatype = new H4Datatype(datatypeID); 216 } 217 catch (Exception ex) { 218 log.debug("getDatatype(): failed to create datatype: ", ex); 219 datatype = null; 220 } 221 } 222 223 return datatype; 224 } 225 226 // To do: Implementing Dataset 227 @Override 228 public Dataset copy(Group pgroup, String dname, long[] dims, Object buff) throws Exception { 229 log.trace("copy(): start: parentGroup={} datasetName={}", pgroup, dname); 230 231 Dataset dataset = null; 232 long srcdid = -1; 233 long dstdid = -1; 234 long tid = -1; 235 int size = 1; 236 int theRank = 2; 237 String path = null; 238 int[] count = null; 239 int[] start = null; 240 241 if (pgroup == null) { 242 log.debug("copy(): Parent group is null"); 243 return null; 244 } 245 246 if (dname == null) 247 dname = getName(); 248 249 if (pgroup.isRoot()) 250 path = HObject.SEPARATOR; 251 else 252 path = pgroup.getPath()+pgroup.getName()+HObject.SEPARATOR; 253 log.trace("copy(): path={}", path); 254 255 srcdid = open(); 256 if (srcdid < 0) { 257 log.debug("copy(): Invalid source SDID"); 258 return null; 259 } 260 261 if (dims == null) { 262 if (!isInited()) 263 init(); 264 265 theRank = getRank(); 266 267 dims = getDims(); 268 } 269 else { 270 theRank = dims.length; 271 } 272 273 start = new int[theRank]; 274 count = new int[theRank]; 275 for (int i=0; i<theRank; i++) { 276 start[i] = 0; 277 count[i] = (int)dims[i]; 278 size *= count[i]; 279 } 280 log.trace("copy(): theRank={} with size={}", theRank, size); 281 282 // create the new dataset and attach it to the parent group 283 tid = datatypeID; 284 dstdid = HDFLibrary.SDcreate(((H4File)pgroup.getFileFormat()).getSDAccessID(), dname, tid, theRank, count); 285 if (dstdid < 0) { 286 log.debug("copy(): Invalid dest SDID"); 287 return null; 288 } 289 290 int ref = HDFLibrary.SDidtoref(dstdid); 291 if (!pgroup.isRoot()) { 292 long vgid = pgroup.open(); 293 HDFLibrary.Vaddtagref(vgid, HDFConstants.DFTAG_NDG, ref); 294 pgroup.close(vgid); 295 } 296 297 // copy attributes from one object to the new object 298 log.trace("copy(): copy attributes"); 299 copyAttribute(srcdid, dstdid); 300 301 // read data from the source dataset 302 log.trace("copy(): read data from the source dataset"); 303 if (buff == null) { 304 buff = new byte[size * HDFLibrary.DFKNTsize(tid)]; 305 HDFLibrary.SDreaddata(srcdid, start, null, count, buff); 306 } 307 308 // write the data into the destination dataset 309 log.trace("copy(): write the data into the destination dataset"); 310 HDFLibrary.SDwritedata(dstdid, start, null, count, buff); 311 312 long[] oid = {HDFConstants.DFTAG_NDG, ref}; 313 dataset = new H4SDS(pgroup.getFileFormat(), dname, path, oid); 314 315 pgroup.addToMemberList(dataset); 316 317 close(srcdid); 318 319 try { 320 HDFLibrary.SDendaccess(dstdid); 321 } 322 catch (HDFException ex) { 323 log.debug("copy(): SDendaccess failure: ", ex); 324 } 325 326 return dataset; 327 } 328 329 // Implementing Dataset 330 @Override 331 public byte[] readBytes() throws HDFException { 332 byte[] theData = null; 333 334 if (!isInited()) 335 init(); 336 337 long id = open(); 338 if (id < 0) { 339 log.debug("readBytes(): Invalid SDID"); 340 return null; 341 } 342 343 int datasize = 1; 344 int[] select = new int[rank]; 345 int[] start = new int[rank]; 346 for (int i=0; i<rank; i++) { 347 datasize *= (int)selectedDims[i]; 348 select[i] = (int)selectedDims[i]; 349 start[i] = (int)startDims[i]; 350 } 351 352 int[] stride = null; 353 if (selectedStride != null) { 354 stride = new int[rank]; 355 for (int i=0; i<rank; i++) { 356 stride[i] = (int)selectedStride[i]; 357 } 358 } 359 360 try { 361 int size = HDFLibrary.DFKNTsize(datatypeID)*datasize; 362 theData = new byte[size]; 363 HDFLibrary.SDreaddata(id, start, stride, select, theData); 364 } 365 catch (Exception ex) { 366 log.debug("readBytes(): failure: ", ex); 367 } 368 finally { 369 close(id); 370 } 371 372 return theData; 373 } 374 375 // Implementing DataFormat 376 /** 377 * Reads the data from file. 378 * 379 * read() reads the data from file to a memory buffer and returns the memory 380 * buffer. The dataset object does not hold the memory buffer. To store the 381 * memory buffer in the dataset object, one must call getData(). 382 * 383 * By default, the whole dataset is read into memory. Users can also select 384 * a subset to read. Subsetting is done in an implicit way. 385 * 386 * @return the data read from file. 387 * 388 * @see #getData() 389 * 390 * @throws HDFException 391 * if object can not be read 392 * @throws OutOfMemoryError 393 * if memory is exhausted 394 */ 395 @Override 396 public Object read() throws HDFException, OutOfMemoryError { 397 Object theData = null; 398 399 if (!isInited()) 400 init(); 401 402 long id = open(); 403 if (id < 0) { 404 log.debug("read(): Invalid SDID"); 405 return null; 406 } 407 408 int datasize = 1; 409 int[] select = new int[rank]; 410 int[] start = new int[rank]; 411 for (int i=0; i<rank; i++) { 412 datasize *= (int)selectedDims[i]; 413 select[i] = (int)selectedDims[i]; 414 start[i] = (int)startDims[i]; 415 } 416 417 int[] stride = null; 418 if (selectedStride != null) { 419 stride = new int[rank]; 420 for (int i=0; i<rank; i++) { 421 stride[i] = (int)selectedStride[i]; 422 } 423 } 424 425 try { 426 theData = H4Datatype.allocateArray(datatypeID, datasize); 427 428 if (theData != null) { 429 // assume external data files are located in the same directory as the main file. 430 HDFLibrary.HXsetdir(getFileFormat().getParent()); 431 432 HDFLibrary.SDreaddata(id, start, stride, select, theData); 433 434 if (isText) 435 theData = byteToString((byte[])theData, select[0]); 436 } 437 } 438 catch (Exception ex) { 439 log.debug("read(): failure: ", ex); 440 } 441 finally { 442 close(id); 443 } 444 445 if (fillValue==null && isImageDisplay) { 446 try { 447 getMetadata(); 448 } // need to set fillValue for images 449 catch (Exception ex) { 450 log.debug("read(): getMetadata failure: ", ex); 451 } 452 } 453 454 if ((rank > 1) && (selectedIndex[0] > selectedIndex[1])) 455 isDefaultImageOrder = false; 456 else 457 isDefaultImageOrder = true; 458 459 log.trace("read(): isDefaultImageOrder={}", isDefaultImageOrder); 460 return theData; 461 } 462 463 // Implementing DataFormat 464 /** 465 * Writes a memory buffer to the object in the file. 466 * 467 * @param buf 468 * the data to write 469 * 470 * @throws HDFException 471 * if data can not be written 472 */ 473 @SuppressWarnings("deprecation") 474 @Override 475 public void write(Object buf) throws HDFException { 476 if (buf == null) { 477 log.debug("write(): Object is null"); 478 return; 479 } 480 481 long id = open(); 482 if (id < 0) { 483 log.debug("write(): Invalid SDID"); 484 return; 485 } 486 487 int[] select = new int[rank]; 488 int[] start = new int[rank]; 489 for (int i=0; i<rank; i++) { 490 select[i] = (int)selectedDims[i]; 491 start[i] = (int)startDims[i]; 492 } 493 494 int[] stride = null; 495 if (selectedStride != null) { 496 stride = new int[rank]; 497 for (int i=0; i<rank; i++) { 498 stride[i] = (int)selectedStride[i]; 499 } 500 } 501 502 Object tmpData = buf; 503 try { 504 if (getDatatype().isUnsigned() && unsignedConverted) 505 tmpData = convertToUnsignedC(buf); 506 // assume external data files are located in the same directory as the main file. 507 HDFLibrary.HXsetdir(getFileFormat().getParent()); 508 509 HDFLibrary.SDwritedata(id, start, stride, select, tmpData); 510 } 511 catch (Exception ex) { 512 log.debug("write(): failure: ", ex); 513 } 514 finally { 515 tmpData = null; 516 close(id); 517 } 518 } 519 520 // Implementing DataFormat 521 /** 522 * Retrieves the object's metadata, such as attributes, from the file. 523 * 524 * Metadata, such as attributes, is stored in a List. 525 * 526 * @return the list of metadata objects. 527 * 528 * @throws HDFException 529 * if the metadata can not be retrieved 530 */ 531 @Override 532 @SuppressWarnings({"rawtypes", "unchecked"}) 533 public List getMetadata() throws HDFException { 534 if (attributeList != null) { 535 log.trace("getMetdata(): attributeList != null"); 536 return attributeList; 537 } 538 539 long id = open(); 540 String[] objName = {""}; 541 int[] sdInfo = {0, 0, 0}; 542 try { 543 // retrieve attributes of the dataset 544 int[] tmpDim = new int[HDFConstants.MAX_VAR_DIMS]; 545 HDFLibrary.SDgetinfo(id, objName, tmpDim, sdInfo); 546 int n = sdInfo[2]; 547 548 if ((attributeList == null) && (n>0)) 549 attributeList = new Vector(n, 5); 550 551 boolean b = false; 552 String[] attrName = new String[1]; 553 int[] attrInfo = {0, 0}; 554 for (int i=0; i<n; i++) { 555 attrName[0] = ""; 556 try { 557 b = HDFLibrary.SDattrinfo(id, i, attrName, attrInfo); 558 // mask off the litend bit 559 attrInfo[0] = attrInfo[0] & (~HDFConstants.DFNT_LITEND); 560 } 561 catch (HDFException ex) { 562 log.debug("getMetadata(): attribute[{}] SDattrinfo failure: ", i, ex); 563 b = false; 564 } 565 566 if (!b) 567 continue; 568 569 long[] attrDims = {attrInfo[1]}; 570 H4ScalarAttribute attr = new H4ScalarAttribute(this, attrName[0], new H4Datatype(attrInfo[0]), attrDims); 571 attributeList.add(attr); 572 573 Object buf = null; 574 try { 575 buf = H4Datatype.allocateArray(attrInfo[0], attrInfo[1]); 576 } 577 catch (OutOfMemoryError e) { 578 log.debug("getMetadata(): out of memory: ", e); 579 buf = null; 580 } 581 582 try { 583 HDFLibrary.SDreadattr(id, i, buf); 584 } 585 catch (HDFException ex) { 586 log.debug("getMetadata(): attribute[{}] SDreadattr failure: ", i, ex); 587 buf = null; 588 } 589 590 if (buf != null) { 591 if ((attrInfo[0] == HDFConstants.DFNT_CHAR) || 592 (attrInfo[0] == HDFConstants.DFNT_UCHAR8)) { 593 buf = Dataset.byteToString((byte[])buf, attrInfo[1]); 594 } 595 else if (attrName[0].equalsIgnoreCase("fillValue") || 596 attrName[0].equalsIgnoreCase("_fillValue")) { 597 fillValue = buf; 598 } 599 600 attr.setAttributeData(buf); 601 } 602 603 } // (int i=0; i<n; i++) 604 605 // retrieve attribute of dimension 606 // BUG !! HDFLibrary.SDgetdimstrs(dimID, argv, 80) does not return anything 607 /** 608 * for (int i=0; i< rank; i++) { int dimID = HDFLibrary.SDgetdimid(id, i); String[] argv = {" ", " 609 * ", " "}; HDFLibrary.SDgetdimstrs(dimID, argv, 80); } 610 */ 611 } 612 catch (Exception ex) { 613 log.debug("getMetadata(): failure: ", ex); 614 } 615 finally { 616 close(id); 617 } 618 619 return attributeList; 620 } 621 622 // To do: implementing DataFormat 623 /** 624 * Writes a specific piece of metadata (such as an attribute) into the file. 625 * 626 * If an HDF(4&5) attribute exists in the file, this method updates its 627 * value. If the attribute does not exist in the file, it creates the 628 * attribute in the file and attaches it to the object. It will fail to 629 * write a new attribute to the object where an attribute with the same name 630 * already exists. To update the value of an existing attribute in the file, 631 * one needs to get the instance of the attribute by getMetadata(), change 632 * its values, then use writeMetadata() to write the value. 633 * 634 * @param info 635 * the metadata to write. 636 * 637 * @throws Exception 638 * if the metadata can not be written 639 */ 640 @Override 641 @SuppressWarnings({"rawtypes", "unchecked"}) 642 public void writeMetadata(Object info) throws Exception { 643 // only attribute metadata is supported. 644 if (!(info instanceof Attribute)) { 645 log.debug("writeMetadata(): Object not an H4ScalarAttribute"); 646 return; 647 } 648 649 try { 650 getFileFormat().writeAttribute(this, (H4ScalarAttribute)info, true); 651 652 if (attributeList == null) 653 attributeList = new Vector(); 654 655 attributeList.add(info); 656 nAttributes = attributeList.size(); 657 } 658 catch (Exception ex) { 659 log.trace("writeMetadata(): failure: ", ex); 660 } 661 } 662 663 /** 664 * Deletes an existing piece of metadata from this object. 665 * 666 * @param info 667 * the metadata to delete. 668 * 669 * @throws HDFException 670 * if the metadata can not be removed 671 */ 672 @Override 673 public void removeMetadata(Object info) throws HDFException { 674 log.trace("removeMetadata(): disabled"); 675 } 676 677 /** 678 * Updates an existing piece of metadata attached to this object. 679 * 680 * @param info 681 * the metadata to update. 682 * 683 * @throws Exception 684 * if the metadata can not be updated 685 */ 686 @Override 687 public void updateMetadata(Object info) throws Exception { 688 log.trace("updateMetadata(): disabled"); 689 } 690 691 // Implementing HObject 692 @Override 693 public long open() { 694 long id=-1; 695 696 try { 697 int index = 0; 698 int tag = (int)oid[0]; 699 700 log.trace("open(): tag={}", tag); 701 if (tag == H4SDS.DFTAG_NDG_NETCDF) 702 index = (int)oid[1]; //HDFLibrary.SDidtoref(id) fails for netCDF 703 else 704 index = HDFLibrary.SDreftoindex(sdid, (int)oid[1]); 705 706 id = HDFLibrary.SDselect(sdid,index); 707 } 708 catch (HDFException ex) { 709 log.debug("open(): failure: ", ex); 710 id = -1; 711 } 712 713 return id; 714 } 715 716 // Implementing HObject 717 @Override 718 public void close(long id) { 719 try { 720 HDFLibrary.SDendaccess(id); 721 } 722 catch (HDFException ex) { 723 log.debug("close(): failure: ", ex); 724 } 725 } 726 727 /** 728 * Initializes the H4SDS such as dimension size of this dataset. 729 */ 730 @SuppressWarnings("deprecation") 731 @Override 732 public void init() { 733 if (inited) { 734 log.trace("init(): Already initialized"); 735 return; // already called. Initialize only once 736 } 737 738 long id = open(); 739 String[] objName = {""}; 740 String[] dimName = {""}; 741 int[] dimInfo = {0, 0, 0}; 742 int[] sdInfo = {0, 0, 0}; 743 boolean isUnlimited = false; 744 745 int[] idims = new int[HDFConstants.MAX_VAR_DIMS]; 746 try { 747 HDFLibrary.SDgetinfo(id, objName, idims, sdInfo); 748 // mask off the litend bit 749 sdInfo[1] = sdInfo[1] & (~HDFConstants.DFNT_LITEND); 750 nAttributes = sdInfo[2]; 751 rank = sdInfo[0]; 752 753 if (rank <= 0) { 754 rank = 1; 755 idims[0] = 1; 756 } 757 758 isUnlimited = HDFLibrary.SDisrecord(id); 759 log.trace("init(): isUnlimited={}", isUnlimited); 760 761 datatypeID = sdInfo[1]; 762 isText = ((datatypeID == HDFConstants.DFNT_CHAR) || (datatypeID == HDFConstants.DFNT_UCHAR8)); 763 764 // get the dimension names 765 try { 766 dimNames = new String[rank]; 767 for (int i=0; i<rank; i++) { 768 long dimid = HDFLibrary.SDgetdimid(id, i); 769 HDFLibrary.SDdiminfo(dimid, dimName, dimInfo); 770 dimNames[i] = dimName[0]; 771 } 772 } 773 catch (Exception ex) { 774 log.debug("init(): get the dimension names: ", ex); 775 } 776 777 // get compression information 778 try { 779 HDFCompInfo compInfo = new HDFCompInfo(); 780 HDFLibrary.SDgetcompinfo(id, compInfo); 781 782 compression.setLength(0); 783 784 if (compInfo.ctype == HDFConstants.COMP_CODE_DEFLATE) { 785 HDFDeflateCompInfo comp = new HDFDeflateCompInfo(); 786 HDFLibrary.SDgetcompinfo(id, comp); 787 compression.append("GZIP(level=").append(comp.level).append(")"); 788 } 789 else if (compInfo.ctype == HDFConstants.COMP_CODE_SZIP) { 790 HDFSZIPCompInfo comp = new HDFSZIPCompInfo(); 791 HDFLibrary.SDgetcompinfo(id, comp); 792 compression.append("SZIP(bits_per_pixel=").append(comp.bits_per_pixel).append(",options_mask=") 793 .append(comp.options_mask).append(",pixels=").append(comp.pixels).append(",pixels_per_block=") 794 .append(comp.pixels_per_block).append(",pixels_per_scanline=").append(comp.pixels_per_scanline).append(")"); 795 } 796 else if (compInfo.ctype == HDFConstants.COMP_CODE_JPEG) { 797 HDFJPEGCompInfo comp = new HDFJPEGCompInfo(); 798 HDFLibrary.SDgetcompinfo(id, comp); 799 compression.append("JPEG(quality=").append(comp.quality).append(",options_mask=") 800 .append(",force_baseline=").append(comp.force_baseline).append(")"); 801 } 802 else if (compInfo.ctype == HDFConstants.COMP_CODE_SKPHUFF) { 803 HDFSKPHUFFCompInfo comp = new HDFSKPHUFFCompInfo(); 804 HDFLibrary.SDgetcompinfo(id, comp); 805 compression.append("SKPHUFF(skp_size=").append(comp.skp_size).append(")"); 806 } 807 else if (compInfo.ctype == HDFConstants.COMP_CODE_RLE) { 808 compression.append("RLE"); 809 } 810 else if (compInfo.ctype == HDFConstants.COMP_CODE_NBIT) { 811 HDFNBITCompInfo comp = new HDFNBITCompInfo(); 812 HDFLibrary.SDgetcompinfo(id, comp); 813 compression.append("NBIT(nt=").append(comp.nt).append(",bit_len=").append(comp.bit_len) 814 .append(",ctype=").append(comp.ctype).append(",fill_one=").append(comp.fill_one) 815 .append(",sign_ext=").append(comp.sign_ext).append(",start_bit=").append(comp.start_bit).append(")"); 816 } 817 818 if (compression.length() == 0) 819 compression.append("NONE"); 820 } 821 catch (Exception ex) { 822 log.debug("init(): get compression information failure: ", ex); 823 } 824 825 // get chunk information 826 try { 827 HDFChunkInfo chunkInfo = new HDFChunkInfo(); 828 int[] cflag = {HDFConstants.HDF_NONE}; 829 830 try { 831 HDFLibrary.SDgetchunkinfo(id, chunkInfo, cflag); 832 } 833 catch (Exception ex) { 834 ex.printStackTrace(); 835 } 836 837 storageLayout.setLength(0); 838 839 if (cflag[0] == HDFConstants.HDF_NONE) { 840 chunkSize = null; 841 storageLayout.append("NONE"); 842 } 843 else { 844 chunkSize = new long[rank]; 845 for (int i=0; i<rank; i++) 846 chunkSize[i] = chunkInfo.chunk_lengths[i]; 847 storageLayout.append("CHUNKED: ").append(chunkSize[0]); 848 for (int i = 1; i < rank; i++) 849 storageLayout.append(" X ").append(chunkSize[i]); 850 } 851 } 852 catch (Exception ex) { 853 log.debug("init(): get chunk information failure: ", ex); 854 } 855 856 inited = true; 857 } 858 catch (HDFException ex) { 859 log.debug("init(): failure: ", ex); 860 } 861 finally { 862 close(id); 863 } 864 865 dims = new long[rank]; 866 maxDims = new long[rank]; 867 startDims = new long[rank]; 868 selectedDims = new long[rank]; 869 870 for (int i=0; i<rank; i++) { 871 startDims[i] = 0; 872 selectedDims[i] = 1; 873 dims[i] = maxDims[i] = idims[i]; 874 } 875 876 if (isUnlimited) 877 maxDims[0] = -1; 878 879 selectedIndex[0] = 0; 880 selectedIndex[1] = 1; 881 selectedIndex[2] = 2; 882 883 // select only two dimension a time, 884 if (rank == 1) 885 selectedDims[0] = dims[0]; 886 887 if (rank > 1) { 888 selectedDims[0] = dims[0]; 889 if (isText) 890 selectedDims[1] = 1; 891 else 892 selectedDims[1] = dims[1]; 893 } 894 } 895 896 /** 897 * Creates a new dataset. 898 * 899 * @param name the name of the dataset to create. 900 * @param pgroup the parent group of the new dataset. 901 * @param type the datatype of the dataset. 902 * @param dims the dimension size of the dataset. 903 * @param maxdims the max dimension size of the dataset. 904 * @param chunks the chunk size of the dataset. 905 * @param gzip the level of the gzip compression. 906 * @param fillValue the default value. 907 * @param data the array of data values. 908 * 909 * @return the new dataset if successful. Otherwise returns null. 910 * 911 * @throws Exception if the dataset can not be created 912 */ 913 public static H4SDS create(String name, Group pgroup, Datatype type, long[] dims, long[] maxdims, 914 long[] chunks, int gzip, Object fillValue, Object data) throws Exception { 915 H4SDS dataset = null; 916 if ((pgroup == null) || (name == null)|| (dims == null)) { 917 log.trace("create(): Parent group, name or dims is null"); 918 return null; 919 } 920 921 H4File file = (H4File)pgroup.getFileFormat(); 922 923 if (file == null) { 924 log.trace("create(): Parent group FileFormat is null"); 925 return null; 926 } 927 928 String path = HObject.SEPARATOR; 929 if (!pgroup.isRoot()) 930 path = pgroup.getPath()+pgroup.getName()+HObject.SEPARATOR; 931 // prepare the dataspace 932 int rank = dims.length; 933 int[] idims = new int[rank]; 934 int[] start = new int[rank]; 935 for (int i=0; i<rank; i++) { 936 idims[i] = (int)dims[i]; 937 start[i] = 0; 938 } 939 940 // only the first element of the SDcreate parameter dim_sizes (i.e., 941 // the dimension of the lowest rank or the slowest-changing dimension) 942 // can be assigned the value SD_UNLIMITED (or 0) to make the first 943 // dimension unlimited. 944 if ((maxdims != null) && (maxdims[0]<=0)) 945 idims[0] = 0; // set to unlimited dimension. 946 947 int[] ichunks = null; 948 if (chunks != null) { 949 ichunks = new int[rank]; 950 for (int i=0; i<rank; i++) 951 ichunks[i] = (int)chunks[i]; 952 } 953 954 // unlimited cannot be used with chunking or compression for HDF 4.2.6 or earlier. 955 if (idims[0] == 0 && (ichunks != null || gzip>0)) { 956 log.debug("create(): Unlimited cannot be used with chunking or compression"); 957 throw new HDFException("Unlimited cannot be used with chunking or compression"); 958 } 959 960 long sdid = (file).getSDAccessID(); 961 long sdsid = -1; 962 long vgid = -1; 963 long tid = type.createNative(); 964 965 if(tid >= 0) { 966 try { 967 sdsid = HDFLibrary.SDcreate(sdid, name, tid, rank, idims); 968 // set fill value to zero. 969 int vsize = HDFLibrary.DFKNTsize(tid); 970 byte[] fill = new byte[vsize]; 971 for (int i=0; i<vsize; i++) 972 fill[i] = 0; 973 HDFLibrary.SDsetfillvalue(sdsid, fill); 974 975 // when we create a new dataset with unlimited dimension, 976 // we have to write some data into the dataset or otherwise 977 // the current dataset has zero dimensin size. 978 } 979 catch (Exception ex) { 980 log.debug("create(): failure: ", ex); 981 throw (ex); 982 } 983 } 984 985 if (sdsid < 0) { 986 log.debug("create(): Dataset creation failed"); 987 throw (new HDFException("Unable to create the new dataset.")); 988 } 989 990 HDFDeflateCompInfo compInfo = null; 991 if (gzip > 0) { 992 // set compression 993 compInfo = new HDFDeflateCompInfo(); 994 compInfo.level = gzip; 995 if (chunks == null) 996 HDFLibrary.SDsetcompress(sdsid, HDFConstants.COMP_CODE_DEFLATE, compInfo); 997 } 998 999 if (chunks != null) { 1000 // set chunk 1001 HDFChunkInfo chunkInfo = new HDFChunkInfo(ichunks); 1002 int flag = HDFConstants.HDF_CHUNK; 1003 1004 if (gzip > 0) { 1005 flag = HDFConstants.HDF_CHUNK | HDFConstants.HDF_COMP; 1006 chunkInfo = new HDFChunkInfo(ichunks, HDFConstants.COMP_CODE_DEFLATE, compInfo); 1007 } 1008 1009 try { 1010 HDFLibrary.SDsetchunk (sdsid, chunkInfo, flag); 1011 } 1012 catch (Exception err) { 1013 log.debug("create(): SDsetchunk failure: ", err); 1014 err.printStackTrace(); 1015 throw new HDFException("SDsetchunk failed."); 1016 } 1017 } 1018 1019 if ((sdsid > 0) && (data != null)) 1020 HDFLibrary.SDwritedata(sdsid, start, null, idims, data); 1021 1022 int ref = HDFLibrary.SDidtoref(sdsid); 1023 1024 if (!pgroup.isRoot()) { 1025 // add the dataset to the parent group 1026 vgid = pgroup.open(); 1027 if (vgid < 0) { 1028 if (sdsid > 0) 1029 HDFLibrary.SDendaccess(sdsid); 1030 log.debug("create(): Invalid Parent Group ID"); 1031 throw (new HDFException("Unable to open the parent group.")); 1032 } 1033 1034 HDFLibrary.Vaddtagref(vgid, HDFConstants.DFTAG_NDG, ref); 1035 1036 pgroup.close(vgid); 1037 } 1038 1039 try { 1040 if (sdsid > 0) 1041 HDFLibrary.SDendaccess(sdsid); 1042 } 1043 catch (Exception ex) { 1044 log.debug("create(): SDendaccess failure: ", ex); 1045 } 1046 1047 long[] oid = {HDFConstants.DFTAG_NDG, ref}; 1048 dataset = new H4SDS(file, name, path, oid); 1049 1050 if (dataset != null) 1051 pgroup.addToMemberList(dataset); 1052 1053 return dataset; 1054 } 1055 1056 /** 1057 * Creates a new dataset. 1058 * 1059 * @param name the name of the dataset to create. 1060 * @param pgroup the parent group of the new dataset. 1061 * @param type the datatype of the dataset. 1062 * @param dims the dimension size of the dataset. 1063 * @param maxdims the max dimension size of the dataset. 1064 * @param chunks the chunk size of the dataset. 1065 * @param gzip the level of the gzip compression. 1066 * @param data the array of data values. 1067 * 1068 * @return the new dataset if successful. Otherwise returns null. 1069 * 1070 * @throws Exception if the dataset can not be created 1071 */ 1072 public static H4SDS create(String name, Group pgroup, Datatype type, 1073 long[] dims, long[] maxdims, long[] chunks, int gzip, Object data) throws Exception { 1074 return create(name, pgroup, type, dims, maxdims, chunks, gzip, null, data); 1075 } 1076 1077 /** 1078 * copy attributes from one SDS to another SDS 1079 */ 1080 private void copyAttribute(long srcdid, long dstdid) { 1081 log.trace("copyAttribute(): start: srcdid={} dstdid={}", srcdid, dstdid); 1082 try { 1083 String[] objName = {""}; 1084 int[] sdInfo = {0, 0, 0}; 1085 int[] tmpDim = new int[HDFConstants.MAX_VAR_DIMS]; 1086 HDFLibrary.SDgetinfo(srcdid, objName, tmpDim, sdInfo); 1087 int numberOfAttributes = sdInfo[2]; 1088 log.trace("copyAttribute(): numberOfAttributes={}", numberOfAttributes); 1089 1090 boolean b = false; 1091 String[] attrName = new String[1]; 1092 int[] attrInfo = {0, 0}; 1093 for (int i=0; i<numberOfAttributes; i++) { 1094 attrName[0] = ""; 1095 try { 1096 b = HDFLibrary.SDattrinfo(srcdid, i, attrName, attrInfo); 1097 } 1098 catch (HDFException ex) { 1099 log.debug("copyAttribute(): attribute[{}] SDattrinfo failure: ", i, ex); 1100 b = false; 1101 } 1102 1103 if (!b) 1104 continue; 1105 1106 // read attribute data from source dataset 1107 byte[] attrBuff = new byte[attrInfo[1] * HDFLibrary.DFKNTsize(attrInfo[0])]; 1108 try { 1109 HDFLibrary.SDreadattr(srcdid, i, attrBuff); 1110 } 1111 catch (HDFException ex) { 1112 log.debug("copyAttribute(): attribute[{}] SDreadattr failure: ", i, ex); 1113 attrBuff = null; 1114 } 1115 1116 if (attrBuff == null) { 1117 log.debug("copyAttribute(): attrBuff[{}] is null", i); 1118 continue; 1119 } 1120 1121 // attach attribute to the destination dataset 1122 HDFLibrary.SDsetattr(dstdid, attrName[0], attrInfo[0], attrInfo[1], attrBuff); 1123 } // (int i=0; i<numberOfAttributes; i++) 1124 } 1125 catch (Exception ex) { 1126 log.debug("copyAttribute(): failure: ", ex); 1127 } 1128 } 1129 1130 //Implementing DataFormat 1131 /** 1132 * Retrieves the object's metadata, such as attributes, from the file. 1133 * 1134 * Metadata, such as attributes, is stored in a List. 1135 * 1136 * @param attrPropList 1137 * the list of properties to get 1138 * 1139 * @return the list of metadata objects. 1140 * 1141 * @throws Exception 1142 * if the metadata can not be retrieved 1143 */ 1144 @SuppressWarnings("rawtypes") 1145 public List getMetadata(int... attrPropList) throws Exception { 1146 throw new UnsupportedOperationException("getMetadata(int... attrPropList) is not supported"); 1147 } 1148}