sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1753881 - in /sis/branches/JDK8/storage/sis-geotiff/src: main/java/org/apache/sis/storage/geotiff/ test/java/org/apache/sis/storage/geotiff/ test/java/org/apache/sis/test/ test/java/org/apache/sis/test/suite/
Date Sat, 23 Jul 2016 16:28:40 GMT
Author: desruisseaux
Date: Sat Jul 23 16:28:40 2016
New Revision: 1753881

URL: http://svn.apache.org/viewvc?rev=1753881&view=rev
Log:
Refactor the Types integer constants as a Type enumeration, and begin parsing a few tags.

Added:
    sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Compression.java
  (with props)
    sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/InvalidTiffHeaderException.java
  (with props)
    sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Type.java
      - copied, changed from r1753880, sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Types.java
    sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/CompressionTest.java
  (with props)
    sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/TypeTest.java
  (with props)
    sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/test/
    sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/test/suite/
    sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/test/suite/GeoTiffTestSuite.java
  (with props)
Removed:
    sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Types.java
Modified:
    sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
    sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Reader.java
    sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Tags.java

Added: sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Compression.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Compression.java?rev=1753881&view=auto
==============================================================================
--- sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Compression.java
(added)
+++ sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Compression.java
[UTF-8] Sat Jul 23 16:28:40 2016
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.storage.geotiff;
+
+
+/**
+ * Possible values for {@link Tags#Compression}.
+ * Data compression applies only to raster image data. All other TIFF fields are unaffected.
+ *
+ * @author  Johann Sorel (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.8
+ * @version 0.8
+ * @module
+ */
+enum Compression {
+    /**
+     * No compression, but pack data into bytes as tightly as possible, leaving no unused
bits except
+     * potentially at the end of rows. The component values are stored as an array of type
byte.
+     */
+    NONE(1),
+
+    /**
+     * CCITT Group 3, 1-Dimensional Modified Huffman run length encoding.
+     */
+    CCITT(2),
+
+    /**
+     * PackBits compression, a simple byte-oriented run length scheme.
+     */
+    PACK_BITS(32773),
+
+    // ---- End of baseline GeoTIFF. Remaining are extensions ----
+
+    /**
+     * LZW compression.
+     */
+    LZW(5),
+
+    /**
+     * Deflate compression, like ZIP format.
+     */
+    DEFLATE(8),
+
+    /**
+     * JPEG compression.
+     */
+    JPEG(6),
+
+    /**
+     * JPEG compression.
+     * @todo what is the difference with JPEG?
+     */
+    JPEG_2(7);
+
+    /**
+     * The TIFF code for this compression.
+     */
+    final int code;
+
+    /**
+     * Creates a new compression enumeration.
+     */
+    Compression(final int code) {
+        this.code = code;
+    }
+
+    /**
+     * Returns the compression method for the given GeoTIFF code, or {@code null} if none.
+     */
+    static Compression valueOf(final long code) {
+        if ((code & ~0xFFFF) == 0) {                // Should be a short according TIFF
specification.
+            switch ((int) code) {
+                case 1:     return NONE;
+                case 2:     return CCITT;
+                case 5:     return LZW;
+                case 6:     return JPEG;
+                case 7:     return JPEG_2;
+                case 8:     return DEFLATE;
+                case 32773: return PACK_BITS;
+            }
+        }
+        return null;
+    }
+}

Propchange: sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Compression.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Compression.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java?rev=1753881&r1=1753880&r2=1753881&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
[UTF-8] Sat Jul 23 16:28:40 2016
@@ -16,6 +16,9 @@
  */
 package org.apache.sis.storage.geotiff;
 
+import java.io.IOException;
+import org.apache.sis.internal.storage.ChannelDataInput;
+
 
 /**
  * An Image File Directory (FID) in a TIFF image.
@@ -37,27 +40,55 @@ final class ImageFileDirectory {
     final long offset;
 
     /**
-     * The size of the image described by this FID, or 0 if the information has not been
found.
-     * Should be interpreted as an unsigned value.
+     * The size of the image described by this FID, or -1 if the information has not been
found.
+     * The image may be much bigger than the memory capacity, in which case the image shall
be tiled.
      */
