diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d6d978b86..89ebafa068 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog for the fact-tools +# Version 1.1.2 -- 17.12.2018 + +* Fix reading of uncompressed values from zfits heap tiles (Issue #389) + Before, the same value was repeated for every row in one tile. + This affects e.g. `UnixTimeUTC` and `BoardTime` and booleans. + # Version 1.1.1 -- 14.11.2018 * Make Writer keys case sensitive by default (#384) diff --git a/pom.xml b/pom.xml index 7c2bb9cb99..086395ec38 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.sfb876 fact-tools fact-tools - 1.1.1 + 1.1.2 http://sfb876.de/fact-tools/ diff --git a/src/main/java/fact/io/hdureader/ZFITSHeapReader.java b/src/main/java/fact/io/hdureader/ZFITSHeapReader.java index 597af7c84d..f32cf60397 100644 --- a/src/main/java/fact/io/hdureader/ZFITSHeapReader.java +++ b/src/main/java/fact/io/hdureader/ZFITSHeapReader.java @@ -125,7 +125,7 @@ public void skipRows(int amount) throws IOException { if (resultingRow >= this.numberOfRowsInTable) { throw new IOException("Not enough rows in table, need "+(amount+numberOfRowsRead)+" have "+numberOfRowsInTable); } - + // check if resulting row is in the current catalog remainer int remainer = zTileLen - numberOfRowsRead%zTileLen; if (amount getNextRow(boolean ignoreWrongTile shortBuffer.get(data); map.put(column.name, data); } else { - ByteBuffer byteBuffer = (ByteBuffer) curBuffer; if (column.repeatCount == 1) { - map.put(column.name, readSingleValueFromBuffer(column, byteBuffer)); + map.put(column.name, readSingleValueFromBuffer(column, (ByteBuffer) curBuffer)); } else { - map.put(column.name, readArrayFromBuffer(column, byteBuffer)); + map.put(column.name, readArrayFromBuffer(column, curBuffer)); } } } @@ -324,10 +323,40 @@ private void getNextTileIntoCache(boolean ignoreWrongTileHeader) throws IOExcept // convert to int, no block is bigger than 4GB int numberBytes = Math.toIntExact(block.getDataSize()); byte[] cache = new byte[numberBytes]; - for (int i = 0; i < numberBytes; i++) { - cache[i] = tileBuffer.get(); + tileBuffer.get(cache); + + ByteBuffer byteBuffer = ByteBuffer.wrap(cache).order(ByteOrder.LITTLE_ENDIAN); + + if (column.repeatCount > 1) { + switch (column.type) { + case BYTE: + tileCache.put(column.name, byteBuffer); + break; + case BOOLEAN: + tileCache.put(column.name, byteBuffer); + break; + case CHAR: + tileCache.put(column.name, byteBuffer.asCharBuffer()); + break; + case SHORT: + tileCache.put(column.name, byteBuffer.asShortBuffer()); + break; + case INT: + tileCache.put(column.name, byteBuffer.asIntBuffer()); + break; + case LONG: + tileCache.put(column.name, byteBuffer.asLongBuffer()); + break; + case FLOAT: + tileCache.put(column.name, byteBuffer.asFloatBuffer()); + break; + case DOUBLE: + tileCache.put(column.name, byteBuffer.asDoubleBuffer()); + break; + } + } else { + tileCache.put(column.name, byteBuffer); } - tileCache.put(column.name, ByteBuffer.wrap(cache).order(ByteOrder.LITTLE_ENDIAN)); } else { throw new NotImplementedException("Compression: '" + block.compression.name() + "' is not implemented"); } @@ -646,10 +675,10 @@ private Serializable readSingleValueFromBuffer(BinTable.TableColumn c, ByteBuffe Serializable b = null; switch (c.type) { case BOOLEAN: - b = buffer.get() > 0; + b = buffer.get() == 'T'; break; case CHAR: - b = buffer.asCharBuffer().toString(); + b = buffer.getChar(); break; case BYTE: b = buffer.get(); @@ -673,44 +702,42 @@ private Serializable readSingleValueFromBuffer(BinTable.TableColumn c, ByteBuffe return b; } - private Serializable readArrayFromBuffer(BinTable.TableColumn c, ByteBuffer buffer) throws IOException { - - if (c.type == BinTable.ColumnType.BOOLEAN) { - boolean[] bools = new boolean[c.repeatCount]; - for (int i = 0; i < c.repeatCount; i++) { - bools[i] = buffer.get() > 0; - } - return bools; - } - + private Serializable readArrayFromBuffer(BinTable.TableColumn c, Buffer buffer) throws IOException { switch (c.type) { - case CHAR: - char[] chars = new char[c.repeatCount]; - buffer.asCharBuffer().get(chars); - return chars; case BYTE: byte[] b = new byte[c.repeatCount]; - buffer.get(b); + ((ByteBuffer) buffer).get(b); return b; + case BOOLEAN: + boolean[] bools = new boolean[c.repeatCount]; + ByteBuffer byteBuffer = (ByteBuffer) buffer; + for (int i = 0; i < c.repeatCount; i++) { + bools[i] = byteBuffer.get() == 'T'; + } + return bools; + case CHAR: + char[] chars = new char[c.repeatCount]; + ((CharBuffer) buffer).get(chars); + return chars; case SHORT: short[] shorts = new short[c.repeatCount]; - buffer.asShortBuffer().get(shorts); + ((ShortBuffer) buffer).get(shorts); return shorts; case INT: int[] ints = new int[c.repeatCount]; - buffer.asIntBuffer().get(ints); + ((IntBuffer) buffer).get(ints); return ints; case LONG: long[] longs = new long[c.repeatCount]; - buffer.asLongBuffer().get(longs); + ((LongBuffer) buffer).get(longs); return longs; case FLOAT: float[] floats = new float[c.repeatCount]; - buffer.asFloatBuffer().get(floats); + ((FloatBuffer) buffer).get(floats); return floats; case DOUBLE: double[] doubles = new double[c.repeatCount]; - buffer.asDoubleBuffer().get(doubles); + ((DoubleBuffer) buffer).get(doubles); return doubles; } return null; diff --git a/src/test/java/fact/io/hdureader/ZFitsReaderTests.java b/src/test/java/fact/io/hdureader/ZFitsReaderTests.java index e8b7174316..9b738d2e61 100644 --- a/src/test/java/fact/io/hdureader/ZFitsReaderTests.java +++ b/src/test/java/fact/io/hdureader/ZFitsReaderTests.java @@ -50,6 +50,29 @@ public void testZSHRINK() throws Exception { assertTrue(num == 6); } + + @Test + public void testUnixTimeUTCIncreases() throws Exception { + URL u = ZFitsReaderTests.class.getResource("/testDataFileZTILELEN.fits.fz"); + + FITS f = new FITS(u); + HDU events = f.getHDU("Events").orElseThrow(() -> new RuntimeException("File did not contain HDU 'Events'")); + BinTable binTable = events.getBinTable(); + ZFITSHeapReader heapReader = ZFITSHeapReader.forTable(binTable); + + long lastTimestamp = -1; + for (OptionalTypesMap p : heapReader) { + assertTrue(p.containsKey("Data")); + + int[] unixTimeUTC = p.getIntArray("UnixTimeUTC").orElseThrow(RuntimeException::new); + long timestamp = ((long) unixTimeUTC[0]) * 1000000 + unixTimeUTC[1]; + + assertTrue(timestamp > lastTimestamp); + lastTimestamp = timestamp; + } + } + + @Test public void testZTileLen() throws Exception { //URL u = CompareOldAndNewReaders.class.getResource("/testDataFile.fits.fz");