Open Source Repository

Home /itextpdf/itextpdf-5.1.2 | Repository Home



com/itextpdf/text/pdf/codec/TIFFFaxDecompressor.java
/*
 * Copyright 2003-2009 by Paulo Soares.
 *
 * This code was originally released in 2001 by SUN (see class
 * com.sun.media.imageioimpl.plugins.tiff.TIFFFaxDecompressor.java)
 * using the BSD license in a specific wording. In a mail dating from
 * January 23, 2008, Brian Burkhalter (@sun.com) gave us permission
 * to use the code under the following version of the BSD license:
 *
 * Copyright (c) 2005 Sun Microsystems, Inc. All  Rights Reserved.
 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met: 
 
 * - Redistribution of source code must retain the above copyright 
 *   notice, this  list of conditions and the following disclaimer.
 
 * - Redistribution in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in 
 *   the documentation and/or other materials provided with the
 *   distribution.
 
 * Neither the name of Sun Microsystems, Inc. or the names of 
 * contributors may be used to endorse or promote products derived 
 * from this software without specific prior written permission.
 
 * This software is provided "AS IS," without a warranty of any 
 * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND 
 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
 * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL 
 * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF 
 * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR 
 * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
 * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
 * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
 * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES. 
 
 * You acknowledge that this software is not designed or intended for 
 * use in the design, construction, operation or maintenance of any 
 * nuclear facility. 
 *
 * $Revision: 4540 $
 * $Date: 2010-07-13 14:57:54 +0200 (di, 13 jul 2010) $
 * $State: Exp $
 */
package com.itextpdf.text.pdf.codec;

//import com.itextpdf.text.error_messages.MessageLocalization;

/**
 * Class that can decompress TIFF files.
 @since 5.0.3
 */
public class TIFFFaxDecompressor {