-    private int imageWidth, imageHeight;
+    private long imageWidth = -1, imageHeight = -1;
 
     /**
-     * The size of each tile, or 0 if the information has not be found.
-     * Should be interpreted as an unsigned value.
+     * The size of each tile, or -1 if the information has not be found.
+     * Tiles should be small enough for fitting in memory.
      */
-    private int tileWidth, tileHeight;
+    private int tileWidth = -1, tileHeight = -1;
 
     private int samplesPerPixel;
 
     /**
+     * The compression method, or {@code null} if unknown. If the compression method is unknown
+     * or unsupported we can not read the image, but we still can read the metadata.
+     */
+    private Compression compression;
+
+    /**
      * Creates a new image file directory located at the given offset (in bytes) in the TIFF
file.
      */
     ImageFileDirectory(final long offset) {
         this.offset = offset;
     }
 
-    void addEntry(final int tag, final int type, final long value) {
-        // TODO
+    /**
+     * Adds the value read from the current position in the given stream
+     * for the entry identified by the given GeoTIFF tag.
+     */
+    void addEntry(final ChannelDataInput input, final int tag, final Type type, final long
count) throws IOException {
+        switch (tag) {
+            case Tags.PhotometricInterpretation: {
+                final boolean blackIsZero = (type.readLong(input, count) != 0);
+                // TODO
+                break;
+            }
+            case Tags.Compression: {
+                compression = Compression.valueOf(type.readLong(input, count));
+                break;
+            }
+            case Tags.ImageLength: {
+                imageHeight = type.readUnsignedLong(input, count);
+                break;
+            }
+            case Tags.ImageWidth: {
+                imageWidth = type.readUnsignedLong(input, count);
+                break;
+            }
+        }
     }
 }

Added: sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/InvalidTiffHeaderException.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/InvalidTiffHeaderException.java?rev=1753881&view=auto
==============================================================================
--- sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/InvalidTiffHeaderException.java
(added)
+++ sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/InvalidTiffHeaderException.java
[UTF-8] Sat Jul 23 16:28:40 2016
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.storage.geotiff;
+
+import java.io.IOException;
+
+
+/**
+ * Thrown when a TIFF Image File Directory can not be read because of a logical inconsistency.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.8
+ * @version 0.8
+ * @module
+ */
+class InvalidTiffHeaderException extends IOException {
+    /**
+     * For cross-version compatibility.
+     */
+    private static final long serialVersionUID = 3469934460013440211L;
+
+    /**
+     * Creates a new exception with the given error message.
+     *
+     * @param message the error message.
+     */
+    InvalidTiffHeaderException(String message) {
+        super(message);
+    }
+
+    /**
+     * Creates a new exception with the given error message and error cause.
+     *
+     * @param message  the error message.
+     * @param cause    the cause of this error.
+     */
+    InvalidTiffHeaderException(String message, final Throwable cause) {
+        super(message, cause);
+    }
+}

Propchange: sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/InvalidTiffHeaderException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/InvalidTiffHeaderException.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Reader.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Reader.java?rev=1753881&r1=1753880&r2=1753881&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Reader.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Reader.java
[UTF-8] Sat Jul 23 16:28:40 2016
@@ -18,7 +18,6 @@ package org.apache.sis.storage.geotiff;
 
 import java.util.List;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Locale;
 import java.io.IOException;
 import java.nio.ByteOrder;
