diff --git a/README.md b/README.md index cc1d5b9b..ffe95eab 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ of HDF5 and HDF4. Previous releases of HDFView that were based on HDF5 1.8, | 3.3.0 | 1.14.0 | 4.2.16 | HDF5 1.12 (new-style) references, Single-Writer/Multiple-Readers (SWMR) reads, bug fixes | | 3.3.1 | 1.14.2 | 4.2.16-2 | Fixes a critical HDF4 + HDFView bug | | 3.3.2 | 1.14.4 | 4.3.0 | Float16 support | -| 3.3.3 | 1.16.0 | 4.4.0 | Complex number support | +| 3.4.0 | 2.0.0 | 4.4.0 | Complex number support | PREVIOUS RELEASES AND SOURCE CODE diff --git a/src/org.hdfgroup.hdfview/hdf/view/TableView/DataDisplayConverterFactory.java b/src/org.hdfgroup.hdfview/hdf/view/TableView/DataDisplayConverterFactory.java index 39bcc84f..2a0b69b3 100644 --- a/src/org.hdfgroup.hdfview/hdf/view/TableView/DataDisplayConverterFactory.java +++ b/src/org.hdfgroup.hdfview/hdf/view/TableView/DataDisplayConverterFactory.java @@ -102,6 +102,8 @@ else if (dtype.isOpaque() || dtype.isBitField()) converter = new BitfieldDataDisplayConverter(dtype); else if (dtype.isRef()) converter = new RefDataDisplayConverter(dtype); + else if (dtype.isComplex()) + converter = new ComplexDataDisplayConverter(dtype); } catch (Exception ex) { log.debug( @@ -963,4 +965,137 @@ public Object canonicalToDisplayValue(Object value) return buffer; } } + + private static class ComplexDataDisplayConverter extends HDFDisplayConverter { + private static final Logger log = LoggerFactory.getLogger(ComplexDataDisplayConverter.class); + + private final HDFDisplayConverter baseTypeConverter; + private final StringBuilder buffer; + + ComplexDataDisplayConverter(final Datatype dtype) throws Exception { + super(dtype); + + if (!dtype.isComplex()) { + log.debug("exit: datatype is not a complex type"); + throw new Exception("ComplexDataDisplayConverter: datatype is not a complex type"); + } + + Datatype baseType = dtype.getDatatypeBase(); + + if (baseType == null) { + log.debug("exit: base datatype is null"); + throw new Exception("ComplexDataDisplayConverter: base datatype is null"); + } + + try { + baseTypeConverter = getDataDisplayConverter(baseType); + + /* + * Make base datatype converter inherit the data conversion settings. + */ + baseTypeConverter.setShowAsHex(this.showAsHex); + baseTypeConverter.setShowAsBin(this.showAsBin); + baseTypeConverter.setNumberFormat(this.numberFormat); + baseTypeConverter.setConvertEnum(this.isEnumConverted); + } + catch (Exception ex) { + log.debug("exit: couldn't get DataDisplayConverter for base datatype: ", ex); + throw new Exception("ComplexDataDisplayConverter: couldn't get DataDisplayConverter for base datatype: " + + ex.getMessage()); + } + + buffer = new StringBuilder(); + } + + @Override + public Object canonicalToDisplayValue(ILayerCell cell, IConfigRegistry configRegistry, Object value) + { + cellRowIdx = cell.getRowIndex(); + cellColIdx = cell.getColumnIndex(); + return canonicalToDisplayValue(value); + } + + @Override + public Object canonicalToDisplayValue(Object value) + { + log.trace("canonicalToDisplayValue({}): start", value); + + if (value instanceof String) + return value; + + if (value == null) { + log.debug("canonicalToDisplayValue({}): value is null", value); + return DataFactoryUtils.nullStr; + } + + buffer.setLength(0); // clear the old string + + /* + * Pass the cell's row and column index down in case there is a CompoundDataDisplayConverter at the bottom + * of the chain. + */ + baseTypeConverter.cellRowIdx = cellRowIdx; + baseTypeConverter.cellColIdx = cellColIdx; + + try { + Object obj; + Object convertedValue; + int arrLen = Array.getLength(value); + + log.trace("canonicalToDisplayValue({}): array length={}", value, arrLen); + + for (int i = 0; i < arrLen; i++) { + if (i > 0) + buffer.append("+"); + + obj = Array.get(value, i); + + convertedValue = baseTypeConverter.canonicalToDisplayValue(obj); + + buffer.append(convertedValue); + } + + buffer.append("i"); + } + catch (Exception ex) { + log.debug("canonicalToDisplayValue({}): failure: ", value, ex); + buffer.setLength(0); + buffer.append(DataFactoryUtils.errStr); + } + + return buffer; + } + + @Override + public void setNumberFormat(NumberFormat format) + { + super.setNumberFormat(format); + + baseTypeConverter.setNumberFormat(format); + } + + @Override + public void setShowAsHex(boolean asHex) + { + super.setShowAsHex(asHex); + + baseTypeConverter.setShowAsHex(asHex); + } + + @Override + public void setShowAsBin(boolean asBin) + { + super.setShowAsBin(asBin); + + baseTypeConverter.setShowAsBin(asBin); + } + + @Override + public void setConvertEnum(boolean convert) + { + super.setConvertEnum(convert); + + baseTypeConverter.setConvertEnum(convert); + } + } } diff --git a/src/org.hdfgroup.hdfview/hdf/view/TableView/DataProviderFactory.java b/src/org.hdfgroup.hdfview/hdf/view/TableView/DataProviderFactory.java index 6edbd7bf..9e1f7071 100644 --- a/src/org.hdfgroup.hdfview/hdf/view/TableView/DataProviderFactory.java +++ b/src/org.hdfgroup.hdfview/hdf/view/TableView/DataProviderFactory.java @@ -115,6 +115,8 @@ else if (dtype.isOpaque() || dtype.isBitField()) dataProvider = new BitfieldDataProvider(dtype, dataBuf, dataTransposed); else if (dtype.isRef()) dataProvider = new RefDataProvider(dtype, dataBuf, dataTransposed); + else if (dtype.isComplex()) + dataProvider = new ComplexDataProvider(dtype, dataBuf, dataTransposed); } catch (Exception ex) { log.debug("getDataProvider(): error occurred in retrieving a DataProvider: ", ex); @@ -1438,6 +1440,7 @@ private void updateArrayOfArrayElements(Object newValue, Object curBuf, int colu case Datatype.CLASS_ARRAY: case Datatype.CLASS_COMPOUND: case Datatype.CLASS_VLEN: + case Datatype.CLASS_COMPLEX: default: buffer = new Object[newcnt]; break; @@ -1480,6 +1483,7 @@ private void updateArrayOfAtomicElements(Object newValue, Object curBuf, int row case Datatype.CLASS_ARRAY: case Datatype.CLASS_COMPOUND: case Datatype.CLASS_VLEN: + case Datatype.CLASS_COMPLEX: default: buffer = new Object[newcnt]; break; @@ -1949,4 +1953,116 @@ private String populateReferenceObject(Object byteBuf, int startIndex) return objectStr; } } + + private static class ComplexDataProvider extends HDFDataProvider { + private static final Logger log = LoggerFactory.getLogger(ComplexDataProvider.class); + + private final HDFDataProvider baseTypeDataProvider; + + private final StringBuilder buffer; + + private final long typeSize; + + ComplexDataProvider(final Datatype dtype, final Object dataBuf, final boolean dataTransposed) throws Exception { + super(dtype, dataBuf, dataTransposed); + + Datatype baseType = dtype.getDatatypeBase(); + + baseTypeDataProvider = getDataProvider(baseType, dataBuf, dataTransposed); + + typeSize = baseType.getDatatypeSize(); + + buffer = new StringBuilder(); + } + + @Override + public Object getDataValue(int columnIndex, int rowIndex) + { + buffer.setLength(0); + + log.trace("getDataValue(rowIndex={}, columnIndex={}): start", rowIndex, columnIndex); + + try { + int bufIndex = physicalLocationToBufIndex(rowIndex, columnIndex); + theValue = retrieveArrayOfAtomicElements(dataBuf, bufIndex * 2); + log.trace("getDataValue(bufIndex={}, dataBuf={})=({})", bufIndex, dataBuf, theValue); + } + catch (Exception ex) { + log.debug("getDataValue(rowIndex={}, columnIndex={}): failure: ", rowIndex, columnIndex, ex); + theValue = DataFactoryUtils.errStr; + } + + log.trace("getDataValue(rowIndex={}, columnIndex={})=({}): finish", rowIndex, columnIndex, theValue); + + return theValue; + } + + private Object[] retrieveArrayOfAtomicElements(Object objBuf, int rowStartIdx) + { + log.debug("retrieveArrayOfAtomicElements(): objBuf={}", objBuf); + Object[] tempArray = new Object[(int) 2]; + Object realElement = Array.get(objBuf, rowStartIdx); + Object imgElement = Array.get(objBuf, rowStartIdx + 1); + log.debug("retrieveArrayOfAtomicElements(): realElement={} imgElement={}", realElement, imgElement); + + tempArray[0] = baseTypeDataProvider.getDataValue(objBuf, rowStartIdx); + tempArray[1] = baseTypeDataProvider.getDataValue(objBuf, rowStartIdx + 1); + + log.debug("retrieveArrayOfAtomicElements(): tempArray={}", tempArray); + return tempArray; + } + + @Override + public void setDataValue(int columnIndex, int rowIndex, Object newValue) + { + try { + int bufIndex = physicalLocationToBufIndex(rowIndex, columnIndex); + + updateArrayElements(dataBuf, newValue, columnIndex, rowIndex); + } + catch (Exception ex) { + log.debug("setDataValue(rowIndex={}, columnIndex={}, {}): cell value update failure: ", rowIndex, + columnIndex, newValue, ex); + } + log.trace("setDataValue(rowIndex={}, columnIndex={})=({}): finish", rowIndex, columnIndex, newValue); + } + + @Override + public void setDataValue(int columnIndex, int rowIndex, Object bufObject, Object newValue) + { + try { + updateArrayElements(bufObject, newValue, columnIndex, rowIndex); + } + catch (Exception ex) { + log.debug("setDataValue(rowIndex={}, columnIndex={}, bufObject={}, {}): cell value update failure: ", + rowIndex, columnIndex, bufObject, newValue, ex); + } + log.trace("setDataValue(rowIndex={}, columnIndex={}, bufObject={})=({}): finish", rowIndex, columnIndex, + bufObject, newValue); + } + + private void updateArrayElements(Object curBuf, Object newValue, int columnIndex, int rowStartIndex) + { + updateArrayOfAtomicElements(newValue, curBuf, rowStartIndex); + } + + private void updateArrayOfAtomicElements(Object newValue, Object curBuf, int rowStartIdx) + { + ArrayList vlElements = ((ArrayList[]) curBuf)[rowStartIdx]; + + StringTokenizer st = new StringTokenizer((String) newValue, "+i"); + int newcnt = st.countTokens(); + Object[] buffer = new Double[newcnt]; + for (int i = 0; i < newcnt; i++) { + baseTypeDataProvider.setDataValue(i, buffer, st.nextToken().trim()); + isValueChanged = isValueChanged || baseTypeDataProvider.getIsValueChanged(); + } + String bname = buffer.getClass().getName(); + String cname = curBuf.getClass().getName(); + log.trace("updateArrayOfAtomicElements(): buffer cname={} of data cname={}", bname, cname); + vlElements = new ArrayList<>(Arrays.asList(buffer)); + log.debug("updateArrayOfAtomicElements(): new vlSize={}", vlElements.size()); + ((ArrayList[]) curBuf)[rowStartIdx] = vlElements; + } + } } diff --git a/src/org.hdfgroup.hdfview/hdf/view/dialog/UserOptionsHDFPage.java b/src/org.hdfgroup.hdfview/hdf/view/dialog/UserOptionsHDFPage.java index cae29b7d..20e298b5 100644 --- a/src/org.hdfgroup.hdfview/hdf/view/dialog/UserOptionsHDFPage.java +++ b/src/org.hdfgroup.hdfview/hdf/view/dialog/UserOptionsHDFPage.java @@ -55,9 +55,9 @@ public class UserOptionsHDFPage extends UserOptionsDefaultPage { private Button checkNativeOrder, checkDecOrder, checkIncOrder; private Button checkIndexName, checkIndexCreateOrder; private Button earlyLibVersion, early18LibVersion, early110LibVersion, early112LibVersion, - early114LibVersion, earlyLateLibVersion; + early114LibVersion, early200LibVersion, earlyLateLibVersion; private Button lateLibVersion, late18LibVersion, late110LibVersion, late112LibVersion, late114LibVersion, - lateLateLibVersion; + late200LibVersion, lateLateLibVersion; private Button pluginDirButton; /** Default early libversion for files */ @@ -130,6 +130,8 @@ else if (early112LibVersion.getSelection()) ViewProperties.setEarlyLib("v112"); else if (early114LibVersion.getSelection()) ViewProperties.setEarlyLib("v114"); + else if (early200LibVersion.getSelection()) + ViewProperties.setEarlyLib("v200"); else if (earlyLateLibVersion.getSelection()) ViewProperties.setEarlyLib("Latest"); else @@ -148,6 +150,8 @@ else if (late112LibVersion.getSelection()) ViewProperties.setLateLib("v112"); else if (late114LibVersion.getSelection()) ViewProperties.setLateLib("v114"); + else if (late200LibVersion.getSelection()) + ViewProperties.setLateLib("v200"); else if (lateLateLibVersion.getSelection()) ViewProperties.setLateLib("Latest"); else @@ -211,6 +215,7 @@ protected void load() early110LibVersion.setSelection(earlyLibVers.compareTo("v110") == 0); early112LibVersion.setSelection(earlyLibVers.compareTo("v112") == 0); early114LibVersion.setSelection(earlyLibVers.compareTo("v114") == 0); + early200LibVersion.setSelection(earlyLibVers.compareTo("v200") == 0); earlyLateLibVersion.setSelection(earlyLibVers.compareTo("Latest") == 0); lateLibVers = ViewProperties.getLateLib(); @@ -220,6 +225,7 @@ protected void load() late110LibVersion.setSelection(lateLibVers.compareTo("v110") == 0); late112LibVersion.setSelection(lateLibVers.compareTo("v112") == 0); late114LibVersion.setSelection(lateLibVers.compareTo("v114") == 0); + late200LibVersion.setSelection(lateLibVers.compareTo("v200") == 0); lateLateLibVersion.setSelection(lateLibVers.compareTo("Latest") == 0); checkConvertEnum.setSelection(ViewProperties.isConvertEnum()); @@ -311,6 +317,11 @@ protected Control createContents(Composite parent) early114LibVersion.setText("v114"); early114LibVersion.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + early200LibVersion = new Button(earlyLibVersionGroup, SWT.RADIO); + early200LibVersion.setFont(curFont); + early200LibVersion.setText("v200"); + early200LibVersion.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + earlyLateLibVersion = new Button(earlyLibVersionGroup, SWT.RADIO); earlyLateLibVersion.setFont(curFont); earlyLateLibVersion.setText("Latest"); @@ -348,6 +359,11 @@ protected Control createContents(Composite parent) late114LibVersion.setText("v114"); late114LibVersion.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + late200LibVersion = new Button(lateLibVersionGroup, SWT.RADIO); + late200LibVersion.setFont(curFont); + late200LibVersion.setText("v200"); + late200LibVersion.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + lateLateLibVersion = new Button(lateLibVersionGroup, SWT.RADIO); lateLateLibVersion.setFont(curFont); lateLateLibVersion.setText("Latest"); diff --git a/src/org.hdfgroup.object/hdf/object/CompoundDS.java b/src/org.hdfgroup.object/hdf/object/CompoundDS.java index 5aa0b3ba..03e1f3e7 100644 --- a/src/org.hdfgroup.object/hdf/object/CompoundDS.java +++ b/src/org.hdfgroup.object/hdf/object/CompoundDS.java @@ -593,6 +593,7 @@ else if (dtype.isArray()) { case Datatype.CLASS_ENUM: case Datatype.CLASS_VLEN: case Datatype.CLASS_TIME: + case Datatype.CLASS_COMPLEX: theObj = convertByteMember(baseType, byteData); break; diff --git a/src/org.hdfgroup.object/hdf/object/Datatype.java b/src/org.hdfgroup.object/hdf/object/Datatype.java index 9c84cd0a..f5ad65ff 100644 --- a/src/org.hdfgroup.object/hdf/object/Datatype.java +++ b/src/org.hdfgroup.object/hdf/object/Datatype.java @@ -151,6 +151,13 @@ public abstract class Datatype extends HObject implements MetaDataContainer { * href="https://support.hdfgroup.org/releases/hdf5/v1_14/v1_14_5/documentation/doxygen/_h5_t__u_g.html#sec_datatype">HDF5 * Datatypes in HDF5 User Guide */ + public static final int CLASS_COMPLEX = 12; + + /** + * See HDF5 + * Datatypes in HDF5 User Guide + */ public static final int ORDER_LE = 0; /** @@ -246,6 +253,11 @@ public abstract class Datatype extends HObject implements MetaDataContainer { */ protected boolean isVLEN = false; + /** + * Determines whether this datatype is a complex type. + */ + protected boolean isComplex = false; + /** * Determines whether this datatype is a variable-length string type. */ @@ -570,6 +582,7 @@ public long open() *