    /**
     * The logical order of bits within a byte.
     <pre>
     * 1 = MSB-to-LSB
     * 2 = LSB-to-MSB (flipped)
     </pre>
     */
    protected int fillOrder;
    protected int compression;
    private int t4Options;
    private int t6Options;
    public int fails;
    // Variables set by T4Options
    /**
     * Uncompressed mode flag: 1 if uncompressed, 0 if not.
     */
    protected int uncompressedMode = 0;
    /**
     * EOL padding flag: 1 if fill bits have been added before an EOL such
     * that the EOL ends on a byte boundary, 0 otherwise.
     */
    protected int fillBits = 0;
    /**
     * Coding dimensionality: 1 for 2-dimensional, 0 for 1-dimensional.
     */
    protected int oneD;
    private byte[] data;
    private int bitPointer, bytePointer;
    // Output image buffer
    private byte[] buffer;
    private int w, h, bitsPerScanline;
    private int lineBitNum;
    // Data structures needed to store changing elements for the previous
    // and the current scanline
    private int changingElemSize = 0;
    private int prevChangingElems[];
    private int currChangingElems[];
    // Element at which to start search in getNextChangingElement
    private int lastChangingElement = 0;
    static int table1[] {
        0x00// 0 bits are left in first byte - SHOULD NOT HAPPEN
        0x01// 1 bits are left in first byte
        0x03// 2 bits are left in first byte
        0x07// 3 bits are left in first byte
        0x0f// 4 bits are left in first byte
        0x1f// 5 bits are left in first byte
        0x3f// 6 bits are left in first byte
        0x7f// 7 bits are left in first byte
        0xff // 8 bits are left in first byte
    };
    static int table2[] {
        0x00// 0
        0x80// 1
        0xc0// 2
        0xe0// 3
        0xf0// 4
        0xf8// 5
        0xfc// 6
        0xfe// 7
        0xff // 8
    };
    // Table to be used when fillOrder = 2, for flipping bytes.
    static byte flipTable[] {
        0, -12864, -6432, -9696, -32,
        16, -11280, -4848, -80112, -16,
        8, -12072, -5640, -88104, -24,
        24, -10488, -4056, -72120, -8,
        4, -12468, -6036, -92100, -28,
        20, -10884, -4452, -76116, -12,
        12, -11676, -5244, -84108, -20,
        28, -10092, -3660, -68124, -4,
        2, -12666, -6234, -9498, -30,
        18, -11082, -4650, -78114, -14,
        10, -11874, -5442, -86106, -22,
        26, -10290, -3858, -70122, -6,
        6, -12270, -5838, -90102, -26,
        22, -10686, -4254, -74118, -10,
        14, -11478, -5046, -82110, -18,
        30, -9894, -3462, -66126, -2,
        1, -12765, -6333, -9597, -31,
        17, -11181, -4749, -79113, -15,
        9, -11973, -5541, -87105, -23,
        25, -10389, -3957, -71121, -7,
        5, -12369, -5937, -91101, -27,
        21, -10785, -4353, -75117, -11,
        13, -11577, -5145, -83109, -19,
        29, -9993, -3561, -67125, -3,
        3, -12567, -6135, -9399, -29,
        19, -10983, -4551, -77115, -13,
        11, -11775, -5343, -85107, -21,
        27, -10191, -3759, -69123, -5,
        7, -12171, -5739, -89103, -25,
        23, -10587, -4155, -73119, -9,
        15, -11379, -4947, -81111, -17,
        31, -9795, -3363, -65127, -1,};
    // The main 10 bit white runs lookup table
    static short white[] {
        // 0 - 7
        64306400640064003225322532253225,
        // 8 - 15
        944944944944976976976976,
        // 16 - 23
        14561456145614561488148814881488,
        // 24 - 31
        718718718718718718718718,
        // 32 - 39
        750750750750750750750750,
        // 40 - 47
        15201520152015201552155215521552,
        // 48 - 55
        428428428428428428428428,
        // 56 - 63
        428428428428428428428428,
        // 64 - 71
        654654654654654654654654,
        // 72 - 79
        10721072107210721104110411041104,
        // 80 - 87
        11361136113611361168116811681168,
        // 88 - 95
        12001200120012001232123212321232,
        // 96 - 103
        622622622622622622622622,
        // 104 - 111
        10081008100810081040104010401040,
        // 112 - 119
        4444444444444444,
        // 120 - 127
        4444444444444444,
        // 128 - 135
        396396396396396396396396,
        // 136 - 143
        396396396396396396396396,
        // 144 - 151
        17121712171217121744174417441744,
        // 152 - 159
        846846846846846846846846,
        // 160 - 167
        12641264126412641296129612961296,
        // 168 - 175
        13281328132813281360136013601360,
        // 176 - 183
        13921392139213921424142414241424,
        // 184 - 191
        686686686686686686686686,
        // 192 - 199
        910910910910910910910910,
        // 200 - 207
        19681968196819682000200020002000,
        // 208 - 215
        203220322032203216161616,
        // 216 - 223
        1025710257102571025712305123051230512305,
        // 224 - 231
        330330330330330330330330,
        // 232 - 239
        330330330330330330330330,
        // 240 - 247
        330330330330330330330330,
        // 248 - 255
        330330330330330330330330,
        // 256 - 263
        362362362362362362362362,
        // 264 - 271
        362362362362362362362362,
        // 272 - 279
        362362362362362362362362,
        // 280 - 287
        362362362362362362362362,
        // 288 - 295
        878878878878878878878878,
        // 296 - 303
        19041904190419041936193619361936,
        // 304 - 311
        -18413, -18413, -16365, -16365, -14317, -14317, -10221, -10221,
        // 312 - 319
        590590590590590590590590,
        // 320 - 327
        782782782782782782782782,
        // 328 - 335
        15841584158415841616161616161616,
        // 336 - 343
        16481648164816481680168016801680,
        // 344 - 351
        814814814814814814814814,
        // 352 - 359
        17761776177617761808180818081808,
        // 360 - 367
        18401840184018401872187218721872,
        // 368 - 375
        61576157615761576157615761576157,
        // 376 - 383
        61576157615761576157615761576157,
        // 384 - 391
        -12275, -12275, -12275, -12275, -12275, -12275, -12275, -12275,
        // 392 - 399
        -12275, -12275, -12275, -12275, -12275, -12275, -12275, -12275,
        // 400 - 407
        1435314353143531435316401164011640116401,
        // 408 - 415
        2254722547245952459520497204972049720497,
        // 416 - 423
        1844918449184491844926643266432869128691,
        // 424 - 431
        3073930739, -32749, -32749, -30701, -30701, -28653, -28653,
        // 432 - 439
        -26605, -26605, -24557, -24557, -22509, -22509, -20461, -20461,
        // 440 - 447
        82078207820782078207820782078207,
        // 448 - 455
        7272727272727272,
        // 456 - 463
        7272727272727272,
        // 464 - 471
        7272727272727272,
        // 472 - 479
        7272727272727272,
        // 480 - 487
        7272727272727272,
        // 488 - 495
        7272727272727272,
        // 496 - 503
        7272727272727272,
        // 504 - 511
        7272727272727272,
        // 512 - 519
        104104104104104104104104,
        // 520 - 527
        104104104104104104104104,
        // 528 - 535
        104104104104104104104104,
        // 536 - 543
        104104104104104104104104,
        // 544 - 551
        104104104104104104104104,
        // 552 - 559
        104104104104104104104104,
        // 560 - 567
        104104104104104104104104,
        // 568 - 575
        104104104104104104104104,
        // 576 - 583
        41074107410741074107410741074107,
        // 584 - 591
        41074107410741074107410741074107,
        // 592 - 599
        41074107410741074107410741074107,
        // 600 - 607
        41074107410741074107410741074107,
        // 608 - 615
        266266266266266266266266,
        // 616 - 623
        266266266266266266266266,
        // 624 - 631
        266266266266266266266266,
        // 632 - 639
        266266266266266266266266,
        // 640 - 647
        298298298298298298298298,
        // 648 - 655
        298298298298298298298298,
        // 656 - 663
        298298298298298298298298,
        // 664 - 671
        298298298298298298298298,
        // 672 - 679
        524524524524524524524524,
        // 680 - 687
        524524524524524524524524,
        // 688 - 695
        556556556556556556556556,
        // 696 - 703
        556556556556556556556556,
        // 704 - 711
        136136136136136136136136,
        // 712 - 719
        136136136136136136136136,
        // 720 - 727
        136136136136136136136136,
        // 728 - 735
        136136136136136136136136,
        // 736 - 743
        136136136136136136136136,
        // 744 - 751
        136136136136136136136136,
        // 752 - 759
        136136136136136136136136,
        // 760 - 767
        136136136136136136136136,
        // 768 - 775
        168168168168168168168168,
        // 776 - 783
        168168168168168168168168,
        // 784 - 791
        168168168168168168168168,
        // 792 - 799
        168168168168168168168168,
        // 800 - 807
        168168168168168168168168,
        // 808 - 815
        168168168168168168168168,
        // 816 - 823
        168168168168168168168168,
        // 824 - 831
        168168168168168168168168,
        // 832 - 839
        460460460460460460460460,
        // 840 - 847
        460460460460460460460460,
        // 848 - 855
        492492492492492492492492,
        // 856 - 863
        492492492492492492492492,
        // 864 - 871
        20592059205920592059205920592059,
        // 872 - 879
        20592059205920592059205920592059,
        // 880 - 887
        20592059205920592059205920592059,
        // 888 - 895
        20592059205920592059205920592059,
        // 896 - 903
        200200200200200200200200,
        // 904 - 911
        200200200200200200200200,
        // 912 - 919
        200200200200200200200200,
        // 920 - 927
        200200200200200200200200,
        // 928 - 935
        200200200200200200200200,
        // 936 - 943
        200200200200200200200200,
        // 944 - 951
        200200200200200200200200,
        // 952 - 959
        200200200200200200200200,
        // 960 - 967
        232232232232232232232232,
        // 968 - 975
        232232232232232232232232,
        // 976 - 983
        232232232232232232232232,
        // 984 - 991
        232232232232232232232232,
        // 992 - 999
        232232232232232232232232,
        // 1000 - 1007
        232232232232232232232232,
        // 1008 - 1015
        232232232232232232232232,
        // 1016 - 1023
        232232232232232232232232,};
    // Additional make up codes for both White and Black runs
    static short additionalMakeup[] {
        286792867931752(short32777,
        (short33801(short34825(short35849(short36873,
        (short29703(short29703(short30727(short30727,
        (short37897(short38921(short39945(short40969
    };
    // Initial black run look up table, uses the first 4 bits of a code
    static short initBlack[] {
        // 0 - 7
        322664122001683838134134,
        // 8 - 15
        10010010010068686868
    };
    // 
    static short twoBitBlack[] {292260226226};   // 0 - 3
    // Main black run table, using the last 9 bits of possible 13 bit code
    static short black[] {
        // 0 - 7
        626230300000,
        // 8 - 15
        00000000,
        // 16 - 23
        00000000,
        // 24 - 31
        00000000,
        // 32 - 39
        32253225322532253225322532253225,
        // 40 - 47
        32253225322532253225322532253225,
        // 48 - 55
        32253225322532253225322532253225,
        // 56 - 63
        32253225322532253225322532253225,
        // 64 - 71
        588588588588588588588588,
        // 72 - 79
        168016802049922547245952664317761776,
        // 80 - 87
        18081808, -24557, -22509, -20461, -1841319041904,
        // 88 - 95
        19361936, -16365, -14317782782782782,
        // 96 - 103
        814814814814, -12269, -102211025710257,
        // 104 - 111
        12305123051435314353164031845117121712,
        // 112 - 119
        174417442869130739, -32749, -30701, -28653, -26605,
        // 120 - 127
        20612061206120612061206120612061,
        // 128 - 135
        424424424424424424424424,
        // 136 - 143
        424424424424424424424424,
        // 144 - 151
        424424424424424424424424,
        // 152 - 159
        424424424424424424424424,
        // 160 - 167
        7507507507501616161616481648,
        // 168 - 175
        14241424145614561488148815201520,
        // 176 - 183
        18401840187218721968196882098209,
        // 184 - 191
        524524524524524524524524,
        // 192 - 199
        556556556556556556556556,
        // 200 - 207
        15521552158415842000200020322032,
        // 208 - 215
        976976100810081040104010721072,
        // 216 - 223
        1296129613281328718718718718,
        // 224 - 231
        456456456456456456456456,
        // 232 - 239
        456456456456456456456456,
        // 240 - 247
        456456456456456456456456,
        // 248 - 255
        456456456456456456456456,
        // 256 - 263
        326326326326326326326326,
        // 264 - 271
        326326326326326326326326,
        // 272 - 279
        326326326326326326326326,
        // 280 - 287
        326326326326326326326326,
        // 288 - 295
        326326326326326326326326,
        // 296 - 303
        326326326326326326326326,
        // 304 - 311
        326326326326326326326326,
        // 312 - 319
        326326326326326326326326,
        // 320 - 327
        358358358358358358358358,
        // 328 - 335
        358358358358358358358358,
        // 336 - 343
        358358358358358358358358,
        // 344 - 351
        358358358358358358358358,
        // 352 - 359
        358358358358358358358358,
        // 360 - 367
        358358358358358358358358,
        // 368 - 375
        358358358358358358358358,
        // 376 - 383
        358358358358358358358358,
        // 384 - 391
        490490490490490490490490,
        // 392 - 399
        490490490490490490490490,
        // 400 - 407
        4113411361616161848848880880,
        // 408 - 415
        912912944944622622622622,
        // 416 - 423
        6546546546541104110411361136,
        // 424 - 431
        11681168120012001232123212641264,
        // 432 - 439
        6866866866861360136013921392,
        // 440 - 447
        1212121212121212,
        // 448 - 455
        390390390390390390390390,
        // 456 - 463
        390390390390390390390390,
        // 464 - 471
        390390390390390390390390,
        // 472 - 479
        390390390390390390390390,
        // 480 - 487
        390390390390390390390390,
        // 488 - 495
        390390390390390390390390,
        // 496 - 503
        390390390390390390390390,
        // 504 - 511
        390390390390390390390390,};
    static byte twoDCodes[] {
        // 0 - 7
        8088237130306262,
        // 8 - 15
        44444444,
        // 16 - 23
        1111111111111111,
        // 24 - 31
        1111111111111111,
        // 32 - 39
        3535353535353535,
        // 40 - 47
        3535353535353535,
        // 48 - 55
        5151515151515151,
        // 56 - 63
        5151515151515151,
        // 64 - 71
        4141414141414141,
        // 72 - 79
        4141414141414141,
        // 80 - 87
        4141414141414141,
        // 88 - 95
        4141414141414141,
        // 96 - 103
        4141414141414141,
        // 104 - 111
        4141414141414141,
        // 112 - 119
        4141414141414141,
        // 120 - 127
        4141414141414141,};

    public TIFFFaxDecompressor() {
    }

    /**
     * Invokes the superclass method and then sets instance variables on
     * the basis of the metadata set on this decompressor.
     */
    public void SetOptions(int fillOrder, int compression, int t4Options, int t6Options) {
        this.fillOrder = fillOrder;
        this.compression = compression;
        this.t4Options = t4Options;
        this.t6Options = t6Options;
        this.oneD = (int) (t4Options & 0x01);
        this.uncompressedMode = (int) ((t4Options & 0x02>> 1);
        this.fillBits = (int) ((t4Options & 0x04>> 2);
    }

    public void decodeRaw(byte[] buffer, byte[] compData, int w, int h) {

        this.buffer = buffer;
        this.data = compData;
        this.w = w;
        this.h = h;
        this.bitsPerScanline = w;
        this.lineBitNum = 0;

        this.bitPointer = 0;
        this.bytePointer = 0;
        this.prevChangingElems = new int[w + 1];
        this.currChangingElems = new int[w + 1];

        fails = 0;

        try {
            if (compression == TIFFConstants.COMPRESSION_CCITTRLE) {
                decodeRLE();
            else if (compression == TIFFConstants.COMPRESSION_CCITTFAX3) {
                decodeT4();
            else if (compression == TIFFConstants.COMPRESSION_CCITTFAX4) {
                this.uncompressedMode = (int) ((t6Options & 0x02>> 1);
                decodeT6();
            else {
                throw new RuntimeException("Unknown compression type " + compression);
            }
        catch (ArrayIndexOutOfBoundsException e) {
            //ignore
        }
    }

    public void decodeRLE() {
        for (int i = 0; i < h; i++) {
            // Decode the line.
            decodeNextScanline();

            // Advance to the next byte boundary if not already there.
            if (bitPointer != 0) {
                bytePointer++;
                bitPointer = 0;
            }

            // Update the total number of bits.
            lineBitNum += bitsPerScanline;
        }
    }

    public void decodeNextScanline() {
        int bits = 0, code = 0, isT = 0;
        int current, entry, twoBits;
        boolean isWhite = true;

        int bitOffset = 0;

        // Initialize starting of the changing elements array
        changingElemSize = 0;

        // While scanline not complete
        while (bitOffset < w) {

            // Mark start of white run.
            int runOffset = bitOffset;

            while (isWhite && bitOffset < w) {
                // White run
                current = nextNBits(10);
                entry = white[current];

                // Get the 3 fields from the entry
                isT = entry & 0x0001;
                bits = (entry >>> 10x0f;

                if (bits == 12) {          // Additional Make up code
                    // Get the next 2 bits
                    twoBits = nextLesserThan8Bits(2);
                    // Consolidate the 2 new bits and last 2 bits into 4 bits
                    current = ((current << 20x000c| twoBits;
                    entry = additionalMakeup[current];
                    bits = (entry >>> 10x07;     // 3 bits 0000 0111
                    code = (entry >>> 40x0fff;  // 12 bits
                    bitOffset += code; // Skip white run

                    updatePointer(- bits);
                else if (bits == 0) {     // ERROR
                    ++fails;
                    // XXX return?
                else if (bits == 15) {    // EOL
                    //
                    // Instead of throwing an exception, assume that the
                    // EOL was premature; emit a warning and return.
                    //
                    ++fails;
                    return;
                else {
                    // 11 bits - 0000 0111 1111 1111 = 0x07ff
                    code = (entry >>> 50x07ff;
                    bitOffset += code;

                    updatePointer(10 - bits);
                    if (isT == 0) {
                        isWhite = false;
                        currChangingElems[changingElemSize++= bitOffset;
                    }
                }
            }

            // Check whether this run completed one width
            if (bitOffset == w) {
                // If the white run has not been terminated then ensure that
                // the next code word is a terminating code for a white run
                // of length zero.
                int runLength = bitOffset - runOffset;
                if (isWhite
                        && runLength != && runLength % 64 == 0
                        && nextNBits(8!= 0x35) {
                    ++fails;
                    updatePointer(8);
                }
                break;
            }

            // Mark start of black run.
            runOffset = bitOffset;

            while (isWhite == false && bitOffset < w) {
                // Black run
                current = nextLesserThan8Bits(4);
                entry = initBlack[current];

                // Get the 3 fields from the entry
                isT = entry & 0x0001;
                bits = (entry >>> 10x000f;
                code = (entry >>> 50x07ff;

                if (code == 100) {
                    current = nextNBits(9);
                    entry = black[current];

                    // Get the 3 fields from the entry
                    isT = entry & 0x0001;
                    bits = (entry >>> 10x000f;
                    code = (entry >>> 50x07ff;

                    if (bits == 12) {
                        // Additional makeup codes
                        updatePointer(5);
                        current = nextLesserThan8Bits(4);
                        entry = additionalMakeup[current];
                        bits = (entry >>> 10x07;     // 3 bits 0000 0111
                        code = (entry >>> 40x0fff;  // 12 bits

                        setToBlack(bitOffset, code);
                        bitOffset += code;

                        updatePointer(- bits);
                    else if (bits == 15) {
                        //
                        // Instead of throwing an exception, assume that the
                        // EOL was premature; emit a warning and return.
                        //
                        ++fails;
                        return;
                    else {
                        setToBlack(bitOffset, code);
                        bitOffset += code;

                        updatePointer(- bits);
                        if (isT == 0) {
                            isWhite = true;
                            currChangingElems[changingElemSize++= bitOffset;
                        }
                    }
                else if (code == 200) {
                    // Is a Terminating code
                    current = nextLesserThan8Bits(2);
                    entry = twoBitBlack[current];
                    code = (entry >>> 50x07ff;
                    bits = (entry >>> 10x0f;

                    setToBlack(bitOffset, code);
                    bitOffset += code;

                    updatePointer(- bits);
                    isWhite = true;
                    currChangingElems[changingElemSize++= bitOffset;
                else {
                    // Is a Terminating code
                    setToBlack(bitOffset, code);
                    bitOffset += code;

                    updatePointer(- bits);
                    isWhite = true;
                    currChangingElems[changingElemSize++= bitOffset;
                }
            }

            // Check whether this run completed one width
            if (bitOffset == w) {
                // If the black run has not been terminated then ensure that
                // the next code word is a terminating code for a black run
                // of length zero.
                int runLength = bitOffset - runOffset;
                if (!isWhite
                        && runLength != && runLength % 64 == 0
                        && nextNBits(10!= 0x37) {
                    ++fails;
                    updatePointer(10);
                }
                break;
            }
        }

        currChangingElems[changingElemSize++= bitOffset;
    }

    public void decodeT4() {
        int height = h;

        int a0, a1, b1, b2;
        int[] b = new int[2];
        int entry, code, bits, color;
        boolean isWhite;
        int currIndex = 0;
        int temp[];

        if (data.length < 2) {
            throw new RuntimeException("Insufficient data to read initial EOL.");
        }

        // The data should start with an EOL code
        int next12 = nextNBits(12);
        if (next12 != 1) {
            ++fails;
        }
        updatePointer(12);

        // Find the first one-dimensionally encoded line.
        int modeFlag = 0;
        int lines = -1// indicates imaginary line before first actual line.
        while (modeFlag != 1) {
            try {
                modeFlag = findNextLine();
                lines++; // Normally 'lines' will be 0 on exiting loop.
            catch (Exception eofe) {
                throw new RuntimeException("No reference line present.");
            }
        }

        int bitOffset;

        // Then the 1D encoded scanline data will occur, changing elements
        // array gets set.
        decodeNextScanline();
        lines++;
        lineBitNum += bitsPerScanline;

        while (lines < height) {

            // Every line must begin with an EOL followed by a bit which
            // indicates whether the following scanline is 1D or 2D encoded.
            try {
                modeFlag = findNextLine();
            catch (Exception eofe) {
                ++fails;
                break;
            }
            if (modeFlag == 0) {
                // 2D encoded scanline follows

                // Initialize previous scanlines changing elements, and
                // initialize current scanline's changing elements array
                temp = prevChangingElems;
                prevChangingElems = currChangingElems;
                currChangingElems = temp;
                currIndex = 0;

                // a0 has to be set just before the start of this scanline.
                a0 = -1;
                isWhite = true;
                bitOffset = 0;

                lastChangingElement = 0;

                while (bitOffset < w) {
                    // Get the next changing element
                    getNextChangingElement(a0, isWhite, b);

                    b1 = b[0];
                    b2 = b[1];

                    // Get the next seven bits
                    entry = nextLesserThan8Bits(7);

                    // Run these through the 2DCodes table
                    entry = (int) (twoDCodes[entry0xff);

                    // Get the code and the number of bits used up
                    code = (entry & 0x78>>> 3;
                    bits = entry & 0x07;

                    if (code == 0) {
                        if (!isWhite) {
                            setToBlack(bitOffset, b2 - bitOffset);
                        }
                        bitOffset = a0 = b2;

                        // Set pointer to consume the correct number of bits.
                        updatePointer(- bits);
                    else if (code == 1) {
                        // Horizontal
                        updatePointer(- bits);

                        // identify the next 2 codes.
                        int number;
                        if (isWhite) {
                            number = decodeWhiteCodeWord();
                            bitOffset += number;
                            currChangingElems[currIndex++= bitOffset;

                            number = decodeBlackCodeWord();
                            setToBlack(bitOffset, number);
                            bitOffset += number;
                            currChangingElems[currIndex++= bitOffset;
                        else {
                            number = decodeBlackCodeWord();
                            setToBlack(bitOffset, number);
                            bitOffset += number;
                            currChangingElems[currIndex++= bitOffset;

                            number = decodeWhiteCodeWord();
                            bitOffset += number;
                            currChangingElems[currIndex++= bitOffset;
                        }

                        a0 = bitOffset;
                    else if (code <= 8) {
                        // Vertical
                        a1 = b1 + (code - 5);

                        currChangingElems[currIndex++= a1;

                        // We write the current color till a1 - 1 pos,
                        // since a1 is where the next color starts
                        if (!isWhite) {
                            setToBlack(bitOffset, a1 - bitOffset);
                        }
                        bitOffset = a0 = a1;
                        isWhite = !isWhite;

                        updatePointer(- bits);
                    else {
                        ++fails;
                        // Find the next one-dimensionally encoded line.
                        int numLinesTested = 0;
                        while (modeFlag != 1) {
                            try {
                                modeFlag = findNextLine();
                                numLinesTested++;
                            catch (Exception eofe) {
                                return;
                            }
                        }
                        lines += numLinesTested - 1;
                        updatePointer(13);
                        break;
                    }
                }

                // Add the changing element beyond the current scanline for the
                // other color too
                currChangingElems[currIndex++= bitOffset;
                changingElemSize = currIndex;
            else // modeFlag == 1
                // 1D encoded scanline follows
                decodeNextScanline();
            }

            lineBitNum += bitsPerScanline;
            lines++;
        // while(lines < height)
    }

    public synchronized void decodeT6() {
        int height = h;


        int a0, a1, b1, b2;
        int entry, code, bits;
        boolean isWhite;
        int currIndex;
        int temp[];

        // Return values from getNextChangingElement
        int[] b = new int[2];

        // uncompressedMode - have written some code for this, but this
        // has not been tested due to lack of test images using this optional
        // extension. This code is when code == 11. aastha 03/03/1999

        // Local cached reference
        int[] cce = currChangingElems;

        // Assume invisible preceding row of all white pixels and insert
        // both black and white changing elements beyond the end of this
        // imaginary scanline.
        changingElemSize = 0;
        cce[changingElemSize++= w;
        cce[changingElemSize++= w;

        int bitOffset;

        for (int lines = 0; lines < height; lines++) {
            // a0 has to be set just before the start of the scanline.
            a0 = -1;
            isWhite = true;

            // Assign the changing elements of the previous scanline to
            // prevChangingElems and start putting this new scanline's
            // changing elements into the currChangingElems.
            temp = prevChangingElems;
            prevChangingElems = currChangingElems;
            cce = currChangingElems = temp;
            currIndex = 0;

            // Start decoding the scanline
            bitOffset = 0;

            // Reset search start position for getNextChangingElement
            lastChangingElement = 0;

            // Till one whole scanline is decoded
            while (bitOffset < w) {
                // Get the next changing element
                getNextChangingElement(a0, isWhite, b);
                b1 = b[0];
                b2 = b[1];

                // Get the next seven bits
                entry = nextLesserThan8Bits(7);
                // Run these through the 2DCodes table
                entry = (int) (twoDCodes[entry0xff);

                // Get the code and the number of bits used up
                code = (entry & 0x78>>> 3;
                bits = entry & 0x07;

                if (code == 0) { // Pass
                    // We always assume WhiteIsZero format for fax.
                    if (!isWhite) {
                        if (b2 > w) {
                            b2 = w;
                        }
                        setToBlack(bitOffset, b2 - bitOffset);
                    }
                    bitOffset = a0 = b2;

                    // Set pointer to only consume the correct number of bits.
                    updatePointer(- bits);
                else if (code == 1) { // Horizontal
                    // Set pointer to only consume the correct number of bits.
                    updatePointer(- bits);

                    // identify the next 2 alternating color codes.
                    int number;
                    if (isWhite) {
                        // Following are white and black runs
                        number = decodeWhiteCodeWord();
                        bitOffset += number;
                        cce[currIndex++= bitOffset;

                        number = decodeBlackCodeWord();
                        if (number > w - bitOffset) {
                            number = w - bitOffset;
                        }
                        setToBlack(bitOffset, number);
                        bitOffset += number;
                        cce[currIndex++= bitOffset;
                    else {
                        // First a black run and then a white run follows
                        number = decodeBlackCodeWord();
                        if (number > w - bitOffset) {
                            number = w - bitOffset;
                        }
                        setToBlack(bitOffset, number);
                        bitOffset += number;
                        cce[currIndex++= bitOffset;

                        number = decodeWhiteCodeWord();
                        bitOffset += number;
                        cce[currIndex++= bitOffset;
                    }

                    a0 = bitOffset;
                else if (code <= 8) { // Vertical
                    a1 = b1 + (code - 5);
                    cce[currIndex++= a1;

                    // We write the current color till a1 - 1 pos,
                    // since a1 is where the next color starts
                    if (!isWhite) {
                        if (a1 > w) {
                            a1 = w;
                        }
                        setToBlack(bitOffset, a1 - bitOffset);
                    }
                    bitOffset = a0 = a1;
                    isWhite = !isWhite;

                    updatePointer(- bits);
                else if (code == 11) {
                    int entranceCode = nextLesserThan8Bits(3);

                    int zeros = 0;
                    boolean exit = false;

                    while (!exit) {
                        while (nextLesserThan8Bits(1!= 1) {
                            zeros++;
                        }

                        if (zeros > 5) {
                            // Exit code

                            // Zeros before exit code
                            zeros = zeros - 6;

                            if (!isWhite && (zeros > 0)) {
                                cce[currIndex++= bitOffset;
                            }

                            // Zeros before the exit code
                            bitOffset += zeros;
                            if (zeros > 0) {
                                // Some zeros have been written
                                isWhite = true;
                            }

                            // Read in the bit which specifies the color of
                            // the following run
                            if (nextLesserThan8Bits(1== 0) {
                                if (!isWhite) {
                                    cce[currIndex++= bitOffset;
                                }
                                isWhite = true;
                            else {
                                if (isWhite) {
                                    cce[currIndex++= bitOffset;
                                }
                                isWhite = false;
                            }

                            exit = true;
                        }

                        if (zeros == 5) {
                            if (!isWhite) {
                                cce[currIndex++= bitOffset;
                            }
                            bitOffset += zeros;

                            // Last thing written was white
                            isWhite = true;
                        else {
                            bitOffset += zeros;

                            cce[currIndex++= bitOffset;
                            setToBlack(bitOffset, 1);
                            ++bitOffset;

                            // Last thing written was black
                            isWhite = false;
                        }

                    }
                }
            // while bitOffset < w

            // Add the changing element beyond the current scanline for the
            // other color too, if not already added previously
            if (currIndex <= w)
                cce[currIndex++= bitOffset;

            // Number of changing elements in this scanline.
            changingElemSize = currIndex;

            lineBitNum += bitsPerScanline;
        // for lines < height
    }

    private void setToBlack(int bitNum, int numBits) {
        // bitNum is relative to current scanline so bump it by lineBitNum
        bitNum += lineBitNum;

        int lastBit = bitNum + numBits;
        int byteNum = bitNum >> 3;

        // Handle bits in first byte
        int shift = bitNum & 0x7;
        if (shift > 0) {
            int maskVal = << (- shift);
            byte val = buffer[byteNum];
            while (maskVal > && bitNum < lastBit) {
                val |= maskVal;
                maskVal >>= 1;
                ++bitNum;
            }
            buffer[byteNum= val;
        }

        // Fill in 8 bits at a time
        byteNum = bitNum >> 3;
        while (bitNum < lastBit - 7) {
            buffer[byteNum++(byte255;
            bitNum += 8;
        }

        // Fill in remaining bits
        while (bitNum < lastBit) {
            byteNum = bitNum >> 3;
            buffer[byteNum|= << ((bitNum & 0x7));
            ++bitNum;
        }
    }

    // Returns run length
    private int decodeWhiteCodeWord() {
        int current, entry, bits, isT, twoBits, code = -1;
        int runLength = 0;
        boolean isWhite = true;

        while (isWhite) {
            current = nextNBits(10);
            entry = white[current];

            // Get the 3 fields from the entry
            isT = entry & 0x0001;
            bits = (entry >>> 10x0f;

            if (bits == 12) {           // Additional Make up code
                // Get the next 2 bits
                twoBits = nextLesserThan8Bits(2);
                // Consolidate the 2 new bits and last 2 bits into 4 bits
                current = ((current << 20x000c| twoBits;
                entry = additionalMakeup[current];
                bits = (entry >>> 10x07;     // 3 bits 0000 0111
                code = (entry >>> 40x0fff;   // 12 bits
                runLength += code;
                updatePointer(- bits);
            else if (bits == 0) {     // ERROR
                throw new RuntimeException("Error 0");
            else if (bits == 15) {    // EOL
                throw new RuntimeException("Error 1");
            else {
                // 11 bits - 0000 0111 1111 1111 = 0x07ff
                code = (entry >>> 50x07ff;
                runLength += code;
                updatePointer(10 - bits);
                if (isT == 0) {
                    isWhite = false;
                }
            }
        }

        return runLength;
    }

    // Returns run length
    private int decodeBlackCodeWord() {
        int current, entry, bits, isT, twoBits, code = -1;
        int runLength = 0;
        boolean isWhite = false;

        while (!isWhite) {
            current = nextLesserThan8Bits(4);
            entry = initBlack[current];

            // Get the 3 fields from the entry
            isT = entry & 0x0001;
            bits = (entry >>> 10x000f;
            code = (entry >>> 50x07ff;

            if (code == 100) {
                current = nextNBits(9);
                entry = black[current];

                // Get the 3 fields from the entry
                isT = entry & 0x0001;
                bits = (entry >>> 10x000f;
                code = (entry >>> 50x07ff;

                if (bits == 12) {
                    // Additional makeup codes
                    updatePointer(5);
                    current = nextLesserThan8Bits(4);
                    entry = additionalMakeup[current];
                    bits = (entry >>> 10x07;     // 3 bits 0000 0111
                    code = (entry >>> 40x0fff;  // 12 bits
                    runLength += code;

                    updatePointer(- bits);
                else if (bits == 15) {
                    // EOL code
                    throw new RuntimeException("Error 2");
                else {
                    runLength += code;
                    updatePointer(- bits);
                    if (isT == 0) {
                        isWhite = true;
                    }
                }
            else if (code == 200) {
                // Is a Terminating code
                current = nextLesserThan8Bits(2);
                entry = twoBitBlack[current];
                code = (entry >>> 50x07ff;
                runLength += code;
                bits = (entry >>> 10x0f;
                updatePointer(- bits);
                isWhite = true;
            else {
                // Is a Terminating code
                runLength += code;
                updatePointer(- bits);
                isWhite = true;
            }
        }

        return runLength;
    }

    private int findNextLine() {
        // Set maximum and current bit index into the compressed data.
        int bitIndexMax = data.length * 1;
        int bitIndexMax12 = bitIndexMax - 12;
        int bitIndex = bytePointer * + bitPointer;

        // Loop while at least 12 bits are available.
        while (bitIndex <= bitIndexMax12) {
            // Get the next 12 bits.
            int next12Bits = nextNBits(12);
            bitIndex += 12;

            // Loop while the 12 bits are not unity, i.e., while the EOL
            // has not been reached, and there is at least one bit left.
            while (next12Bits != && bitIndex < bitIndexMax) {
                next12Bits =
                        ((next12Bits & 0x000007ff<< 1)
                        (nextLesserThan8Bits(10x00000001);
                bitIndex++;
            }

            if (next12Bits == 1) { // now positioned just after EOL
                if (oneD == 1) { // two-dimensional coding
                    if (bitIndex < bitIndexMax) {
                        // check next bit against type of line being sought
                        return nextLesserThan8Bits(1);
                    }
                else {
                    return 1;
                }
            }
        }

        // EOL not found.
        throw new RuntimeException();
    }

    private void getNextChangingElement(int a0, boolean isWhite, int[] ret) {
        // Local copies of instance variables
        int[] pce = this.prevChangingElems;
        int ces = this.changingElemSize;

        // If the previous match was at an odd element, we still
        // have to search the preceeding element.
        // int start = lastChangingElement & ~0x1;
        int start = lastChangingElement > ? lastChangingElement - 0;
        if (isWhite) {
            start &= ~0x1; // Search even numbered elements
        else {
            start |= 0x1// Search odd numbered elements
        }

        int i = start;
        for (; i < ces; i += 2) {
            int temp = pce[i];
            if (temp > a0) {
                lastChangingElement = i;
                ret[0= temp;
                break;
            }
        }

        if (i + < ces) {
            ret[1= pce[i + 1];
        }
    }

    private int nextNBits(int bitsToGet) {
        byte b, next, next2next;
        int l = data.length - 1;
        int bp = this.bytePointer;

        if (fillOrder == 1) {
            b = data[bp];

            if (bp == l) {
                next = 0x00;
                next2next = 0x00;
            else if ((bp + 1== l) {
                next = data[bp + 1];
                next2next = 0x00;
            else {
                next = data[bp + 1];
                next2next = data[bp + 2];
            }
        else if (fillOrder == 2) {
            b = flipTable[data[bp0xff];

            if (bp == l) {
                next = 0x00;
                next2next = 0x00;
            else if ((bp + 1== l) {
                next = flipTable[data[bp + 10xff];
                next2next = 0x00;
            else {
                next = flipTable[data[bp + 10xff];
                next2next = flipTable[data[bp + 20xff];
            }
        else {
            throw new RuntimeException("Invalid FillOrder");
        }

        int bitsLeft = - bitPointer;
        int bitsFromNextByte = bitsToGet - bitsLeft;
        int bitsFromNext2NextByte = 0;
        if (bitsFromNextByte > 8) {
            bitsFromNext2NextByte = bitsFromNextByte - 8;
            bitsFromNextByte = 8;
        }

        bytePointer++;

        int i1 = (b & table1[bitsLeft]) << (bitsToGet - bitsLeft);
        int i2 = (next & table2[bitsFromNextByte]) >>> (- bitsFromNextByte);

        int i3 = 0;
        if (bitsFromNext2NextByte != 0) {
            i2 <<= bitsFromNext2NextByte;
            i3 = (next2next & table2[bitsFromNext2NextByte])
                    >>> (- bitsFromNext2NextByte);
            i2 |= i3;
            bytePointer++;
            bitPointer = bitsFromNext2NextByte;
        else {
            if (bitsFromNextByte == 8) {
                bitPointer = 0;
                bytePointer++;
            else {
                bitPointer = bitsFromNextByte;
            }
        }

        int i = i1 | i2;
        return i;
    }

    private int nextLesserThan8Bits(int bitsToGet) {
        byte b, next;
        int l = data.length - 1;
        int bp = this.bytePointer;

        if (fillOrder == 1) {
            b = data[bp];
            if (bp == l) {
                next = 0x00;
            else {
                next = data[bp + 1];
            }
        else if (fillOrder == 2) {
            b = flipTable[data[bp0xff];
            if (bp == l) {
                next = 0x00;
            else {
                next = flipTable[data[bp + 10xff];
            }
        else {
            throw new RuntimeException("Invalid FillOrder");
        }

        int bitsLeft = - bitPointer;
        int bitsFromNextByte = bitsToGet - bitsLeft;

        int shift = bitsLeft - bitsToGet;
        int i1, i2;
        if (shift >= 0) {
            i1 = (b & table1[bitsLeft]) >>> shift;
            bitPointer += bitsToGet;
            if (bitPointer == 8) {
                bitPointer = 0;
                bytePointer++;
            }
        else {
            i1 = (b & table1[bitsLeft]) << (-shift);
            i2 = (next & table2[bitsFromNextByte]) >>> (- bitsFromNextByte);

            i1 |= i2;
            bytePointer++;
            bitPointer = bitsFromNextByte;
        }

        return i1;
    }

    // Move pointer backwards by given amount of bits
    private void updatePointer(int bitsToMoveBack) {
        if (bitsToMoveBack > 8) {
            bytePointer -= bitsToMoveBack / 8;
            bitsToMoveBack %= 8;
        }

        int i = bitPointer - bitsToMoveBack;
        if (i < 0) {
            bytePointer--;
            bitPointer = + i;
        else {
            bitPointer = i;
        }
    }
}