@@ -199,7 +198,6 @@ final class Reader extends GeoTIFF {
         input.seek(Math.addExact(origin, offset));
         final int offsetSize = Integer.BYTES << intSizeExpansion;
         final ImageFileDirectory dir = new ImageFileDirectory(offset);
-        final Collection<long[]> deferred = new ArrayList<>(4);
         for (long remaining = readUnsignedShort(); --remaining >= 0;) {
             /*
              * Each entry in the Image File Directory has the following format:
@@ -209,19 +207,30 @@ final class Reader extends GeoTIFF {
              *   - The value, or the file offset to the value elswhere in the file.
              */
             final int   tag   = input.readUnsignedShort();
-            final short type  = input.readShort();
+            final Type  type  = Type.valueOf(input.readShort());        // May be null.
             final long  count = readUnsignedInt();
-            final long  size  = Math.multiplyExact(Types.size(type), count);
-            final long  value = readUnsignedInt();
+            final long  size  = (type != null) ? Math.multiplyExact(type.size, count) : 0;
             if (size <= offsetSize) {
-                // offset is the real value(s).
-                dir.addEntry(tag, type, value);
+                /*
+                 * If the value can fit inside the number of bytes given by 'offsetSize',
then the value is
+                 * stored directly at that location. This is the most common way TIFF tag
values are stored.
+                 */
+                final long position = input.getStreamPosition();
+                if (size != 0) {
+                    /*
+                     * A size of zero means that we have an unknown type, in which case the
TIFF specification
+                     * recommends to ignore it (for allowing them to add new types in the
future), or an entry
+                     * without value (count = 0) - in principle illegal but we make this
reader tolerant.
+                     */
+                    dir.addEntry(input, tag, type, count);
+                }
+                input.seek(position + offsetSize);
             } else {
                 // offset from beginning of file where the values are stored.
-                deferred.add(new long[] {tag, type, count, value});
+                final long value = readUnsignedInt();
+                // TODO
             }
         }
-        // TODO: process deferred data.
         return imageFileDirectories.add(dir);
     }
 

Modified: sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Tags.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Tags.java?rev=1753881&r1=1753880&r2=1753881&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Tags.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Tags.java
[UTF-8] Sat Jul 23 16:28:40 2016
@@ -22,7 +22,7 @@ package org.apache.sis.storage.geotiff;
  * For that reason, many of those field names do not follow usual Java convention for constants.
  *
  * <p>A useful (but unofficial) reference is the
- * <a href="http://www.awaresystems.be/imaging/tiff/tifftags.html">TIFF Tag Reference</a>
page.
+ * <a href="http://www.awaresystems.be/imaging/tiff/tifftags.html">TIFF Tag Reference</a>
page.</p>
  *
  * @author  Johann Sorel (Geomatys)
  * @since   0.8

