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; 016 017import java.lang.reflect.Array; 018import java.math.BigDecimal; 019import java.math.BigInteger; 020import java.text.DecimalFormat; 021import java.util.ArrayList; 022import java.util.Arrays; 023import java.util.Collection; 024import java.util.HashMap; 025import java.util.Iterator; 026import java.util.List; 027import java.util.Map; 028import java.util.Vector; 029 030/** 031 * The abstract class provides general APIs to create and manipulate dataset/attribute 032 * objects, and retrieve dataset/attribute properties, datatype and dimension sizes. 033 * 034 * This class provides two convenient functions, read()/write(), to read/write 035 * data values. Reading/writing data may take many library calls if we use the 036 * library APIs directly. The read() and write functions hide all the details of 037 * these calls from users. 038 * 039 * For more details on dataset and attributes, 040 * see <b> <a href="https://support.hdfgroup.org/HDF5/doc/UG/HDF5_Users_Guide-Responsive%20HTML5/index.html">HDF5 User's Guide</a> </b> 041 * 042 * @see hdf.object.ScalarDS 043 * @see hdf.object.CompoundDS 044 * 045 * @version 1.1 9/4/2007 046 * @author Peter X. Cao 047 */ 048public abstract class Dataset extends HObject implements DataFormat 049{ 050 private static final long serialVersionUID = -3360885430038261178L; 051 052 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Dataset.class); 053 054 /** 055 * The memory buffer that holds the raw data array of the dataset. 056 */ 057 protected transient Object data; 058 059 /** 060 * The type of space for the dataset. 061 */ 062 protected int space_type; 063 064 /** 065 * The number of dimensions of the dataset. 066 */ 067 protected int rank; 068 069 /** 070 * The current dimension sizes of the dataset 071 */ 072 protected long[] dims; 073 074 /** 075 * The max dimension sizes of the dataset 076 */ 077 protected long[] maxDims; 078 079 /** 080 * Array that contains the number of data points selected (for read/write) 081 * in each dimension. 082 * 083 * The selected size must be less than or equal to the current dimension size. 084 * A subset of a rectangle selection is defined by the starting position and 085 * selected sizes. 086 * 087 * For example, if a 4 X 5 dataset is as follows: 088 * 089 * <pre> 090 * 0, 1, 2, 3, 4 091 * 10, 11, 12, 13, 14 092 * 20, 21, 22, 23, 24 093 * 30, 31, 32, 33, 34 094 * long[] dims = {4, 5}; 095 * long[] startDims = {1, 2}; 096 * long[] selectedDims = {3, 3}; 097 * then the following subset is selected by the startDims and selectedDims above: 098 * 12, 13, 14 099 * 22, 23, 24 100 * 32, 33, 34 101 * </pre> 102 */ 103 protected long[] selectedDims; 104 105 /** 106 * The starting position of each dimension of a selected subset. With both 107 * the starting position and selected sizes, the subset of a rectangle 108 * selection is fully defined. 109 */ 110 protected long[] startDims; 111 112 /** 113 * Array that contains the indices of the dimensions selected for display. 114 * 115 * <B>selectedIndex[] is provided for two purposes:</B> 116 * <OL> 117 * <LI> 118 * selectedIndex[] is used to indicate the order of dimensions for display, 119 * i.e. selectedIndex[0] = row, selectedIndex[1] = column and 120 * selectedIndex[2] = depth. For example, for a four dimension dataset, if 121 * selectedIndex[] is {1, 2, 3}, then dim[1] is selected as row index, 122 * dim[2] is selected as column index and dim[3] is selected as depth index. 123 * <LI> 124 * selectedIndex[] is also used to select dimensions for display for 125 * datasets with three or more dimensions. We assume that applications such 126 * as HDFView can only display data up to three dimensions (a 2D 127 * spreadsheet/image with a third dimension that the 2D spreadsheet/image is 128 * cut from). For datasets with more than three dimensions, we need 129 * selectedIndex[] to store which three dimensions are chosen for display. 130 * For example, for a four dimension dataset, if selectedIndex[] = {1, 2, 3}, 131 * then dim[1] is selected as row index, dim[2] is selected as column index 132 * and dim[3] is selected as depth index. dim[0] is not selected. Its 133 * location is fixed at 0 by default. 134 * </OL> 135 */ 136 protected final int[] selectedIndex; 137 138 /** 139 * The number of elements to move from the start location in each dimension. 140 * For example, if selectedStride[0] = 2, every other data point is selected 141 * along dim[0]. 142 */ 143 protected long[] selectedStride; 144 145 /** 146 * The array of dimension sizes for a chunk. 147 */ 148 protected long[] chunkSize; 149 150 /** The compression information. */ 151 protected StringBuilder compression; 152 /** The compression information default prefix. */ 153 public static final String COMPRESSION_GZIP_TXT = "GZIP: level = "; 154 155 /** The filters information. */ 156 protected StringBuilder filters; 157 158 /** The storage layout information. */ 159 protected StringBuilder storageLayout; 160 161 /** The storage information. */ 162 protected StringBuilder storage; 163 164 /** The datatype object of the dataset. */ 165 protected Datatype datatype; 166 167 /** 168 * Array of strings that represent the dimension names. It is null if dimension names do not exist. 169 */ 170 protected String[] dimNames; 171 172 /** Flag to indicate if the byte[] array is converted to strings */ 173 protected boolean convertByteToString = true; 174 175 /** Flag to indicate if data values are loaded into memory. */ 176 protected boolean isDataLoaded = false; 177 178 /** Flag to indicate if this dataset has been initialized */ 179 protected boolean inited = false; 180 181 /** The number of data points in the memory buffer. */ 182 protected long nPoints = 1; 183 184 /** Flag to indicate if the data is a single scalar point */ 185 protected boolean isScalar; 186 187 /** True if this dataset is an image. */ 188 protected boolean isImage; 189 190 /** True if this dataset is ASCII text. */ 191 protected boolean isText; 192 193 /** 194 * The data buffer that contains the raw data directly reading from file 195 * (before any data conversion). 196 */ 197 protected transient Object originalBuf = null; 198 199 /** 200 * The array that holds the converted data of unsigned C-type integers. 201 * 202 * For example, Suppose that the original data is an array of unsigned 203 * 16-bit short integers. Since Java does not support unsigned integer, the 204 * data is converted to an array of 32-bit singed integer. In that case, the 205 * converted buffer is the array of 32-bit singed integer. 206 */ 207 protected transient Object convertedBuf = null; 208 209 /** 210 * Constructs a Dataset object with a given file, name and path. 211 * 212 * @param theFile 213 * the file that contains the dataset. 214 * @param dsName 215 * the name of the Dataset, e.g. "dset1". 216 * @param dsPath 217 * the full group path of this Dataset, e.g. "/arrays/". 218 */ 219 public Dataset(FileFormat theFile, String dsName, String dsPath) { 220 this(theFile, dsName, dsPath, null); 221 } 222 223 /** 224 * @deprecated Not for public use in the future. <br> 225 * Using {@link #Dataset(FileFormat, String, String)} 226 * 227 * @param theFile 228 * the file that contains the dataset. 229 * @param dsName 230 * the name of the Dataset, e.g. "dset1". 231 * @param dsPath 232 * the full group path of this Dataset, e.g. "/arrays/". 233 * @param oid 234 * the oid of this Dataset. 235 */ 236 @Deprecated 237 public Dataset(FileFormat theFile, String dsName, String dsPath, long[] oid) { 238 super(theFile, dsName, dsPath, oid); 239 log.trace("Dataset: start {}", dsName); 240 241 datatype = null; 242 rank = -1; 243 space_type = -1; 244 data = null; 245 dims = null; 246 maxDims = null; 247 selectedDims = null; 248 startDims = null; 249 selectedStride = null; 250 chunkSize = null; 251 compression = new StringBuilder("NONE"); 252 filters = new StringBuilder("NONE"); 253 storageLayout = new StringBuilder("NONE"); 254 storage = new StringBuilder("NONE"); 255 dimNames = null; 256 257 selectedIndex = new int[3]; 258 selectedIndex[0] = 0; 259 selectedIndex[1] = 1; 260 selectedIndex[2] = 2; 261 } 262 263 /** 264 * Clears memory held by the dataset, such as the data buffer. 265 */ 266 @SuppressWarnings("rawtypes") 267 public void clear() { 268 if (data != null) { 269 if (data instanceof List) 270 ((List) data).clear(); 271 data = null; 272 originalBuf = null; 273 convertedBuf = null; 274 } 275 isDataLoaded = false; 276 } 277 278 /** 279 * Returns the type of space for the dataset. 280 * 281 * @return the type of space for the dataset. 282 */ 283 @Override 284 public final int getSpaceType() { 285 return space_type; 286 } 287 288 /** 289 * Returns the rank (number of dimensions) of the dataset. 290 * 291 * @return the number of dimensions of the dataset. 292 */ 293 @Override 294 public final int getRank() { 295 return rank; 296 } 297 298 /** 299 * Returns the array that contains the dimension sizes of the dataset. 300 * 301 * @return the dimension sizes of the dataset. 302 */ 303 @Override 304 public final long[] getDims() { 305 return dims; 306 } 307 308 /** 309 * Returns the array that contains the max dimension sizes of the dataset. 310 * 311 * @return the max dimension sizes of the dataset. 312 */ 313 public final long[] getMaxDims() { 314 if (maxDims == null) 315 return dims; 316 317 return maxDims; 318 } 319 320 /** 321 * Returns the dimension sizes of the selected subset. 322 * 323 * The SelectedDims is the number of data points of the selected subset. 324 * Applications can use this array to change the size of selected subset. 325 * 326 * The selected size must be less than or equal to the current dimension size. 327 * Combined with the starting position, selected sizes and stride, the 328 * subset of a rectangle selection is fully defined. 329 * 330 * For example, if a 4 X 5 dataset is as follows: 331 * 332 * <pre> 333 * 0, 1, 2, 3, 4 334 * 10, 11, 12, 13, 14 335 * 20, 21, 22, 23, 24 336 * 30, 31, 32, 33, 34 337 * long[] dims = {4, 5}; 338 * long[] startDims = {1, 2}; 339 * long[] selectedDims = {3, 3}; 340 * long[] selectedStride = {1, 1}; 341 * then the following subset is selected by the startDims and selectedDims 342 * 12, 13, 14 343 * 22, 23, 24 344 * 32, 33, 34 345 * </pre> 346 * 347 * @return the dimension sizes of the selected subset. 348 */ 349 @Override 350 public final long[] getSelectedDims() { 351 return selectedDims; 352 } 353 354 /** 355 * Returns the starting position of a selected subset. 356 * 357 * Applications can use this array to change the starting position of a 358 * selection. Combined with the selected dimensions, selected sizes and 359 * stride, the subset of a rectangle selection is fully defined. 360 * 361 * For example, if a 4 X 5 dataset is as follows: 362 * 363 * <pre> 364 * 0, 1, 2, 3, 4 365 * 10, 11, 12, 13, 14 366 * 20, 21, 22, 23, 24 367 * 30, 31, 32, 33, 34 368 * long[] dims = {4, 5}; 369 * long[] startDims = {1, 2}; 370 * long[] selectedDims = {3, 3}; 371 * long[] selectedStride = {1, 1}; 372 * then the following subset is selected by the startDims and selectedDims 373 * 12, 13, 14 374 * 22, 23, 24 375 * 32, 33, 34 376 * </pre> 377 * 378 * @return the starting position of a selected subset. 379 */ 380 @Override 381 public final long[] getStartDims() { 382 return startDims; 383 } 384 385 /** 386 * Returns the selectedStride of the selected dataset. 387 * 388 * Applications can use this array to change how many elements to move in 389 * each dimension. 390 * 391 * Combined with the starting position and selected sizes, the subset of a 392 * rectangle selection is defined. 393 * 394 * For example, if a 4 X 5 dataset is as follows: 395 * 396 * <pre> 397 * 0, 1, 2, 3, 4 398 * 10, 11, 12, 13, 14 399 * 20, 21, 22, 23, 24 400 * 30, 31, 32, 33, 34 401 * long[] dims = {4, 5}; 402 * long[] startDims = {0, 0}; 403 * long[] selectedDims = {2, 2}; 404 * long[] selectedStride = {2, 3}; 405 * then the following subset is selected by the startDims and selectedDims 406 * 0, 3 407 * 20, 23 408 * </pre> 409 * 410 * @return the selectedStride of the selected dataset. 411 */ 412 @Override 413 public final long[] getStride() { 414 if (rank <= 0) 415 return null; 416 417 if (selectedStride == null) { 418 selectedStride = new long[rank]; 419 for (int i = 0; i < rank; i++) 420 selectedStride[i] = 1; 421 } 422 423 return selectedStride; 424 } 425 426 /** 427 * Sets the flag that indicates if a byte array is converted to a string 428 * array. 429 * 430 * In a string dataset, the raw data from file is stored in a byte array. By 431 * default, this byte array is converted to an array of strings. For a large 432 * dataset (e.g. more than one million strings), the conversion takes a long 433 * time and requires a lot of memory space to store the strings. In some 434 * applications, such a conversion can be delayed. For example, A GUI 435 * application may convert only the part of the strings that is visible to the 436 * users, not the entire data array. 437 * 438 * setConvertByteToString(boolean b) allows users to set the flag so that 439 * applications can choose to perform the byte-to-string conversion or not. 440 * If the flag is set to false, the getData() returns an array of byte 441 * instead of an array of strings. 442 * 443 * @param b 444 * convert bytes to strings if b is true; otherwise, if false, do 445 * not convert bytes to strings. 446 */ 447 public final void setConvertByteToString(boolean b) { 448 convertByteToString = b; 449 } 450 451 /** 452 * Returns the flag that indicates if a byte array is converted to a string 453 * array. 454 * 455 * @return true if byte array is converted to string; otherwise, returns 456 * false if there is no conversion. 457 */ 458 public final boolean getConvertByteToString() { 459 return convertByteToString; 460 } 461 462 /** 463 * Reads the raw data of the dataset from file to a byte array. 464 * 465 * readBytes() reads raw data to an array of bytes instead of array of its 466 * datatype. For example, for a one-dimension 32-bit integer dataset of 467 * size 5, readBytes() returns a byte array of size 20 instead of an 468 * int array of 5. 469 * 470 * readBytes() can be used to copy data from one dataset to another 471 * efficiently because the raw data is not converted to its native type, it 472 * saves memory space and CPU time. 473 * 474 * @return the byte array of the raw data. 475 * 476 * @throws Exception if data can not be read 477 */ 478 public abstract byte[] readBytes() throws Exception; 479 480 /** 481 * Writes the memory buffer of this dataset to file. 482 * 483 * @throws Exception if buffer can not be written 484 */ 485 @Override 486 public final void write() throws Exception { 487 log.trace("Dataset: write enter"); 488 if (data != null) { 489 log.trace("Dataset: write data"); 490 write(data); 491 } 492 } 493 494 /** 495 * Creates a new dataset and writes the data buffer to the new dataset. 496 * 497 * This function allows applications to create a new dataset for a given 498 * data buffer. For example, users can select a specific interesting part 499 * from a large image and create a new image with the selection. 500 * 501 * The new dataset retains the datatype and dataset creation properties of 502 * this dataset. 503 * 504 * @param pgroup 505 * the group which the dataset is copied to. 506 * @param name 507 * the name of the new dataset. 508 * @param dims 509 * the dimension sizes of the the new dataset. 510 * @param data 511 * the data values of the subset to be copied. 512 * 513 * @return the new dataset. 514 * 515 * @throws Exception if dataset can not be copied 516 */ 517 public abstract Dataset copy(Group pgroup, String name, long[] dims, Object data) throws Exception; 518 519 /** 520 * The status of initialization for this object 521 * 522 * @return true if the data has been initialized 523 */ 524 @Override 525 public final boolean isInited() { 526 return inited; 527 } 528 529 /** 530 * Resets selection of dataspace 531 */ 532 protected void resetSelection() { 533 for (int i = 0; i < rank; i++) { 534 startDims[i] = 0; 535 selectedDims[i] = 1; 536 if (selectedStride != null) 537 selectedStride[i] = 1; 538 } 539 540 if (rank == 1) { 541 selectedIndex[0] = 0; 542 selectedDims[0] = dims[0]; 543 } 544 else if (rank == 2) { 545 selectedIndex[0] = 0; 546 selectedIndex[1] = 1; 547 selectedDims[0] = dims[0]; 548 selectedDims[1] = dims[1]; 549 } 550 else if (rank > 2) { 551 if (isImage) { 552 // 3D dataset is arranged in the order of [frame][height][width] 553 selectedIndex[1] = rank - 1; // width, the fastest dimension 554 selectedIndex[0] = rank - 2; // height 555 selectedIndex[2] = rank - 3; // frames 556 } 557 else { 558 selectedIndex[0] = 0; // width, the fastest dimension 559 selectedIndex[1] = 1; // height 560 selectedIndex[2] = 2; // frames 561 } 562 563 selectedDims[selectedIndex[0]] = dims[selectedIndex[0]]; 564 selectedDims[selectedIndex[1]] = dims[selectedIndex[1]]; 565 selectedDims[selectedIndex[2]] = dims[selectedIndex[2]]; 566 } 567 568 isDataLoaded = false; 569 } 570 571 /** 572 * Returns the data buffer of the dataset in memory. 573 * 574 * If data is already loaded into memory, returns the data; otherwise, calls 575 * read() to read data from file into a memory buffer and returns the memory 576 * buffer. 577 * 578 * By default, the whole dataset is read into memory. Users can also select 579 * a subset to read. Subsetting is done in an implicit way. 580 * 581 * <b>How to Select a Subset</b> 582 * 583 * A selection is specified by three arrays: start, stride and count. 584 * <ol> 585 * <li>start: offset of a selection 586 * <li>stride: determines how many elements to move in each dimension 587 * <li>count: number of elements to select in each dimension 588 * </ol> 589 * getStartDims(), getStride() and getSelectedDims() returns the start, 590 * stride and count arrays respectively. Applications can make a selection 591 * by changing the values of the arrays. 592 * 593 * The following example shows how to make a subset. In the example, the 594 * dataset is a 4-dimensional array of [200][100][50][10], i.e. dims[0]=200; 595 * dims[1]=100; dims[2]=50; dims[3]=10; <br> 596 * We want to select every other data point in dims[1] and dims[2] 597 * 598 * <pre> 599 * int rank = dataset.getRank(); // number of dimensions of the dataset 600 * long[] dims = dataset.getDims(); // the dimension sizes of the dataset 601 * long[] selected = dataset.getSelectedDims(); // the selected size of the dataet 602 * long[] start = dataset.getStartDims(); // the offset of the selection 603 * long[] stride = dataset.getStride(); // the stride of the dataset 604 * int[] selectedIndex = dataset.getSelectedIndex(); // the selected dimensions for display 605 * 606 * // select dim1 and dim2 as 2D data for display,and slice through dim0 607 * selectedIndex[0] = 1; 608 * selectedIndex[1] = 2; 609 * selectedIndex[1] = 0; 610 * 611 * // reset the selection arrays 612 * for (int i = 0; i < rank; i++) { 613 * start[i] = 0; 614 * selected[i] = 1; 615 * stride[i] = 1; 616 * } 617 * 618 * // set stride to 2 on dim1 and dim2 so that every other data point is 619 * // selected. 620 * stride[1] = 2; 621 * stride[2] = 2; 622 * 623 * // set the selection size of dim1 and dim2 624 * selected[1] = dims[1] / stride[1]; 625 * selected[2] = dims[1] / stride[2]; 626 * 627 * // when dataset.getData() is called, the selection above will be used since 628 * // the dimension arrays are passed by reference. Changes of these arrays 629 * // outside the dataset object directly change the values of these array 630 * // in the dataset object. 631 * </pre> 632 * 633 * For ScalarDS, the memory data buffer is a one-dimensional array of byte, 634 * short, int, float, double or String type based on the datatype of the 635 * dataset. 636 * 637 * For CompoundDS, the memory data object is an java.util.List object. Each 638 * element of the list is a data array that corresponds to a compound field. 639 * 640 * For example, if compound dataset "comp" has the following nested 641 * structure, and member datatypes 642 * 643 * <pre> 644 * comp --> m01 (int) 645 * comp --> m02 (float) 646 * comp --> nest1 --> m11 (char) 647 * comp --> nest1 --> m12 (String) 648 * comp --> nest1 --> nest2 --> m21 (long) 649 * comp --> nest1 --> nest2 --> m22 (double) 650 * </pre> 651 * 652 * getData() returns a list of six arrays: {int[], float[], char[], 653 * String[], long[] and double[]}. 654 * 655 * @return the memory buffer of the dataset. 656 * 657 * @throws Exception if object can not be read 658 * @throws OutOfMemoryError if memory is exhausted 659 */ 660 @Override 661 public Object getData() throws Exception, OutOfMemoryError { 662 log.trace("getData(): isDataLoaded={}", isDataLoaded); 663 if (!isDataLoaded) { 664 data = read(); // load the data 665 if (data != null) { 666 originalBuf = data; 667 isDataLoaded = true; 668 nPoints = 1; 669 log.trace("getData(): selectedDims length={}",selectedDims.length); 670 for (int j = 0; j < selectedDims.length; j++) 671 nPoints *= selectedDims[j]; 672 } 673 log.trace("getData(): read {}", nPoints); 674 } 675 676 return data; 677 } 678 679 /** 680 * Not for public use in the future. 681 * 682 * setData() is not safe to use because it changes memory buffer 683 * of the dataset object. Dataset operations such as write/read 684 * will fail if the buffer type or size is changed. 685 * 686 * @param d the object data -must be an array of Objects 687 */ 688 @Override 689 public final void setData(Object d) { 690 if (!(this instanceof Attribute)) 691 throw new UnsupportedOperationException("setData: unsupported for non-Attribute objects"); 692 693 log.trace("setData(): isDataLoaded={}", isDataLoaded); 694 data = d; 695 originalBuf = data; 696 isDataLoaded = true; 697 } 698 699 /** 700 * Clears the current data buffer in memory and forces the next read() to load 701 * the data from file. 702 * 703 * The function read() loads data from file into memory only if the data is 704 * not read. If data is already in memory, read() just returns the memory 705 * buffer. Sometimes we want to force read() to re-read data from file. For 706 * example, when the selection is changed, we need to re-read the data. 707 * 708 * @see #getData() 709 * @see #read() 710 */ 711 @Override 712 public void clearData() { 713 isDataLoaded = false; 714 } 715 716 /** 717 * Refreshes the current object in the file. 718 * 719 * The function read() loads data from file into memory only if the data is not 720 * read. If data is already in memory, read() just returns the memory buffer. 721 * Sometimes we want to force a clear and read to re-read the object from the file. 722 * For example, when the selection is changed, we need to re-read the data. 723 * 724 * @see #getData() 725 * @see #read() 726 */ 727 @Override 728 public Object refreshData() { 729 Object dataValue = null; 730 731 clearData(); 732 try { 733 dataValue = getData(); 734 735 /* 736 * TODO: Converting data from unsigned C integers to Java integers 737 * is currently unsupported for Compound Datasets. 738 */ 739 if (!(this instanceof CompoundDS)) 740 convertFromUnsignedC(); 741 742 dataValue = getData(); 743 log.trace("refresh data"); 744 } 745 catch (Exception ex) { 746 log.trace("refresh data failure: ", ex); 747 } 748 return dataValue; 749 } 750 751 /** 752 * Returns the dimension size of the vertical axis. 753 * 754 * This function is used by GUI applications such as HDFView. GUI 755 * applications display a dataset in a 2D table or 2D image. The display 756 * order is specified by the index array of selectedIndex as follow: 757 * <dl> 758 * <dt>selectedIndex[0] -- height</dt> 759 * <dd>The vertical axis</dd> 760 * <dt>selectedIndex[1] -- width</dt> 761 * <dd>The horizontal axis</dd> 762 * <dt>selectedIndex[2] -- depth</dt> 763 * <dd>The depth axis is used for 3 or more dimensional datasets.</dd> 764 * </dl> 765 * Applications can use getSelectedIndex() to access and change the display 766 * order. For example, in a 2D dataset of 200x50 (dim0=200, dim1=50), the 767 * following code will set the height=200 and width=50. 768 * 769 * <pre> 770 * int[] selectedIndex = dataset.getSelectedIndex(); 771 * selectedIndex[0] = 0; 772 * selectedIndex[1] = 1; 773 * </pre> 774 * 775 * @see #getSelectedIndex() 776 * @see #getWidth() 777 * 778 * @return the size of dimension of the vertical axis. 779 */ 780 @Override 781 public final long getHeight() { 782 if ((selectedDims == null) || (selectedIndex == null)) 783 return 0; 784 785 if ((selectedDims.length < 1) || (selectedIndex.length < 1)) 786 return 0; 787 788 return selectedDims[selectedIndex[0]]; 789 } 790 791 /** 792 * Returns the dimension size of the horizontal axis. 793 * 794 * This function is used by GUI applications such as HDFView. GUI 795 * applications display a dataset in 2D Table or 2D Image. The display order is 796 * specified by the index array of selectedIndex as follow: 797 * <dl> 798 * <dt>selectedIndex[0] -- height</dt> 799 * <dd>The vertical axis</dd> 800 * <dt>selectedIndex[1] -- width</dt> 801 * <dd>The horizontal axis</dd> 802 * <dt>selectedIndex[2] -- depth</dt> 803 * <dd>The depth axis, which is used for 3 or more dimension datasets.</dd> 804 * </dl> 805 * Applications can use getSelectedIndex() to access and change the display 806 * order. For example, in a 2D dataset of 200x50 (dim0=200, dim1=50), the 807 * following code will set the height=200 and width=100. 808 * 809 * <pre> 810 * int[] selectedIndex = dataset.getSelectedIndex(); 811 * selectedIndex[0] = 0; 812 * selectedIndex[1] = 1; 813 * </pre> 814 * 815 * @see #getSelectedIndex() 816 * @see #getHeight() 817 * 818 * @return the size of dimension of the horizontal axis. 819 */ 820 @Override 821 public final long getWidth() { 822 if ((selectedDims == null) || (selectedIndex == null)) 823 return 0; 824 825 if ((selectedDims.length < 2) || (selectedIndex.length < 2)) 826 return 1; 827 828 return selectedDims[selectedIndex[1]]; 829 } 830 831 /** 832 * Returns the dimension size of the frame axis. 833 * 834 * This function is used by GUI applications such as HDFView. GUI 835 * applications display a dataset in 2D Table or 2D Image. The display order is 836 * specified by the index array of selectedIndex as follow: 837 * <dl> 838 * <dt>selectedIndex[0] -- height</dt> 839 * <dd>The vertical axis</dd> 840 * <dt>selectedIndex[1] -- width</dt> 841 * <dd>The horizontal axis</dd> 842 * <dt>selectedIndex[2] -- depth</dt> 843 * <dd>The depth axis, which is used for 3 or more dimension datasets.</dd> 844 * </dl> 845 * Applications can use getSelectedIndex() to access and change the display 846 * order. For example, in a 2D dataset of 200x50 (dim0=200, dim1=50), the 847 * following code will set the height=200 and width=100. 848 * 849 * <pre> 850 * int[] selectedIndex = dataset.getSelectedIndex(); 851 * selectedIndex[0] = 0; 852 * selectedIndex[1] = 1; 853 * </pre> 854 * 855 * @see #getSelectedIndex() 856 * @see #getHeight() 857 * 858 * @return the size of dimension of the frame axis. 859 */ 860 @Override 861 public final long getDepth() { 862 if ((selectedDims == null) || (selectedIndex == null)) 863 return 0; 864 865 if ((selectedDims.length < 2) || (selectedIndex.length < 2)) 866 return 1; 867 868 log.trace("getDepth {}", selectedDims[selectedIndex[2]]); 869 return selectedDims[selectedIndex[2]]; 870 } 871 872 /** 873 * Returns the indices of display order. 874 * 875 * selectedIndex[] is provided for two purposes: 876 * <OL> 877 * <LI> 878 * selectedIndex[] is used to indicate the order of dimensions for display. 879 * selectedIndex[0] is for the row, selectedIndex[1] is for the column and 880 * selectedIndex[2] for the depth. 881 * 882 * For example, for a four dimension dataset, if selectedIndex[] = {1, 2, 3}, 883 * then dim[1] is selected as row index, dim[2] is selected as column index 884 * and dim[3] is selected as depth index. 885 * <LI> 886 * selectedIndex[] is also used to select dimensions for display for 887 * datasets with three or more dimensions. We assume that applications such 888 * as HDFView can only display data values up to three dimensions (2D 889 * spreadsheet/image with a third dimension which the 2D spreadsheet/image 890 * is selected from). For datasets with more than three dimensions, we need 891 * selectedIndex[] to tell applications which three dimensions are chosen 892 * for display. <br> 893 * For example, for a four dimension dataset, if selectedIndex[] = {1, 2, 3}, 894 * then dim[1] is selected as row index, dim[2] is selected as column index 895 * and dim[3] is selected as depth index. dim[0] is not selected. Its 896 * location is fixed at 0 by default. 897 * </OL> 898 * 899 * @return the array of the indices of display order. 900 */ 901 @Override 902 public final int[] getSelectedIndex() { 903 return selectedIndex; 904 } 905 906 /** 907 * Returns the string representation of compression information. 908 * 909 * For example, 910 * "SZIP: Pixels per block = 8: H5Z_FILTER_CONFIG_DECODE_ENABLED". 911 * 912 * @return the string representation of compression information. 913 */ 914 @Override 915 public final String getCompression() { 916 return compression.toString(); 917 } 918 919 /** 920 * Returns the string representation of filter information. 921 * 922 * @return the string representation of filter information. 923 */ 924 public final String getFilters() { 925 return filters.toString(); 926 } 927 928 /** 929 * Returns the string representation of storage layout information. 930 * 931 * @return the string representation of storage layout information. 932 */ 933 public final String getStorageLayout() { 934 return storageLayout.toString(); 935 } 936 937 /** 938 * Returns the string representation of storage information. 939 * 940 * @return the string representation of storage information. 941 */ 942 public final String getStorage() { 943 return storage.toString(); 944 } 945 946 /** 947 * Returns the array that contains the dimension sizes of the chunk of the 948 * dataset. Returns null if the dataset is not chunked. 949 * 950 * @return the array of chunk sizes or returns null if the dataset is not 951 * chunked. 952 */ 953 public final long[] getChunkSize() { 954 return chunkSize; 955 } 956 957 /** 958 * Returns the datatype of the data object. 959 * 960 * @return the datatype of the data object. 961 */ 962 @Override 963 public Datatype getDatatype() { 964 return datatype; 965 } 966 967 /** 968 * @deprecated Not for public use in the future. <br> 969 * Using {@link #convertFromUnsignedC(Object, Object)} 970 * 971 * @param dataIN the object data 972 * 973 * @return the converted object 974 */ 975 @Deprecated 976 public static Object convertFromUnsignedC(Object dataIN) { 977 return Dataset.convertFromUnsignedC(dataIN, null); 978 } 979 980 /** 981 * Converts one-dimension array of unsigned C-type integers to a new array 982 * of appropriate Java integer in memory. 983 * 984 * Since Java does not support unsigned integer, values of unsigned C-type 985 * integers must be converted into its appropriate Java integer. Otherwise, 986 * the data value will not displayed correctly. For example, if an unsigned 987 * C byte, x = 200, is stored into an Java byte y, y will be -56 instead of 988 * the correct value of 200. 989 * 990 * Unsigned C integers are upgrade to Java integers according to the 991 * following table: 992 * <table border=1> 993 * <caption><b>Mapping Unsigned C Integers to Java Integers</b></caption> 994 * <TR> 995 * <TD><B>Unsigned C Integer</B></TD> 996 * <TD><B>JAVA Intege</B>r</TD> 997 * </TR> 998 * <TR> 999 * <TD>unsigned byte</TD> 1000 * <TD>signed short</TD> 1001 * </TR> 1002 * <TR> 1003 * <TD>unsigned short</TD> 1004 * <TD>signed int</TD> 1005 * </TR> 1006 * <TR> 1007 * <TD>unsigned int</TD> 1008 * <TD>signed long</TD> 1009 * </TR> 1010 * <TR> 1011 * <TD>unsigned long</TD> 1012 * <TD>signed long</TD> 1013 * </TR> 1014 * </TABLE> 1015 * <strong>NOTE: this conversion cannot deal with unsigned 64-bit integers. 1016 * Therefore, the values of unsigned 64-bit datasets may be wrong in Java 1017 * applications</strong>. 1018 * 1019 * If memory data of unsigned integers is converted by 1020 * convertFromUnsignedC(), convertToUnsignedC() must be called to convert 1021 * the data back to unsigned C before data is written into file. 1022 * 1023 * @see #convertToUnsignedC(Object, Object) 1024 * 1025 * @param dataIN 1026 * the input 1D array of the unsigned C-type integers. 1027 * @param dataOUT 1028 * the output converted (or upgraded) 1D array of Java integers. 1029 * 1030 * @return the upgraded 1D array of Java integers. 1031 */ 1032 @SuppressWarnings("rawtypes") 1033 public static Object convertFromUnsignedC(Object dataIN, Object dataOUT) { 1034 if (dataIN == null) { 1035 log.debug("convertFromUnsignedC(): data_in is null"); 1036 return null; 1037 } 1038 1039 Class dataClass = dataIN.getClass(); 1040 if (!dataClass.isArray()) { 1041 log.debug("convertFromUnsignedC(): data_in not an array"); 1042 return null; 1043 } 1044 1045 if (dataOUT != null) { 1046 Class dataClassOut = dataOUT.getClass(); 1047 if (!dataClassOut.isArray() || (Array.getLength(dataIN) != Array.getLength(dataOUT))) { 1048 log.debug("convertFromUnsignedC(): data_out not an array or does not match data_in size"); 1049 dataOUT = null; 1050 } 1051 } 1052 1053 String cname = dataClass.getName(); 1054 char dname = cname.charAt(cname.lastIndexOf('[') + 1); 1055 int size = Array.getLength(dataIN); 1056 log.trace("convertFromUnsignedC(): cname={} dname={} size={}", cname, dname, size); 1057 1058 if (dname == 'B') { 1059 log.debug("convertFromUnsignedC(): Java convert byte to short"); 1060 short[] sdata = null; 1061 if (dataOUT == null) 1062 sdata = new short[size]; 1063 else 1064 sdata = (short[]) dataOUT; 1065 1066 byte[] bdata = (byte[]) dataIN; 1067 for (int i = 0; i < size; i++) 1068 sdata[i] = (short) ((bdata[i] + 256) & 0xFF); 1069 1070 dataOUT = sdata; 1071 } 1072 else if (dname == 'S') { 1073 log.debug("convertFromUnsignedC(): Java convert short to int"); 1074 int[] idata = null; 1075 if (dataOUT == null) 1076 idata = new int[size]; 1077 else 1078 idata = (int[]) dataOUT; 1079 1080 short[] sdata = (short[]) dataIN; 1081 for (int i = 0; i < size; i++) 1082 idata[i] = (sdata[i] + 65536) & 0xFFFF; 1083 1084 dataOUT = idata; 1085 } 1086 else if (dname == 'I') { 1087 log.debug("convertFromUnsignedC(): Java convert int to long"); 1088 long[] ldata = null; 1089 if (dataOUT == null) 1090 ldata = new long[size]; 1091 else 1092 ldata = (long[]) dataOUT; 1093 1094 int[] idata = (int[]) dataIN; 1095 for (int i = 0; i < size; i++) 1096 ldata[i] = (idata[i] + 4294967296L) & 0xFFFFFFFFL; 1097 1098 dataOUT = ldata; 1099 } 1100 else { 1101 dataOUT = dataIN; 1102 log.debug("convertFromUnsignedC(): Java does not support unsigned long"); 1103 } 1104 1105 return dataOUT; 1106 } 1107 1108 /** 1109 * @deprecated Not for public use in the future. <br> 1110 * Using {@link #convertToUnsignedC(Object, Object)} 1111 * 1112 * @param dataIN 1113 * the input 1D array of the unsigned C-type integers. 1114 * 1115 * @return the upgraded 1D array of Java integers. 1116 */ 1117 @Deprecated 1118 public static Object convertToUnsignedC(Object dataIN) { 1119 return Dataset.convertToUnsignedC(dataIN, null); 1120 } 1121 1122 /** 1123 * Converts the array of converted unsigned integers back to unsigned C-type 1124 * integer data in memory. 1125 * 1126 * If memory data of unsigned integers is converted by 1127 * convertFromUnsignedC(), convertToUnsignedC() must be called to convert 1128 * the data back to unsigned C before data is written into file. 1129 * 1130 * @see #convertFromUnsignedC(Object, Object) 1131 * 1132 * @param dataIN 1133 * the input array of the Java integer. 1134 * @param dataOUT 1135 * the output array of the unsigned C-type integer. 1136 * 1137 * @return the converted data of unsigned C-type integer array. 1138 */ 1139 @SuppressWarnings("rawtypes") 1140 public static Object convertToUnsignedC(Object dataIN, Object dataOUT) { 1141 if (dataIN == null) { 1142 log.debug("convertToUnsignedC(): data_in is null"); 1143 return null; 1144 } 1145 1146 Class dataClass = dataIN.getClass(); 1147 if (!dataClass.isArray()) { 1148 log.debug("convertToUnsignedC(): data_in not an array"); 1149 return null; 1150 } 1151 1152 if (dataOUT != null) { 1153 Class dataClassOut = dataOUT.getClass(); 1154 if (!dataClassOut.isArray() || (Array.getLength(dataIN) != Array.getLength(dataOUT))) { 1155 log.debug("convertToUnsignedC(): data_out not an array or does not match data_in size"); 1156 dataOUT = null; 1157 } 1158 } 1159 1160 String cname = dataClass.getName(); 1161 char dname = cname.charAt(cname.lastIndexOf('[') + 1); 1162 int size = Array.getLength(dataIN); 1163 log.trace("convertToUnsignedC(): cname={} dname={} size={}", cname, dname, size); 1164 1165 if (dname == 'S') { 1166 log.debug("convertToUnsignedC(): Java convert short to byte"); 1167 byte[] bdata = null; 1168 if (dataOUT == null) 1169 bdata = new byte[size]; 1170 else 1171 bdata = (byte[]) dataOUT; 1172 short[] sdata = (short[]) dataIN; 1173 for (int i = 0; i < size; i++) 1174 bdata[i] = (byte) sdata[i]; 1175 dataOUT = bdata; 1176 } 1177 else if (dname == 'I') { 1178 log.debug("convertToUnsignedC(): Java convert int to short"); 1179 short[] sdata = null; 1180 if (dataOUT == null) 1181 sdata = new short[size]; 1182 else 1183 sdata = (short[]) dataOUT; 1184 int[] idata = (int[]) dataIN; 1185 for (int i = 0; i < size; i++) 1186 sdata[i] = (short) idata[i]; 1187 dataOUT = sdata; 1188 } 1189 else if (dname == 'J') { 1190 log.debug("convertToUnsignedC(): Java convert long to int"); 1191 int[] idata = null; 1192 if (dataOUT == null) 1193 idata = new int[size]; 1194 else 1195 idata = (int[]) dataOUT; 1196 long[] ldata = (long[]) dataIN; 1197 for (int i = 0; i < size; i++) 1198 idata[i] = (int) ldata[i]; 1199 dataOUT = idata; 1200 } 1201 else { 1202 dataOUT = dataIN; 1203 log.debug("convertToUnsignedC(): Java does not support unsigned long"); 1204 } 1205 1206 return dataOUT; 1207 } 1208 1209 /** 1210 * Converts an array of bytes into an array of Strings for a fixed string 1211 * dataset. 1212 * 1213 * A C-string is an array of chars while an Java String is an object. When a 1214 * string dataset is read into a Java application, the data is stored in an 1215 * array of Java bytes. byteToString() is used to convert the array of bytes 1216 * into an array of Java strings so that applications can display and modify 1217 * the data content. 1218 * 1219 * For example, the content of a two element C string dataset is {"ABC", 1220 * "abc"}. Java applications will read the data into a byte array of {65, 1221 * 66, 67, 97, 98, 99). byteToString(bytes, 3) returns an array of Java 1222 * String of strs[0]="ABC", and strs[1]="abc". 1223 * 1224 * If memory data of strings is converted to Java Strings, stringToByte() 1225 * must be called to convert the memory data back to byte array before data 1226 * is written to file. 1227 * 1228 * @see #stringToByte(String[], int) 1229 * 1230 * @param bytes 1231 * the array of bytes to convert. 1232 * @param length 1233 * the length of string. 1234 * 1235 * @return the array of Java String. 1236 */ 1237 public static final String[] byteToString(byte[] bytes, int length) { 1238 if (bytes == null) { 1239 log.debug("byteToString(): input is null"); 1240 return null; 1241 } 1242 1243 int n = bytes.length / length; 1244 log.trace("byteToString(): n={} from length of {}", n, length); 1245 String[] strArray = new String[n]; 1246 String str = null; 1247 int idx = 0; 1248 for (int i = 0; i < n; i++) { 1249 str = new String(bytes, i * length, length); 1250 idx = str.indexOf('\0'); 1251 if (idx >= 0) 1252 str = str.substring(0, idx); 1253 1254 // trim only the end 1255 int end = str.length(); 1256 while (end > 0 && str.charAt(end - 1) <= '\u0020') 1257 end--; 1258 1259 strArray[i] = (end <= 0) ? "" : str.substring(0, end); 1260 } 1261 1262 return strArray; 1263 } 1264 1265 /** 1266 * Converts a string array into an array of bytes for a fixed string 1267 * dataset. 1268 * 1269 * If memory data of strings is converted to Java Strings, stringToByte() 1270 * must be called to convert the memory data back to byte array before data 1271 * is written to file. 1272 * 1273 * @see #byteToString(byte[] bytes, int length) 1274 * 1275 * @param strings 1276 * the array of string. 1277 * @param length 1278 * the length of string. 1279 * 1280 * @return the array of bytes. 1281 */ 1282 public static final byte[] stringToByte(String[] strings, int length) { 1283 if (strings == null) { 1284 log.debug("stringToByte(): input is null"); 1285 return null; 1286 } 1287 1288 int size = strings.length; 1289 byte[] bytes = new byte[size * length]; 1290 log.trace("stringToByte(): size={} length={}", size, length); 1291 StringBuilder strBuff = new StringBuilder(length); 1292 for (int i = 0; i < size; i++) { 1293 // initialize the string with spaces 1294 strBuff.replace(0, length, " "); 1295 1296 if (strings[i] != null) { 1297 if (strings[i].length() > length) 1298 strings[i] = strings[i].substring(0, length); 1299 strBuff.replace(0, length, strings[i]); 1300 } 1301 1302 strBuff.setLength(length); 1303 System.arraycopy(strBuff.toString().getBytes(), 0, bytes, length * i, length); 1304 } 1305 1306 return bytes; 1307 } 1308 1309 /** 1310 * Returns the array of strings that represent the dimension names. Returns 1311 * null if there is no dimension name. 1312 * 1313 * Some datasets have pre-defined names for each dimension such as 1314 * "Latitude" and "Longitude". getDimNames() returns these pre-defined 1315 * names. 1316 * 1317 * @return the names of dimensions, or null if there is no dimension name. 1318 */ 1319 public final String[] getDimNames() { 1320 return dimNames; 1321 } 1322 1323 /** 1324 * Checks if a given datatype is a string. Sub-classes must replace this 1325 * default implementation. 1326 * 1327 * @param tid 1328 * The data type identifier. 1329 * 1330 * @return true if the datatype is a string; otherwise returns false. 1331 */ 1332 public boolean isString(long tid) { 1333 return false; 1334 } 1335 1336 /** 1337 * Returns the size in bytes of a given datatype. Sub-classes must replace 1338 * this default implementation. 1339 * 1340 * @param tid 1341 * The data type identifier. 1342 * 1343 * @return The size of the datatype 1344 */ 1345 public long getSize(long tid) { 1346 return -1; 1347 } 1348 1349 /** 1350 * Get Class of the original data buffer if converted. 1351 * 1352 * @return the Class of originalBuf 1353 */ 1354 @Override 1355 @SuppressWarnings("rawtypes") 1356 public final Class getOriginalClass() { 1357 return originalBuf.getClass(); 1358 } 1359 1360 /** 1361 * @return true if the data is a single scalar point; otherwise, returns 1362 * false. 1363 */ 1364 public boolean isScalar() { 1365 return isScalar; 1366 } 1367 1368 /** 1369 * Checks if dataset is virtual. Sub-classes must replace 1370 * this default implementation. 1371 * 1372 * @return true if the dataset is virtual; otherwise returns false. 1373 */ 1374 public boolean isVirtual() { 1375 return false; 1376 } 1377 1378 /** 1379 * Gets the source file name at index if dataset is virtual. Sub-classes must replace 1380 * this default implementation. 1381 * 1382 * @param index 1383 * index of the source file name if dataset is virtual. 1384 * 1385 * @return filename if the dataset is virtual; otherwise returns null. 1386 */ 1387 public String getVirtualFilename(int index) { 1388 return null; 1389 } 1390 1391 /** 1392 * Gets the number of source files if dataset is virtual. Sub-classes must replace 1393 * this default implementation. 1394 * 1395 * @return the list size if the dataset is virtual; otherwise returns negative. 1396 */ 1397 public int getVirtualMaps() { 1398 return -1; 1399 } 1400 1401 /** 1402 * Returns a string representation of the data value. For 1403 * example, "0, 255". 1404 * 1405 * For a compound datatype, it will be a 1D array of strings with field 1406 * members separated by the delimiter. For example, 1407 * "{0, 10.5}, {255, 20.0}, {512, 30.0}" is a compound attribute of {int, 1408 * float} of three data points. 1409 * 1410 * @param delimiter 1411 * The delimiter used to separate individual data points. It 1412 * can be a comma, semicolon, tab or space. For example, 1413 * toString(",") will separate data by commas. 1414 * 1415 * @return the string representation of the data values. 1416 */ 1417 public String toString(String delimiter) { 1418 return toString(delimiter, -1); 1419 } 1420 1421 /** 1422 * Returns a string representation of the data value. For 1423 * example, "0, 255". 1424 * 1425 * For a compound datatype, it will be a 1D array of strings with field 1426 * members separated by the delimiter. For example, 1427 * "{0, 10.5}, {255, 20.0}, {512, 30.0}" is a compound attribute of {int, 1428 * float} of three data points. 1429 * 1430 * @param delimiter 1431 * The delimiter used to separate individual data points. It 1432 * can be a comma, semicolon, tab or space. For example, 1433 * toString(",") will separate data by commas. 1434 * @param maxItems 1435 * The maximum number of Array values to return 1436 * 1437 * @return the string representation of the data values. 1438 */ 1439 public String toString(String delimiter, int maxItems) { 1440 Object theData = originalBuf; 1441 if (theData == null) { 1442 log.debug("toString: value is null"); 1443 return null; 1444 } 1445 1446 if (theData instanceof List<?>) { 1447 log.trace("toString: value is list"); 1448 return null; 1449 } 1450 1451 Class<? extends Object> valClass = theData.getClass(); 1452 1453 if (!valClass.isArray()) { 1454 log.trace("toString: finish - not array"); 1455 String strValue = theData.toString(); 1456 if (maxItems > 0 && strValue.length() > maxItems) 1457 // truncate the extra characters 1458 strValue = strValue.substring(0, maxItems); 1459 return strValue; 1460 } 1461 1462 // value is an array 1463 StringBuilder sb = new StringBuilder(); 1464 int n = Array.getLength(theData); 1465 if ((maxItems > 0) && (n > maxItems)) 1466 n = maxItems; 1467 1468 log.trace("toString: is_enum={} is_unsigned={} Array.getLength={}", getDatatype().isEnum(), 1469 getDatatype().isUnsigned(), n); 1470 1471 if (getDatatype().isEnum()) { 1472 String cname = valClass.getName(); 1473 char dname = cname.charAt(cname.lastIndexOf('[') + 1); 1474 log.trace("toString: is_enum with cname={} dname={}", cname, dname); 1475 1476 Map<String, String> map = this.getDatatype().getEnumMembers(); 1477 String theValue = null; 1478 switch (dname) { 1479 case 'B': 1480 byte[] barray = (byte[]) theData; 1481 short sValue = barray[0]; 1482 theValue = String.valueOf(sValue); 1483 if (map.containsKey(theValue)) 1484 sb.append(map.get(theValue)); 1485 else 1486 sb.append(sValue); 1487 for (int i = 1; i < n; i++) { 1488 sb.append(delimiter); 1489 sValue = barray[i]; 1490 theValue = String.valueOf(sValue); 1491 if (map.containsKey(theValue)) 1492 sb.append(map.get(theValue)); 1493 else 1494 sb.append(sValue); 1495 } 1496 break; 1497 case 'S': 1498 short[] sarray = (short[]) theData; 1499 int iValue = sarray[0]; 1500 theValue = String.valueOf(iValue); 1501 if (map.containsKey(theValue)) 1502 sb.append(map.get(theValue)); 1503 else 1504 sb.append(iValue); 1505 for (int i = 1; i < n; i++) { 1506 sb.append(delimiter); 1507 iValue = sarray[i]; 1508 theValue = String.valueOf(iValue); 1509 if (map.containsKey(theValue)) 1510 sb.append(map.get(theValue)); 1511 else 1512 sb.append(iValue); 1513 } 1514 break; 1515 case 'I': 1516 int[] iarray = (int[]) theData; 1517 long lValue = iarray[0]; 1518 theValue = String.valueOf(lValue); 1519 if (map.containsKey(theValue)) 1520 sb.append(map.get(theValue)); 1521 else 1522 sb.append(lValue); 1523 for (int i = 1; i < n; i++) { 1524 sb.append(delimiter); 1525 lValue = iarray[i]; 1526 theValue = String.valueOf(lValue); 1527 if (map.containsKey(theValue)) 1528 sb.append(map.get(theValue)); 1529 else 1530 sb.append(lValue); 1531 } 1532 break; 1533 case 'J': 1534 long[] larray = (long[]) theData; 1535 Long l = larray[0]; 1536 theValue = Long.toString(l); 1537 if (map.containsKey(theValue)) 1538 sb.append(map.get(theValue)); 1539 else 1540 sb.append(theValue); 1541 for (int i = 1; i < n; i++) { 1542 sb.append(delimiter); 1543 l = larray[i]; 1544 theValue = Long.toString(l); 1545 if (map.containsKey(theValue)) 1546 sb.append(map.get(theValue)); 1547 else 1548 sb.append(theValue); 1549 } 1550 break; 1551 default: 1552 sb.append(Array.get(theData, 0)); 1553 for (int i = 1; i < n; i++) { 1554 sb.append(delimiter); 1555 sb.append(Array.get(theData, i)); 1556 } 1557 break; 1558 } 1559 } 1560 else if (getDatatype().isUnsigned()) { 1561 String cname = valClass.getName(); 1562 char dname = cname.charAt(cname.lastIndexOf('[') + 1); 1563 log.trace("toString: is_unsigned with cname={} dname={}", cname, dname); 1564 1565 switch (dname) { 1566 case 'B': 1567 byte[] barray = (byte[]) theData; 1568 short sValue = barray[0]; 1569 if (sValue < 0) 1570 sValue += 256; 1571 sb.append(sValue); 1572 for (int i = 1; i < n; i++) { 1573 sb.append(delimiter); 1574 sValue = barray[i]; 1575 if (sValue < 0) 1576 sValue += 256; 1577 sb.append(sValue); 1578 } 1579 break; 1580 case 'S': 1581 short[] sarray = (short[]) theData; 1582 int iValue = sarray[0]; 1583 if (iValue < 0) 1584 iValue += 65536; 1585 sb.append(iValue); 1586 for (int i = 1; i < n; i++) { 1587 sb.append(delimiter); 1588 iValue = sarray[i]; 1589 if (iValue < 0) 1590 iValue += 65536; 1591 sb.append(iValue); 1592 } 1593 break; 1594 case 'I': 1595 int[] iarray = (int[]) theData; 1596 long lValue = iarray[0]; 1597 if (lValue < 0) 1598 lValue += 4294967296L; 1599 sb.append(lValue); 1600 for (int i = 1; i < n; i++) { 1601 sb.append(delimiter); 1602 lValue = iarray[i]; 1603 if (lValue < 0) 1604 lValue += 4294967296L; 1605 sb.append(lValue); 1606 } 1607 break; 1608 case 'J': 1609 long[] larray = (long[]) theData; 1610 Long l = larray[0]; 1611 String theValue = Long.toString(l); 1612 if (l < 0) { 1613 l = (l << 1) >>> 1; 1614 BigInteger big1 = new BigInteger("9223372036854775808"); // 2^65 1615 BigInteger big2 = new BigInteger(l.toString()); 1616 BigInteger big = big1.add(big2); 1617 theValue = big.toString(); 1618 } 1619 sb.append(theValue); 1620 for (int i = 1; i < n; i++) { 1621 sb.append(delimiter); 1622 l = larray[i]; 1623 theValue = Long.toString(l); 1624 if (l < 0) { 1625 l = (l << 1) >>> 1; 1626 BigInteger big1 = new BigInteger("9223372036854775808"); // 2^65 1627 BigInteger big2 = new BigInteger(l.toString()); 1628 BigInteger big = big1.add(big2); 1629 theValue = big.toString(); 1630 } 1631 sb.append(theValue); 1632 } 1633 break; 1634 default: 1635 String strValue = Array.get(theData, 0).toString(); 1636 if (maxItems > 0 && strValue.length() > maxItems) 1637 // truncate the extra characters 1638 strValue = strValue.substring(0, maxItems); 1639 sb.append(strValue); 1640 for (int i = 1; i < n; i++) { 1641 sb.append(delimiter); 1642 strValue = Array.get(theData, i).toString(); 1643 if (maxItems > 0 && strValue.length() > maxItems) 1644 // truncate the extra characters 1645 strValue = strValue.substring(0, maxItems); 1646 sb.append(strValue); 1647 } 1648 break; 1649 } 1650 } 1651 else { 1652 log.trace("toString: not enum or unsigned"); 1653 Object value = Array.get(theData, 0); 1654 String strValue; 1655 1656 if (value == null) 1657 strValue = "null"; 1658 else 1659 strValue = value.toString(); 1660 1661 if (maxItems > 0 && strValue.length() > maxItems) 1662 // truncate the extra characters 1663 strValue = strValue.substring(0, maxItems); 1664 sb.append(strValue); 1665 1666 for (int i = 1; i < n; i++) { 1667 sb.append(delimiter); 1668 value = Array.get(theData, i); 1669 1670 if (value == null) 1671 strValue = "null"; 1672 else 1673 strValue = value.toString(); 1674 1675 if (maxItems > 0 && strValue.length() > maxItems) 1676 // truncate the extra characters 1677 strValue = strValue.substring(0, maxItems); 1678 sb.append(strValue); 1679 } 1680 } 1681 1682 return sb.toString(); 1683 } 1684}