1 /*
   2  * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package com.sun.imageio.plugins.tiff;
  26 
  27 import java.io.IOException;
  28 import javax.imageio.IIOException;
  29 import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
  30 
  31 class TIFFLZWDecompressor extends TIFFDecompressor {
  32 
  33     private static final int CLEAR_CODE = 256;
  34     private static final int EOI_CODE   = 257;
  35     private static final int FIRST_CODE = 258;
  36 
  37     private static final int andTable[] = {
  38         511,
  39         1023,
  40         2047,
  41         4095
  42     };
  43 
  44     private int predictor;
  45 
  46     // whether to reverse the bits in each byte of the input data, i.e.,
  47     // convert right-to-left fill order (lsb) to left-to-right (msb).
  48     private boolean flipBits;
  49 
  50     private byte[] srcData;
  51     private byte[] dstData;
  52 
  53     private int srcIndex;
  54     private int dstIndex;
  55 
  56     private byte stringTable[][];
  57     private int tableIndex, bitsToGet = 9;
  58 
  59     private int nextData = 0;
  60     private int nextBits = 0;
  61 
  62     public TIFFLZWDecompressor(int predictor, int fillOrder)
  63         throws IIOException {
  64         super();
  65 
  66         if (predictor != BaselineTIFFTagSet.PREDICTOR_NONE &&
  67             predictor !=
  68             BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) {
  69             throw new IIOException("Illegal value for Predictor in " +
  70                                    "TIFF file");
  71         }
  72 
  73         this.predictor = predictor;
  74 
  75         flipBits = fillOrder == BaselineTIFFTagSet.FILL_ORDER_RIGHT_TO_LEFT;
  76     }
  77 
  78     public void decodeRaw(byte[] b,
  79                           int dstOffset,
  80                           int bitsPerPixel,
  81                           int scanlineStride) throws IOException {
  82 
  83         // Check bitsPerSample.
  84         if (predictor ==
  85             BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) {
  86             int len = bitsPerSample.length;
  87             for(int i = 0; i < len; i++) {
  88                 if(bitsPerSample[i] != 8) {
  89                     throw new IIOException
  90                         (bitsPerSample[i] + "-bit samples "+
  91                          "are not supported for Horizontal "+
  92                          "differencing Predictor");
  93                 }
  94             }
  95         }
  96 
  97         stream.seek(offset);
  98 
  99         byte[] sdata = new byte[byteCount];
 100         stream.readFully(sdata);
 101 
 102         if (flipBits) {
 103             for (int i = 0; i < byteCount; i++) {
 104                 sdata[i] = TIFFFaxDecompressor.flipTable[sdata[i] & 0xff];
 105             }
 106         }
 107 
 108         int bytesPerRow = (srcWidth*bitsPerPixel + 7)/8;
 109         byte[] buf;
 110         int bufOffset;
 111         if(bytesPerRow == scanlineStride) {
 112             buf = b;
 113             bufOffset = dstOffset;
 114         } else {
 115             buf = new byte[bytesPerRow*srcHeight];
 116             bufOffset = 0;
 117         }
 118 
 119         int numBytesDecoded = decode(sdata, 0, buf, bufOffset);
 120 
 121         if(bytesPerRow != scanlineStride) {
 122             int off = 0;
 123             for (int y = 0; y < srcHeight; y++) {
 124                 System.arraycopy(buf, off, b, dstOffset, bytesPerRow);
 125                 off += bytesPerRow;
 126                 dstOffset += scanlineStride;
 127             }
 128         }
 129     }
 130 
 131     public int decode(byte[] sdata, int srcOffset,
 132                       byte[] ddata, int dstOffset)
 133         throws IOException {
 134         if (sdata[0] == (byte)0x00 && sdata[1] == (byte)0x01) {
 135             throw new IIOException
 136                 ("TIFF 5.0-style LZW compression is not supported!");
 137         }
 138 
 139         this.srcData = sdata;
 140         this.dstData = ddata;
 141 
 142         this.srcIndex = srcOffset;
 143         this.dstIndex = dstOffset;
 144 
 145         this.nextData = 0;
 146         this.nextBits = 0;
 147 
 148         initializeStringTable();
 149 
 150         int code, oldCode = 0;
 151         byte[] string;
 152 
 153         while ((code = getNextCode()) != EOI_CODE) {
 154             if (code == CLEAR_CODE) {
 155                 initializeStringTable();
 156                 code = getNextCode();
 157                 if (code == EOI_CODE) {
 158                     break;
 159                 }
 160 
 161                 writeString(stringTable[code]);
 162                 oldCode = code;
 163             } else {
 164                 if (code < tableIndex) {
 165                     string = stringTable[code];
 166 
 167                     writeString(string);
 168                     addStringToTable(stringTable[oldCode], string[0]);
 169                     oldCode = code;
 170                 } else {
 171                     string = stringTable[oldCode];
 172                     string = composeString(string, string[0]);
 173                     writeString(string);
 174                     addStringToTable(string);
 175                     oldCode = code;
 176                 }
 177             }
 178         }
 179 
 180         if (predictor ==
 181             BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) {
 182             int step = planar || samplesPerPixel == 1 ? 1 : samplesPerPixel;
 183 
 184             int samplesPerRow = step * srcWidth;
 185 
 186             int off = dstOffset + step;
 187             for (int j = 0; j < srcHeight; j++) {
 188                 int count = off;
 189                 for (int i = step; i < samplesPerRow; i++) {
 190                     dstData[count] += dstData[count - step];
 191                     count++;
 192                 }
 193                 off += samplesPerRow;
 194             }
 195         }
 196 
 197         return dstIndex - dstOffset;
 198     }
 199 
 200     /**
 201      * Initialize the string table.
 202      */
 203     public void initializeStringTable() {
 204         stringTable = new byte[4096][];
 205 
 206         for (int i = 0; i < CLEAR_CODE; i++) {
 207             stringTable[i] = new byte[1];
 208             stringTable[i][0] = (byte)i;
 209         }
 210 
 211         tableIndex = FIRST_CODE;
 212         bitsToGet = 9;
 213     }
 214 
 215     /**
 216      * Write out the string just uncompressed.
 217      */
 218     public void writeString(byte string[]) {
 219         if(dstIndex < dstData.length) {
 220             int maxIndex = Math.min(string.length,
 221                                     dstData.length - dstIndex);
 222 
 223             for (int i=0; i < maxIndex; i++) {
 224                 dstData[dstIndex++] = string[i];
 225             }
 226         }
 227     }
 228 
 229     /**
 230      * Add a new string to the string table.
 231      */
 232     public void addStringToTable(byte oldString[], byte newString) {
 233         int length = oldString.length;
 234         byte string[] = new byte[length + 1];
 235         System.arraycopy(oldString, 0, string, 0, length);
 236         string[length] = newString;
 237 
 238         // Add this new String to the table
 239         stringTable[tableIndex++] = string;
 240 
 241         if (tableIndex == 511) {
 242             bitsToGet = 10;
 243         } else if (tableIndex == 1023) {
 244             bitsToGet = 11;
 245         } else if (tableIndex == 2047) {
 246             bitsToGet = 12;
 247         }
 248     }
 249 
 250     /**
 251      * Add a new string to the string table.
 252      */
 253     public void addStringToTable(byte string[]) {
 254         // Add this new String to the table
 255         stringTable[tableIndex++] = string;
 256 
 257         if (tableIndex == 511) {
 258             bitsToGet = 10;
 259         } else if (tableIndex == 1023) {
 260             bitsToGet = 11;
 261         } else if (tableIndex == 2047) {
 262             bitsToGet = 12;
 263         }
 264     }
 265 
 266     /**
 267      * Append {@code newString} to the end of {@code oldString}.
 268      */
 269     public byte[] composeString(byte oldString[], byte newString) {
 270         int length = oldString.length;
 271         byte string[] = new byte[length + 1];
 272         System.arraycopy(oldString, 0, string, 0, length);
 273         string[length] = newString;
 274 
 275         return string;
 276     }
 277 
 278     // Returns the next 9, 10, 11 or 12 bits
 279     public int getNextCode() {
 280         // Attempt to get the next code. The exception is caught to make
 281         // this robust to cases wherein the EndOfInformation code has been
 282         // omitted from a strip. Examples of such cases have been observed
 283         // in practice.
 284 
 285         try {
 286             nextData = (nextData << 8) | (srcData[srcIndex++] & 0xff);
 287             nextBits += 8;
 288 
 289             if (nextBits < bitsToGet) {
 290                 nextData = (nextData << 8) | (srcData[srcIndex++] & 0xff);
 291                 nextBits += 8;
 292             }
 293 
 294             int code =
 295                 (nextData >> (nextBits - bitsToGet)) & andTable[bitsToGet - 9];
 296             nextBits -= bitsToGet;
 297 
 298             return code;
 299         } catch (ArrayIndexOutOfBoundsException e) {
 300             // Strip not terminated as expected: return EndOfInformation code.
 301             return EOI_CODE;
 302         }
 303     }
 304 }