Copied: sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Type.java
(from r1753880, sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Types.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Type.java?p2=sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Type.java&p1=sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Types.java&r1=1753880&r2=1753881&rev=1753881&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Types.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Type.java
[UTF-8] Sat Jul 23 16:28:40 2016
@@ -16,63 +16,435 @@
  */
 package org.apache.sis.storage.geotiff;
 
+import java.util.Arrays;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import org.apache.sis.internal.storage.ChannelDataInput;
+import org.apache.sis.util.ArraysExt;
+import org.apache.sis.util.resources.Errors;
+
 
 /**
- * The numerical values of TIFF types.
+ * The types of values in a TIFF header. Provides also some support for reading a value of
a given type.
+ *
+ * <p><b>Note on naming convention:</b>
+ * the values in this enumeration are not necessarily named as the TIFF type names.
+ * This enumeration rather match the Java primitive type names.</p>
  *
+ * @author  Martin Desruisseaux (Geomatys)
  * @since   0.8
  * @version 0.8
  * @module
  */
-final class Types {
+enum Type {
+    /**
+     * An 8-bits byte that may contain anything, depending on the definition of the field.
+     * <ul>
+     *   <li>TIFF name: {@code UNDEFINED}</li>
+     *   <li>TIFF code: 7</li>
+     * </ul>
+     */
+    UNDEFINED(7, Byte.BYTES),
+
+    /**
+     * An 8-bits signed (twos-complement) integer.
+     * <ul>
+     *   <li>TIFF name: {@code SBYTE}</li>
+     *   <li>TIFF code: 6</li>
+     * </ul>
+     */
+    BYTE(6, Byte.BYTES) {
+        @Override long readLong(final ChannelDataInput input, final long count) throws IOException
{
+            ensureSingleton(count);
+            return input.readByte();
+        }
+    },
+
+    /**
+     * A 8-bits unsigned integer.
+     * <ul>
+     *   <li>TIFF name: {@code BYTE}</li>
+     *   <li>TIFF code: 1</li>
+     * </ul>
+     */
+    UBYTE(1, Byte.BYTES) {
+        @Override long readLong(final ChannelDataInput input, final long count) throws IOException
{
+            ensureSingleton(count);
+            return input.readUnsignedByte();
+        }
+    },
+
+    /**
+     * A 16-bits (2-bytes) signed (twos-complement) integer.
+     * <ul>
+     *   <li>TIFF name: {@code SSHORT}</li>
+     *   <li>TIFF code: 8</li>
+     * </ul>
+     */
+    SHORT(8, Short.BYTES) {
+        @Override long readLong(final ChannelDataInput input, final long count) throws IOException
{
+            ensureSingleton(count);
+            return input.readShort();
+        }
+    },
+
+    /**
+     * A 16-bits (2-bytes) unsigned integer.
+     * <ul>
+     *   <li>TIFF name: {@code SHORT}</li>
+     *   <li>TIFF code: 3</li>
+     * </ul>
+     */
+    USHORT(3, Short.BYTES) {
+        @Override long readLong(final ChannelDataInput input, final long count) throws IOException
{
+            ensureSingleton(count);
+            return input.readUnsignedShort();
+        }
+    },
+
+    /**
+     * A 32-bits (4-bytes) signed (twos-complement) integer.
+     * <ul>
+     *   <li>TIFF name: {@code SLONG}</li>
+     *   <li>TIFF code: 9</li>
+     * </ul>
+     */
+    INT(9, Integer.BYTES) {
+        @Override long readLong(final ChannelDataInput input, final long count) throws IOException
{
+            ensureSingleton(count);
+            return input.readInt();
+        }
+    },
+
     /**
-     * Types defined by the TIFF specification or one of its extensions.
+     * 32-bits (4-bytes) unsigned integer.
+     * <ul>
+     *   <li>TIFF name: {@code LONG}</li>
+     *   <li>TIFF code: 4</li>
+     * </ul>
      */
-    static final short UBYTE     = 1,
-                       ASCII     = 2,
-                       USHORT    = 3,
-                       UINT      = 4,
-                       URATIONAL = 5,      // unsigned Integer / unsigned Integer
-                       BYTE      = 6,
-                                           // type 7 is undefined
-                       SHORT     = 8,
-                       INT       = 9,
-                       RATIONAL  = 10,     // signed Integer / signed Integer
-                       FLOAT     = 11,
-                       DOUBLE    = 12,
-                       IFD       = 13,     // IFD is like UINT.
-                       ULONG     = 16,
-                       LONG      = 17,
-                       IFD8      = 18;     // IFD is like ULONG.
+    UINT(4, Integer.BYTES) {
+        @Override long readLong(final ChannelDataInput input, final long count) throws IOException
{
+            ensureSingleton(count);
+            return input.readUnsignedInt();
+        }
+    },
 
     /**
-     * The size of each type in bytes, or 0 if unknown.
+     * A 64-bits (8-bytes) signed (twos-complement) integer.
+     * <ul>
+     *   <li>TIFF code: 17</li>
+     * </ul>
      */
-    private static final byte[] SIZE = new byte[19];
+    LONG(17, Long.BYTES) {
+        @Override long readLong(final ChannelDataInput input, final long count) throws IOException
{
+            ensureSingleton(count);
+            return input.readLong();
+        }
+    },
+
+    /**
+     * A 64-bits (8-bytes) unsigned integer.
+     * <ul>
+     *   <li>TIFF code: 16</li>
+     * </ul>
+     */
+    ULONG(16, Long.BYTES) {
+        @Override long readLong(final ChannelDataInput input, final long count) throws IOException
{
+            ensureSingleton(count);
+            final long value = input.readLong();
+            if (value >= 0) {
+                return value;
+            }
+            return super.readLong(input, count);
+        }
+    },
+
+    /**
+     * Single precision (4-bytes) IEEE format.
+     * <ul>
+     *   <li>TIFF name: {@code FLOAT}</li>
+     *   <li>TIFF code: 11</li>
+     * </ul>
+     */
+    FLOAT(11, Float.BYTES) {
+        @Override long readLong(final ChannelDataInput input, final long count) throws IOException
{
+            ensureSingleton(count);
+            final float value = input.readFloat();
+            final long r = (long) value;
+            if (r == value) {
+                return r;
+            }
+            return super.readLong(input, count);            // Throws the exception.
+        }
+
+        @Override double readDouble(final ChannelDataInput input, final long count) throws
IOException {
+            ensureSingleton(count);
+            return input.readFloat();
+        }
+    },
+
+    /**
+     * Double precision (8-bytes) IEEE format.
+     * <ul>
+     *   <li>TIFF name: {@code DOUBLE}</li>
+     *   <li>TIFF code: 12</li>
+     * </ul>
+     */
+    DOUBLE(12, Double.BYTES) {
+        @Override long readLong(final ChannelDataInput input, final long count) throws IOException
{
+            ensureSingleton(count);
+            final double value = input.readDouble();
+            final long r = (long) value;
+            if (r == value) {
+                return r;
+            }
+            return super.readLong(input, count);            // Throws the exception.
+        }
+
+        @Override double readDouble(final ChannelDataInput input, final long count) throws
IOException {
+            ensureSingleton(count);
+            return input.readDouble();
+        }
+    },
+
+    /**
+     * Two signed integers: the first represents the numerator of a fraction; the second,
the denominator.
+     * <ul>
+     *   <li>TIFF name: {@code SRATIONAL}</li>
+     *   <li>TIFF code: 10</li>
+     * </ul>
+     */
+    RATIONAL(10, (2*Integer.BYTES)) {
+        @Override long readLong(final ChannelDataInput input, final long count) throws IOException
{
+            ensureSingleton(count);
+            final int numerator   = input.readInt();
+            final int denominator = input.readInt();
+            if ((numerator % denominator) == 0) {
+                return numerator / denominator;
+            }
+            return super.readLong(input, count);            // Throws the exception.
+        }
+
+        @Override double readDouble(final ChannelDataInput input, final long count) throws
IOException {
+            ensureSingleton(count);
+            return input.readInt() / (double) input.readInt();
+        }
+
+        @Override String[] readString(final ChannelDataInput input, final long length, final
Charset charset) throws IOException {
+            ensureSingleton(length);
+            return new String[] {
+                new StringBuilder().append(input.readInt()).append('/').append(input.readInt()).toString()
+            };
+        }
+    },
+
+    /**
+     * Two unsigned integers: the first represents the numerator of a fraction; the second,
the denominator.
+     * <ul>
+     *   <li>TIFF name: {@code RATIONAL}</li>
+     *   <li>TIFF code: 5</li>
+     * </ul>
+     */
+    URATIONAL(5, (2*Integer.BYTES)) {
+        @Override long readLong(final ChannelDataInput input, final long count) throws IOException
{
+            ensureSingleton(count);
+            final long numerator   = input.readUnsignedInt();
+            final long denominator = input.readUnsignedInt();
+            if ((numerator % denominator) == 0) {
+                return numerator / denominator;
+            }
+            return super.readLong(input, count);            // Throws the exception.
+        }
+
+        @Override double readDouble(final ChannelDataInput input, final long count) throws
IOException {
+            ensureSingleton(count);
+            return input.readUnsignedInt() / (double) input.readUnsignedInt();
+        }
+
+        @Override String[] readString(final ChannelDataInput input, final long length, final
Charset charset) throws IOException {
+            ensureSingleton(length);
+            return new String[] {
+                new StringBuilder().append(input.readUnsignedInt()).append('/').append(input.readUnsignedInt()).toString()
+            };
+        }
+    },
+
+    /**
+     * 8-bits byte that contains a 7-bit ASCII code. In a string of ASCII characters, the
last byte must be NUL
+     * (binary zero). The string length (including the NUL byte) is the {@code count} field
before the string.
+     * NUL bytes may also appear in the middle of the string for separating its content into
multi-strings.
+     * <ul>
+     *   <li>TIFF name: {@code ASCII}</li>
+     *   <li>TIFF code: 2</li>
+     * </ul>
+     */
+    ASCII(2, Byte.BYTES) {
+        @Override String[] readString(final ChannelDataInput input, final long length, final
Charset charset) throws IOException {
+            final byte[] chars = input.readBytes(Math.toIntExact(length));
+            String[] lines = new String[1];                     // We will usually have exactly
one string.
+            int count = 0, lower = 0;
+            for (int i=0; i<chars.length; i++) {
+                if (chars[i] == 0) {
+                    if (count >= lines.length) {
+                        lines = Arrays.copyOf(lines, 2*count);
+                    }
+                    lines[count++] = new String(chars, lower, i-lower, charset);
+                }
+            }
+            return ArraysExt.resize(lines, count);
+        }
+
+        @Override long readLong(final ChannelDataInput input, final long count) throws IOException
{
+            final String[] lines = readString(input, count, StandardCharsets.US_ASCII);
+            ensureSingleton(lines.length);
+            try {
+                return Long.parseLong(lines[0]);
+            } catch (NumberFormatException e) {
+                throw new InvalidTiffHeaderException(unparsable(lines), e);
+            }
+        }
+
+        @Override double readDouble(final ChannelDataInput input, final long count) throws
IOException {
+            final String[] lines = readString(input, count, StandardCharsets.US_ASCII);
+            ensureSingleton(lines.length);
+            try {
+                return Double.parseDouble(lines[0]);
+            } catch (NumberFormatException e) {
+                throw new InvalidTiffHeaderException(unparsable(lines), e);
+            }
+        }
+    };
+
+    /**
+     * The TIFF numerical code for this type.
+     */
+    final int code;
+
+    /**
+     * The size of this type, in number of bytes.
+     */
+    final int size;
+
+    /**
+     * Creates a new enumeration
+     */
+    private Type(final int code, final int size) {
+        this.code = code;
+        this.size = size;
+    }
+
+    /**
+     * All types known to this enumeration in an array where the index is the GeoTIFF numerical
code.
+     */
+    private static final Type[] FROM_CODES = new Type[19];
     static {
-        final byte[] s = SIZE;
-        s[ASCII]                      =   Byte.BYTES;
-        s[BYTE]      =  s[UBYTE]      =   Byte.BYTES;
-        s[SHORT]     =  s[USHORT]     =   Short.BYTES;
-        s[INT]       =  s[UINT]       =   Integer.BYTES;
-        s[LONG]      =  s[ULONG]      =   Long.BYTES;
-        s[RATIONAL]  =  s[URATIONAL]  = 2*Integer.BYTES;
-        s[IFD]                        =   Integer.BYTES;
-        s[IFD8]                       =   Long.BYTES;
-        s[FLOAT]                      =   Float.BYTES;
-        s[DOUBLE]                     =   Double.BYTES;
+        for (final Type type : values()) {
+            FROM_CODES[type.code] = type;
+        }
+        FROM_CODES[13] = UINT;      // IFD type.
+        FROM_CODES[18] = ULONG;     // IFD8 type.
+    }
+
+    /**
+     * Returns the type for the given GeoTIFF code, or {@code null} if the given type is
unknown.
+     *
+     * @param  code  the GeoTIFF numerical code.
+     * @return the enumeration value that represent the given type, or {@code null} if unknown.
+     */
+    static Type valueOf(final int code) {
+        return (code >= 0 && code < FROM_CODES.length) ? FROM_CODES[code] :
null;
+    }
+
+    /**
+     * Returns the error message for unparsable number.
+     */
+    static String unparsable(final String[] lines) {
+        // TODO: replace "<?>" by the actual tag name.
+        return Errors.format(Errors.Keys.UnparsableStringInElement_2, "<?>", lines[0]);
+    }
+
+    /**
+     * Invoked by {@code read(…)} method implementations for verifying that the {@code
count} argument value is 1.
+     * All read methods expect exactly one value, except the methods of the {@link #ASCII}
enumeration value which
+     * are treated differently.
+     *
+     * @param  count  the number of values to read.
+     * @throws InvalidTiffHeaderException if {@code count} does not have the expected value.
+     */
+    static void ensureSingleton(final long count) throws IOException {
+        if (count != 1) {
+            // TODO: replace "<?>" by the actual tag name.
+            throw new InvalidTiffHeaderException(Errors.format(Errors.Keys.TooManyOccurrences_2,
1, "<?>"));
+        }
+    }
+
+    /**
+     * Reads a single value which is expected to be positive. A negative value may be an
encoding error in the
+     * big TIFF file, or if it was really the intended value then something greater than
what we can support.
+     */
+    final long readUnsignedLong(final ChannelDataInput input, final long count) throws IOException
{
+        final long value = readLong(input, count);
+        if (value >= 0) {
+            return value;
+        }
+        // TODO: replace "<?>" by the actual tag name.
+        throw new InvalidTiffHeaderException(Errors.format(Errors.Keys.UnexpectedValueInElement_2,
"<?>", value));
+    }
+
+    /**
+     * Reads a single value and returns it as a {@code long} type, performing conversion
if needed.
+     * This method should be invoked when the caller expect a single value.
+     *
+     * <p>If the value is an ASCII type, then this method will parse the text as a
number.
+     * This support of ASCII type is required for supporting the encoding used in the tags
+     * added by GDAL.</p>
+     *
+     * @param  input  the input from where to read the value.
+     * @param  count  the amount of values (normally exactly 1).
+     * @return the value as a {@code long}.
+     * @throws InvalidTiffHeaderException if the value can not be converted to a {@code long}.
+     * @throws IOException if another error occurred while reading the stream.
+     */
+    long readLong(ChannelDataInput input, long count) throws IOException {
+        // TODO: replace "<?>" by the actual tag name.
+        throw new InvalidTiffHeaderException(Errors.format(Errors.Keys.IllegalPropertyType_2,
"<?>", name()));
     }
 
     /**
-     * Do not allow instantiation of this class.
+     * Reads a single value and returns it as a {@code double} type, performing conversion
if needed.
+     * This method should be invoked when the caller expect a single value.
+     *
+     * <p>If the value is an ASCII type, then this method will parse the text as a
number.
+     * This support of ASCII type is required for supporting the encoding used in the tags
+     * added by GDAL.</p>
+     *
+     * @param  input  the input from where to read the value.
+     * @param  count  the amount of values (normally exactly 1).
+     * @return the value as a {@code double}.
+     * @throws InvalidTiffHeaderException if the value can not be converted to a {@code double}.
+     * @throws IOException if another error occurred while reading the stream.
      */
-    private Types() {
+    double readDouble(ChannelDataInput input, long count) throws IOException {
+        return readLong(input, count);
     }
 
     /**
-     * Returns the size in bytes of the given type.
+     * Reads the value as strings. There is usually exactly one string, but an arbitrary
amount is allowed.
+     *
+     * @param  input    the input from where to read the value.
+     * @param  length   the string length, including the final NUL byte.
+     * @param  charset  the character encoding (normally US ASCII).
+     * @return the value as a string.
+     * @throws IOException if an error occurred while reading the stream.
+     * @throws ArithmeticException if the given length is too large.
      */
-    static int size(final short type) {
-        return SIZE[type] & 0xFF;
+    String[] readString(ChannelDataInput input, final long length, final Charset charset)
throws IOException {
+        final String[] s = new String[Math.toIntExact(length)];
+        for (int i=0; i<s.length; i++) {
+            s[i] = String.valueOf(readLong(input, 1));
+        }
+        return s;
     }
 }

Added: sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/CompressionTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/CompressionTest.java?rev=1753881&view=auto
==============================================================================
--- sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/CompressionTest.java
(added)
+++ sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/CompressionTest.java
[UTF-8] Sat Jul 23 16:28:40 2016
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License)); Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing)); software
+ * distributed under the License is distributed on an "AS IS" BASIS));
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND)); either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.storage.geotiff;
+
+import org.apache.sis.test.TestCase;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+
+/**
+ * Tests the {@link Compression} base class.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.8
+ * @version 0.8
+ * @module
+ */
+public final strictfp class CompressionTest extends TestCase {
+    /**
+     * Tests {@link Compression#valueOf(int)}.
+     */
+    @Test
+    public void testValueOf() {
+        for (final Compression c : Compression.values()) {
+            assertSame(c.name(), c, Compression.valueOf(c.code));
+        }
+    }
+}

