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 hdf.hdflib.HDFConstants; 021import hdf.hdflib.HDFException; 022import hdf.hdflib.HDFLibrary; 023 024import hdf.object.Attribute; 025import hdf.object.CompoundDS; 026import hdf.object.Dataset; 027import hdf.object.Datatype; 028import hdf.object.FileFormat; 029import hdf.object.Group; 030import hdf.object.MetaDataContainer; 031 032import hdf.object.h4.H4CompoundAttribute; 033 034/** 035 * H4Vdata describes a multi-dimension array of HDF4 vdata, inheriting CompoundDS. 036 * 037 * A vdata is like a table that consists of a collection of records whose values 038 * are stored in fixed-length fields. All records have the same structure and 039 * all values in each field have the same data type. Vdatas are uniquely 040 * identified by a name, a class, and a series of individual field names. 041 * 042 * <b>How to Select a Subset</b> 043 * 044 * Dataset defines APIs for reading, writing and subsetting a dataset. No function is 045 * defined to select a subset of a data array. The selection is done in an implicit way. 046 * Function calls to dimension information such as getSelectedDims() return an array 047 * of dimension values, which is a reference to the array in the dataset object. 048 * Changes of the array outside the dataset object directly change the values of 049 * the array in the dataset object. It is like pointers in C. 050 * 051 * The following is an example of how to make a subset. In the example, the dataset 052 * is a 4-dimension with size of [200][100][50][10], i.e. 053 * dims[0]=200; dims[1]=100; dims[2]=50; dims[3]=10; <br> 054 * We want to select every other data point in dims[1] and dims[2] 055 * <pre> 056 int rank = dataset.getRank(); // number of dimensions of the dataset 057 long[] dims = dataset.getDims(); // the dimension sizes of the dataset 058 long[] selected = dataset.getSelectedDims(); // the selected size of the dataet 059 long[] start = dataset.getStartDims(); // the offset of the selection 060 long[] stride = dataset.getStride(); // the stride of the dataset 061 int[] selectedIndex = dataset.getSelectedIndex(); // the selected dimensions for display 062 063 // select dim1 and dim2 as 2D data for display, and slice through dim0 064 selectedIndex[0] = 1; 065 selectedIndex[1] = 2; 066 selectedIndex[1] = 0; 067 068 // reset the selection arrays 069 for (int i=0; i<rank; i++) { 070 start[i] = 0; 071 selected[i] = 1; 072 stride[i] = 1; 073 } 074 075 // set stride to 2 on dim1 and dim2 so that every other data point is selected. 076 stride[1] = 2; 077 stride[2] = 2; 078 079 // set the selection size of dim1 and dim2 080 selected[1] = dims[1]/stride[1]; 081 selected[2] = dims[1]/stride[2]; 082 083 // when dataset.read() is called, the selection above will be used since 084 // the dimension arrays is passed by reference. Changes of these arrays 085 // outside the dataset object directly change the values of these array 086 // in the dataset object. 087 088 * </pre> 089 * 090 * @version 1.1 9/4/2007 091 * @author Peter X. Cao 092 */ 093public class H4Vdata extends CompoundDS implements MetaDataContainer 094{ 095 private static final long serialVersionUID = -5978700886955419959L; 096 097 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(H4Vdata.class); 098 099 /** 100 * The list of attributes of this data object. Members of the list are 101 * instance of H4CompoundAttribute. 102 */ 103 @SuppressWarnings("rawtypes") 104 private List attributeList; 105 106 /** 107 * Number of records of this Vdata table. 108 */ 109 private int numberOfRecords; 110 111 /** 112 * The data types of the members of the compound dataset. 113 */ 114 private long[] memberTIDs; 115 116 /** the number of attributes */ 117 private int nAttributes = -1; 118 119 120 /** 121 * Creates an H4Vdata object with specific name and path. 122 * 123 * @param theFile the HDF file. 124 * @param name the name of this H4Vdata. 125 * @param path the full path of this H4Vdata. 126 */ 127 public H4Vdata(FileFormat theFile, String name, String path) { 128 this(theFile, name, path, null); 129 } 130 131 /** 132 * Creates an H4Vdata object with specific name, path and oid. 133 * 134 * @param theFile the HDF file. 135 * @param name the name of this H4Vdata. 136 * @param path the full path of this H4Vdata. 137 * @param oid the unique identifier of this data object. 138 */ 139 @SuppressWarnings("deprecation") 140 public H4Vdata(FileFormat theFile, String name, String path, long[] oid) { 141 super (theFile, name, path, oid); 142 numberOfRecords = 0; 143 numberOfMembers = 0; 144 memberOrders = null; 145 } 146 147 /* 148 * (non-Javadoc) 149 * @see hdf.object.DataFormat#hasAttribute() 150 */ 151 @Override 152 public boolean hasAttribute() { 153 if (nAttributes < 0) { 154 long id = open(); 155 156 if (id >= 0) { 157 try { 158 nAttributes = HDFLibrary.VSnattrs(id); 159 } 160 catch (Exception ex) { 161 log.debug("hasAttribute() failure: ", ex); 162 nAttributes = 0; 163 } 164 165 log.trace("hasAttribute(): nAttributes={}", nAttributes); 166 167 close(id); 168 } 169 } 170 171 return (nAttributes > 0); 172 } 173 174 // implementing Dataset 175 /** 176 * Returns the datatype of the data object. 177 * 178 * @return the datatype of the data object. 179 */ 180 @Override 181 public Datatype getDatatype() { 182 if (!inited) 183 init(); 184 185 if (datatype == null) { 186 try { 187 datatype = new H4Datatype(-1); 188 } 189 catch (Exception ex) { 190 log.debug("getDatatype(): failed to create datatype: ", ex); 191 datatype = null; 192 } 193 } 194 195 return datatype; 196 } 197 198 /** 199 * Returns the fill values for the data object. 200 * 201 * @return the fill values for the data object. 202 */ 203 @Override 204 public Object getFillValue() { 205 return null; 206 } 207 208 // Implementing Dataset 209 @Override 210 public byte[] readBytes() throws HDFException { 211 byte[] theData = null; 212 213 if (!isInited()) 214 init(); 215 216 if (numberOfMembers <= 0) { 217 log.debug("readBytes(): VData contains no members"); 218 return null; // this Vdata does not have any filed 219 } 220 221 long id = open(); 222 if (id < 0) { 223 log.debug("readBytes(): Invalid VData ID"); 224 return null; 225 } 226 227 String allNames = memberNames[0]; 228 for (int i=0; i<numberOfMembers; i++) 229 allNames += ","+memberNames[i]; 230 231 try { 232 // moves the access pointer to the start position 233 HDFLibrary.VSseek(id, (int)startDims[0]); 234 // Specify the fields to be accessed 235 HDFLibrary.VSsetfields(id, allNames); 236 int[] recordSize = {0}; 237 HDFLibrary.VSQueryvsize(id, recordSize); 238 int size =recordSize[0] * (int)selectedDims[0]; 239 theData = new byte[size]; 240 HDFLibrary.VSread(id, theData, (int)selectedDims[0], HDFConstants.FULL_INTERLACE); 241 } 242 catch (Exception ex) { 243 log.debug("readBytes(): failure: ", ex); 244 } 245 finally { 246 close(id); 247 } 248 249 return theData; 250 } 251 252 // Implementing DataFormat 253 /** 254 * Reads the data from file. 255 * 256 * read() reads the data from file to a memory buffer and returns the memory 257 * buffer. The dataset object does not hold the memory buffer. To store the 258 * memory buffer in the dataset object, one must call getData(). 259 * 260 * By default, the whole dataset is read into memory. Users can also select 261 * a subset to read. Subsetting is done in an implicit way. 262 * 263 * @return the data read from file. 264 * 265 * @see #getData() 266 * 267 * @throws HDFException 268 * if object can not be read 269 * @throws OutOfMemoryError 270 * if memory is exhausted 271 */ 272 @SuppressWarnings({ "rawtypes", "unchecked", "deprecation" }) 273 @Override 274 public Object read() throws HDFException { 275 List list = null; 276 277 if (!isInited()) 278 init(); 279 280 if (numberOfMembers <= 0) { 281 log.debug("read(): VData contains no members"); 282 return null; // this Vdata does not have any filed 283 } 284 285 long id = open(); 286 if (id < 0) { 287 log.debug("read(): Invalid VData ID"); 288 return null; 289 } 290 291 list = new Vector(); 292 293 // assume external data files are located in the same directory as the main file. 294 HDFLibrary.HXsetdir(getFileFormat().getParent()); 295 296 Object member_data = null; 297 for (int i=0; i<numberOfMembers; i++) { 298 if (!isMemberSelected[i]) 299 continue; 300 301 try { 302 // moves the access pointer to the start position 303 HDFLibrary.VSseek(id, (int)startDims[0]); 304 // Specify the fields to be accessed 305 HDFLibrary.VSsetfields(id, memberNames[i]); 306 } 307 catch (HDFException ex) { 308 log.debug("read(): failure: ", ex); 309 isMemberSelected[i] = false; 310 continue; 311 } 312 313 int n = memberOrders[i]*(int)selectedDims[0]; 314 315 member_data = H4Datatype.allocateArray(memberTIDs[i], n); 316 317 log.trace("read(): index={} isMemberSelected[i]={} memberOrders[i]={} array size={}", i, isMemberSelected[i], memberOrders[i], n); 318 if (member_data == null) { 319 String[] nullValues = new String[n]; 320 for (int j=0; j<n; j++) 321 nullValues[j] = "*ERROR*"; 322 list.add(nullValues); 323 continue; 324 } 325 326 try { 327 HDFLibrary.VSread(id, member_data, (int)selectedDims[0], HDFConstants.FULL_INTERLACE); 328 if ((memberTIDs[i] == HDFConstants.DFNT_CHAR) || 329 (memberTIDs[i] == HDFConstants.DFNT_UCHAR8)) { 330 // convert characters to string 331 log.trace("read(): convert characters to string"); 332 member_data = Dataset.byteToString((byte[])member_data, memberOrders[i]); 333 try { 334 memberTypes[i] = new H4Datatype(Datatype.CLASS_STRING, memberOrders[i], Datatype.NATIVE, Datatype.NATIVE); 335 } 336 catch (Exception ex) { 337 log.debug("read(): failed to create datatype for member[{}]: ", i, ex); 338 memberTypes[i] = null; 339 } 340 memberOrders[i] = 1; //one String 341 } 342 else if (H4Datatype.isUnsigned(memberTIDs[i])) { 343 // convert unsigned integer to appropriate Java integer 344 log.trace("read(): convert unsigned integer to appropriate Java integer"); 345 member_data = Dataset.convertFromUnsignedC(member_data); 346 } 347 } 348 catch (HDFException ex) { 349 String[] nullValues = new String[n]; 350 for (int j=0; j<n; j++) 351 nullValues[j] = "*ERROR*"; 352 list.add(nullValues); 353 continue; 354 } 355 356 list.add(member_data); 357 } // (int i=0; i<numberOfMembers; i++) 358 359 close(id); 360 361 return list; 362 } 363 364 // Implementing DataFormat 365 /** 366 * Writes a memory buffer to the object in the file. 367 * 368 * @param buf 369 * the data to write 370 * 371 * @throws HDFException 372 * if data can not be written 373 */ 374 @Override 375 public void write(Object buf) throws HDFException { 376 //For writing to a vdata, VSsetfields can only be called once, to set 377 //up the fields in a vdata. Once the vdata fields are set, they may 378 //not be changed. Thus, to update some fields of a record after the 379 //first write, the user must read all the fields to a buffer, update 380 //the buffer, then write the entire record back to the vdata. 381 log.trace("write(): disabled"); 382 /* 383 if (buf == null || numberOfMembers <= 0 || !(buf instanceof List)) 384 return; // no data to write 385 386 List list = (List)buf; 387 Object member_data = null; 388 String member_name = null; 389 390 int vid = open(); 391 if (vid < 0) return; 392 393 int idx = 0; 394 for (int i=0; i<numberOfMembers; i++) { 395 if (!isMemberSelected[i]) 396 continue; 397 398 HDFLibrary.VSsetfields(vid, memberNames[i]); 399 400 try { 401 // Specify the fields to be accessed 402 403 // moves the access pointer to the start position 404 HDFLibrary.VSseek(vid, (int)startDims[0]); 405 } 406 catch (HDFException ex) { 407 continue; 408 } 409 410 member_data = list.get(idx++); 411 if (member_data == null) 412 continue; 413 414 if (memberTIDs[i] == HDFConstants.DFNT_CHAR || 415 memberTIDs[i] == HDFConstants.DFNT_UCHAR8) { 416 member_data = Dataset.stringToByte((String[])member_data, memberOrders[i]); 417 } 418 else if (H4Datatype.isUnsigned(memberTIDs[i])) { 419 // convert unsigned integer to appropriate Java integer 420 member_data = Dataset.convertToUnsignedC(member_data); 421 } 422 423 424 int interlace = HDFConstants.NO_INTERLACE; 425 try { 426 int write_num = HDFLibrary.VSwrite( 427 vid, member_data, (int)selectedDims[0], interlace); 428 } 429 catch (HDFException ex) { 430 log.debug("write():", ex); 431 } 432 } // (int i=0; i<numberOfMembers; i++) 433 434 close(vid); 435 */ 436 } 437 438 /** 439 * Converts the data values of this data object to appropriate Java integers if 440 * they are unsigned integers. 441 * 442 * @see hdf.object.Dataset#convertToUnsignedC(Object) 443 * @see hdf.object.Dataset#convertFromUnsignedC(Object, Object) 444 * 445 * @return the converted data buffer. 446 */ 447 @Override 448 public Object convertFromUnsignedC() { 449 throw new UnsupportedOperationException("H4Vdata:convertFromUnsignedC Unsupported operation."); 450 } 451 452 /** 453 * Converts Java integer data values of this data object back to unsigned C-type 454 * integer data if they are unsigned integers. 455 * 456 * @see hdf.object.Dataset#convertToUnsignedC(Object) 457 * @see hdf.object.Dataset#convertToUnsignedC(Object, Object) 458 * 459 * @return the converted data buffer. 460 */ 461 @Override 462 public Object convertToUnsignedC() { 463 throw new UnsupportedOperationException("H4Vdata:convertToUnsignedC Unsupported operation."); 464 } 465 466 // Implementing DataFormat 467 /** 468 * Retrieves the object's metadata, such as attributes, from the file. 469 * 470 * Metadata, such as attributes, is stored in a List. 471 * 472 * @return the list of metadata objects. 473 * 474 * @throws HDFException 475 * if the metadata can not be retrieved 476 */ 477 @Override 478 @SuppressWarnings({"rawtypes", "unchecked"}) 479 public List getMetadata() throws HDFException { 480 if (attributeList != null) { 481 log.trace("getMetdata(): attributeList != null"); 482 return attributeList; 483 } 484 485 long id = open(); 486 487 if (id < 0) { 488 log.debug("getMetadata(): Invalid VData ID"); 489 return attributeList; 490 } 491 492 int n = 0; 493 try { 494 n = HDFLibrary.VSnattrs(id); 495 496 if (n <= 0) { 497 log.debug("getMetadata(): VData number of attributes <= 0"); 498 return attributeList; 499 } 500 501 attributeList = new Vector(n, 5); 502 boolean b = false; 503 String[] attrName = new String[1]; 504 int[] attrInfo = new int[5]; 505 506 // _HDF_VDATA (or -1) to specify the vdata attribute 507 int nleft = n; 508 for (int j = -1; j < numberOfMembers; j++) { 509 for (int i = 0; i < nleft; i++) { 510 attrName[0] = ""; 511 512 try { 513 b = HDFLibrary.VSattrinfo(id, j, i, attrName, attrInfo); 514 // mask off the litend bit 515 attrInfo[0] = attrInfo[0] & (~HDFConstants.DFNT_LITEND); 516 } 517 catch (HDFException ex) { 518 log.debug("getMetadata(): attribute[{}] VSattrinfo failure: ", i, ex); 519 b = false; 520 ex.printStackTrace(); 521 } 522 523 if (!b || attrName[0].length() <= 0) 524 continue; 525 526 long[] attrDims = {attrInfo[1]}; 527 H4CompoundAttribute attr = new H4CompoundAttribute(this, attrName[0], new H4Datatype(attrInfo[0]), attrDims); 528 if (j >= 0) 529 attr.setProperty("field", memberNames[j]); 530 attributeList.add(attr); 531 532 Object buf = null; 533 try { 534 buf = H4Datatype.allocateArray(attrInfo[0], attrInfo[1]); 535 } 536 catch (OutOfMemoryError e) { 537 log.debug("getMetadata(): out of memory: ", e); 538 buf = null; 539 } 540 541 try { 542 HDFLibrary.VSgetattr(id, j, i, buf); 543 } 544 catch (HDFException ex) { 545 log.debug("getMetadata(): attribute[{}] VSgetattr failure: ", i, ex); 546 buf = null; 547 } 548 549 if (buf != null) { 550 if ((attrInfo[0] == HDFConstants.DFNT_CHAR) || 551 (attrInfo[0] == HDFConstants.DFNT_UCHAR8)) { 552 buf = Dataset.byteToString((byte[])buf, attrInfo[1]); 553 } 554 555 attr.setAttributeData(buf); 556 nleft--; 557 } 558 } // (int i=0; i<n; i++) 559 } // (int j=-1; j<numberOfMembers; j++) 560 } 561 catch (Exception ex) { 562 log.debug("getMetadata(): failure: ", ex); 563 } 564 finally { 565 close(id); 566 } 567 568 // todo: We shall also load attributes of fields 569 570 return attributeList; 571 } 572 573 // To do: Implementing DataFormat 574 /** 575 * Writes a specific piece of metadata (such as an attribute) into the file. 576 * 577 * If an HDF(4&5) attribute exists in the file, this method updates its 578 * value. If the attribute does not exist in the file, it creates the 579 * attribute in the file and attaches it to the object. It will fail to 580 * write a new attribute to the object where an attribute with the same name 581 * already exists. To update the value of an existing attribute in the file, 582 * one needs to get the instance of the attribute by getMetadata(), change 583 * its values, then use writeMetadata() to write the value. 584 * 585 * @param info 586 * the metadata to write. 587 * 588 * @throws Exception 589 * if the metadata can not be written 590 */ 591 @Override 592 @SuppressWarnings({"rawtypes", "unchecked"}) 593 public void writeMetadata(Object info) throws Exception { 594 // only attribute metadata is supported. 595 if (!(info instanceof Attribute)) { 596 log.debug("writeMetadata(): Object not an H4Attribute"); 597 return; 598 } 599 600 try { 601 getFileFormat().writeAttribute(this, (H4ScalarAttribute)info, true); 602 603 if (attributeList == null) 604 attributeList = new Vector(); 605 606 attributeList.add(info); 607 nAttributes = attributeList.size(); 608 } 609 catch (Exception ex) { 610 log.trace("writeMetadata(): failure: ", ex); 611 } 612 } 613 614 /** 615 * Deletes an existing piece of metadata from this object. 616 * 617 * @param info 618 * the metadata to delete. 619 * 620 * @throws HDFException 621 * if the metadata can not be removed 622 */ 623 @Override 624 public void removeMetadata(Object info) throws HDFException { 625 log.trace("removeMetadata(): disabled"); 626 } 627 628 /** 629 * Updates an existing piece of metadata attached to this object. 630 * 631 * @param info 632 * the metadata to update. 633 * 634 * @throws Exception 635 * if the metadata can not be updated 636 */ 637 @Override 638 public void updateMetadata(Object info) throws Exception { 639 log.trace("updateMetadata(): disabled"); 640 } 641 642 // Implementing DataFormat 643 @Override 644 public long open() { 645 // try to open with write permission 646 long vsid = -1; 647 try { 648 vsid = HDFLibrary.VSattach(getFID(), (int)oid[1], "w"); 649 } 650 catch (HDFException ex) { 651 log.debug("open(w): VSattach failure: ", ex); 652 vsid = -1; 653 } 654 655 // try to open with read-only permission 656 if (vsid < 0) { 657 try { 658 vsid = HDFLibrary.VSattach(getFID(), (int)oid[1], "r"); 659 } 660 catch (HDFException ex) { 661 log.debug("open(r): VSattach failure: ", ex); 662 vsid = -1; 663 } 664 log.debug("open(r): VSattach vsid: {}", vsid); 665 } 666 667 return vsid; 668 } 669 670 // Implementing DataFormat 671 @Override 672 public void close(long vsid) { 673 try { 674 HDFLibrary.VSdetach(vsid); 675 } 676 catch (Exception ex) { 677 log.debug("close(): VSdetach failure: ", ex); 678 } 679 } 680 681 /** 682 * Initializes the H4Vdata such as dimension sizes of this dataset. 683 */ 684 @Override 685 public void init() { 686 if (inited) { 687 log.trace("init(): Already initialized"); 688 return; // already called. Initialize only once 689 } 690 691 long id = open(); 692 if (id < 0) { 693 log.debug("init(): Invalid VData ID"); 694 return; 695 } 696 697 try { 698 numberOfMembers = HDFLibrary.VFnfields(id); 699 numberOfRecords = HDFLibrary.VSelts(id); 700 } 701 catch (HDFException ex) { 702 numberOfMembers = 0; 703 numberOfRecords = 0; 704 } 705 706 // Still need to get information if there is no record, see bug 1738 707 // if ((numberOfMembers <=0) || (numberOfRecords <= 0)) { 708 // // no table field is defined or no records 709 // close(id); 710 // return; 711 // } 712 713 // a Vdata table is an one dimension array of records. 714 // each record has the same fields 715 rank = 1; 716 dims = new long[1]; 717 dims[0] = numberOfRecords; 718 selectedDims = new long[1]; 719 selectedDims[0] = numberOfRecords; 720 selectedIndex[0] = 0; 721 startDims = new long[1]; 722 startDims[0] = 0; 723 724 memberNames = new String[numberOfMembers]; 725 memberTIDs = new long[numberOfMembers]; 726 memberTypes = new Datatype[numberOfMembers]; 727 memberOrders = new int[numberOfMembers]; 728 isMemberSelected = new boolean[numberOfMembers]; 729 730 try { 731 datatype = new H4Datatype(Datatype.CLASS_COMPOUND, -1, Datatype.NATIVE, Datatype.NATIVE); 732 } 733 catch (Exception ex) { 734 log.debug("init(): failed to create compound datatype for VData"); 735 datatype = null; 736 } 737 738 for (int i = 0; i < numberOfMembers; i++) { 739 isMemberSelected[i] = true; 740 try { 741 memberNames[i] = HDFLibrary.VFfieldname(id, i); 742 memberTIDs[i] = HDFLibrary.VFfieldtype(id, i); 743 try { 744 memberTypes[i] = new H4Datatype(memberTIDs[i]); 745 } 746 catch (Exception ex) { 747 log.debug("init(): failed to create datatype for member[{}]: ", i, ex); 748 memberTypes[i] = null; 749 } 750 // mask off the litend bit 751 memberTIDs[i] = memberTIDs[i] & (~HDFConstants.DFNT_LITEND); 752 memberOrders[i] = HDFLibrary.VFfieldorder(id, i); 753 log.trace("init():{}> isMemberSelected[i]={} memberNames[i]={} memberTIDs[i]={} memberOrders[i]={}", i, isMemberSelected[i], memberNames[i], memberTIDs[i], memberOrders[i]); 754 755 /* 756 * NOTE: An ugly workaround to get HDF4 "compound" datatypes to work correctly. 757 */ 758 if (datatype != null) { 759 datatype.getCompoundMemberNames().add(memberNames[i]); 760 datatype.getCompoundMemberTypes().add(memberTypes[i]); 761 } 762 } 763 catch (HDFException ex) { 764 log.debug("init(): member[{}]: ", i, ex); 765 continue; 766 } 767 } // (int i=0; i<numberOfMembers; i++) 768 769 inited = true; 770 771 close(id); 772 } 773 774 /** 775 * Returns the number of records. 776 * 777 * @return the number of records 778 */ 779 public int getRecordCount() { 780 return numberOfRecords; 781 } 782 783 /** 784 * Returns the number of fields. 785 * 786 * @return the number of fields 787 */ 788 public int getFieldCount() { 789 return numberOfMembers; 790 } 791 792 /** 793 * Returns the orders of fields 794 * 795 * @return the orders of fields 796 */ 797 public int[] getFieldOrders() { 798 return memberOrders; 799 } 800 801 //Implementing DataFormat 802 /** 803 * Retrieves the object's metadata, such as attributes, from the file. 804 * 805 * Metadata, such as attributes, is stored in a List. 806 * 807 * @param attrPropList 808 * the list of properties to get 809 * 810 * @return the list of metadata objects. 811 * 812 * @throws Exception 813 * if the metadata can not be retrieved 814 */ 815 @SuppressWarnings("rawtypes") 816 public List getMetadata(int... attrPropList) throws Exception { 817 throw new UnsupportedOperationException("getMetadata(int... attrPropList) is not supported"); 818 } 819 820 @Override 821 public Dataset copy(Group pgroup, String name, long[] dims, Object data) throws Exception { 822 throw new UnsupportedOperationException("Writing a vdata to a new dataset is not implemented."); 823 } 824}