Propchange: sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/CompressionTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/CompressionTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Added: sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/TypeTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/TypeTest.java?rev=1753881&view=auto
==============================================================================
--- sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/TypeTest.java
(added)
+++ sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/TypeTest.java
[UTF-8] Sat Jul 23 16:28:40 2016
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License)); Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing)); software
+ * distributed under the License is distributed on an "AS IS" BASIS));
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND)); either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.storage.geotiff;
+
+import org.apache.sis.test.TestCase;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+
+/**
+ * Tests the {@link Type} enumeration.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.8
+ * @version 0.8
+ * @module
+ */
+public final strictfp class TypeTest extends TestCase {
+    /**
+     * Tests {@link Type#valueOf(int)}.
+     */
+    @Test
+    public void testValueOf() {
+        assertEquals("UBYTE",     Type.UBYTE,     Type.valueOf( 1));
+        assertEquals("ASCII",     Type.ASCII,     Type.valueOf( 2));
+        assertEquals("USHORT",    Type.USHORT,    Type.valueOf( 3));
+        assertEquals("UINT",      Type.UINT,      Type.valueOf( 4));
+        assertEquals("URATIONAL", Type.URATIONAL, Type.valueOf( 5));      // unsigned Integer
/ unsigned Integer
+        assertEquals("BYTE",      Type.BYTE,      Type.valueOf( 6));
+        assertEquals("UNDEFINED", Type.UNDEFINED, Type.valueOf( 7));
+        assertEquals("SHORT",     Type.SHORT,     Type.valueOf( 8));
+        assertEquals("INT",       Type.INT,       Type.valueOf( 9));
+        assertEquals("RATIONAL",  Type.RATIONAL,  Type.valueOf(10));     // signed Integer
/ signed Integer
+        assertEquals("FLOAT",     Type.FLOAT,     Type.valueOf(11));
+        assertEquals("DOUBLE",    Type.DOUBLE,    Type.valueOf(12));
+        assertEquals("IFD",       Type.UINT,      Type.valueOf(13));     // IFD is like UINT.
+        assertEquals("ULONG",     Type.ULONG,     Type.valueOf(16));
+        assertEquals("LONG",      Type.LONG,      Type.valueOf(17));
+        assertEquals("IFD8",      Type.ULONG,     Type.valueOf(18));     // IFD8 is like
ULONG.
+    }
+
+    /**
+     * Verifies values of the {@link Type#size} property.
+     */
+    @Test
+    public void verifySize() {
+        verifySize(Byte.SIZE,       Type.BYTE,  Type.UBYTE, Type.ASCII);
+        verifySize(Short.SIZE,      Type.SHORT, Type.USHORT);
+        verifySize(Integer.SIZE,    Type.INT,   Type.UINT);
+        verifySize(Long.SIZE,       Type.LONG,  Type.ULONG);
+        verifySize(Float.SIZE,      Type.FLOAT);
+        verifySize(Double.SIZE,     Type.DOUBLE);
+        verifySize(Integer.SIZE*2,  Type.URATIONAL, Type.RATIONAL);
+    }
+
+    /**
+     * Verifies that all given values have the expected size.
+     */
+    private static void verifySize(final int expected, final Type... values) {
+        for (final Type type : values) {
+            assertEquals(expected, type.size * Byte.SIZE);
+        }
+    }
+}

Propchange: sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/TypeTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/TypeTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Added: sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/test/suite/GeoTiffTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/test/suite/GeoTiffTestSuite.java?rev=1753881&view=auto
==============================================================================
--- sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/test/suite/GeoTiffTestSuite.java
(added)
+++ sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/test/suite/GeoTiffTestSuite.java
[UTF-8] Sat Jul 23 16:28:40 2016
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.test.suite;
+
+import org.apache.sis.test.TestSuite;
+import org.junit.runners.Suite;
+import org.junit.BeforeClass;
+
+
+/**
+ * All tests from the {@code sis-geotiff} module, in approximative dependency order.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.8
+ * @version 0.8
+ * @module
+ */
+@Suite.SuiteClasses({
+    org.apache.sis.storage.geotiff.TypeTest.class,
+    org.apache.sis.storage.geotiff.CompressionTest.class
+})
+public final strictfp class GeoTiffTestSuite extends TestSuite {
+    /**
+     * Verifies the list of tests before to run the suite.
+     * See {@link #verifyTestList(Class, Class[])} for more information.
+     */
+    @BeforeClass
+    public static void verifyTestList() {
+        assertNoMissingTest(GeoTiffTestSuite.class);
+        verifyTestList(GeoTiffTestSuite.class);
+    }
+}

Propchange: sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/test/suite/GeoTiffTestSuite.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/test/suite/GeoTiffTestSuite.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8




Mime
View raw message