/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 . */ #include "ccidecom.hxx" #include //=============================== Huffman tables ======================== //---------------------------- White-Run ------------------------------ #define CCIWhiteTableSize 105 const CCIHuffmanTableEntry CCIWhiteTable[CCIWhiteTableSize]={ { 0, 0x0035, 8 }, { 1, 0x0007, 6 }, { 2, 0x0007, 4 }, { 3, 0x0008, 4 }, { 4, 0x000b, 4 }, { 5, 0x000c, 4 }, { 6, 0x000e, 4 }, { 7, 0x000f, 4 }, { 8, 0x0013, 5 }, { 9, 0x0014, 5 }, { 10, 0x0007, 5 }, { 11, 0x0008, 5 }, { 12, 0x0008, 6 }, { 13, 0x0003, 6 }, { 14, 0x0034, 6 }, { 15, 0x0035, 6 }, { 16, 0x002a, 6 }, { 17, 0x002b, 6 }, { 18, 0x0027, 7 }, { 19, 0x000c, 7 }, { 20, 0x0008, 7 }, { 21, 0x0017, 7 }, { 22, 0x0003, 7 }, { 23, 0x0004, 7 }, { 24, 0x0028, 7 }, { 25, 0x002b, 7 }, { 26, 0x0013, 7 }, { 27, 0x0024, 7 }, { 28, 0x0018, 7 }, { 29, 0x0002, 8 }, { 30, 0x0003, 8 }, { 31, 0x001a, 8 }, { 32, 0x001b, 8 }, { 33, 0x0012, 8 }, { 34, 0x0013, 8 }, { 35, 0x0014, 8 }, { 36, 0x0015, 8 }, { 37, 0x0016, 8 }, { 38, 0x0017, 8 }, { 39, 0x0028, 8 }, { 40, 0x0029, 8 }, { 41, 0x002a, 8 }, { 42, 0x002b, 8 }, { 43, 0x002c, 8 }, { 44, 0x002d, 8 }, { 45, 0x0004, 8 }, { 46, 0x0005, 8 }, { 47, 0x000a, 8 }, { 48, 0x000b, 8 }, { 49, 0x0052, 8 }, { 50, 0x0053, 8 }, { 51, 0x0054, 8 }, { 52, 0x0055, 8 }, { 53, 0x0024, 8 }, { 54, 0x0025, 8 }, { 55, 0x0058, 8 }, { 56, 0x0059, 8 }, { 57, 0x005a, 8 }, { 58, 0x005b, 8 }, { 59, 0x004a, 8 }, { 60, 0x004b, 8 }, { 61, 0x0032, 8 }, { 62, 0x0033, 8 }, { 63, 0x0034, 8 }, { 64, 0x001b, 5 }, { 128, 0x0012, 5 }, { 192, 0x0017, 6 }, { 256, 0x0037, 7 }, { 320, 0x0036, 8 }, { 384, 0x0037, 8 }, { 448, 0x0064, 8 }, { 512, 0x0065, 8 }, { 576, 0x0068, 8 }, { 640, 0x0067, 8 }, { 704, 0x00cc, 9 }, { 768, 0x00cd, 9 }, { 832, 0x00d2, 9 }, { 896, 0x00d3, 9 }, { 960, 0x00d4, 9 }, { 1024, 0x00d5, 9 }, { 1088, 0x00d6, 9 }, { 1152, 0x00d7, 9 }, { 1216, 0x00d8, 9 }, { 1280, 0x00d9, 9 }, { 1344, 0x00da, 9 }, { 1408, 0x00db, 9 }, { 1472, 0x0098, 9 }, { 1536, 0x0099, 9 }, { 1600, 0x009a, 9 }, { 1664, 0x0018, 6 }, { 1728, 0x009b, 9 }, { 1792, 0x0008, 11 }, { 1856, 0x000c, 11 }, { 1920, 0x000d, 11 }, { 1984, 0x0012, 12 }, { 2048, 0x0013, 12 }, { 2112, 0x0014, 12 }, { 2176, 0x0015, 12 }, { 2240, 0x0016, 12 }, { 2304, 0x0017, 12 }, { 2368, 0x001c, 12 }, { 2432, 0x001d, 12 }, { 2496, 0x001e, 12 }, { 2560, 0x001f, 12 }, { 9999, 0x0001, 12 } // EOL }; //---------------------------- Black-Run ------------------------------ #define CCIBlackTableSize 105 const CCIHuffmanTableEntry CCIBlackTable[CCIBlackTableSize]={ { 0, 0x0037, 10 }, { 1, 0x0002, 3 }, { 2, 0x0003, 2 }, { 3, 0x0002, 2 }, { 4, 0x0003, 3 }, { 5, 0x0003, 4 }, { 6, 0x0002, 4 }, { 7, 0x0003, 5 }, { 8, 0x0005, 6 }, { 9, 0x0004, 6 }, { 10, 0x0004, 7 }, { 11, 0x0005, 7 }, { 12, 0x0007, 7 }, { 13, 0x0004, 8 }, { 14, 0x0007, 8 }, { 15, 0x0018, 9 }, { 16, 0x0017, 10 }, { 17, 0x0018, 10 }, { 18, 0x0008, 10 }, { 19, 0x0067, 11 }, { 20, 0x0068, 11 }, { 21, 0x006c, 11 }, { 22, 0x0037, 11 }, { 23, 0x0028, 11 }, { 24, 0x0017, 11 }, { 25, 0x0018, 11 }, { 26, 0x00ca, 12 }, { 27, 0x00cb, 12 }, { 28, 0x00cc, 12 }, { 29, 0x00cd, 12 }, { 30, 0x0068, 12 }, { 31, 0x0069, 12 }, { 32, 0x006a, 12 }, { 33, 0x006b, 12 }, { 34, 0x00d2, 12 }, { 35, 0x00d3, 12 }, { 36, 0x00d4, 12 }, { 37, 0x00d5, 12 }, { 38, 0x00d6, 12 }, { 39, 0x00d7, 12 }, { 40, 0x006c, 12 }, { 41, 0x006d, 12 }, { 42, 0x00da, 12 }, { 43, 0x00db, 12 }, { 44, 0x0054, 12 }, { 45, 0x0055, 12 }, { 46, 0x0056, 12 }, { 47, 0x0057, 12 }, { 48, 0x0064, 12 }, { 49, 0x0065, 12 }, { 50, 0x0052, 12 }, { 51, 0x0053, 12 }, { 52, 0x0024, 12 }, { 53, 0x0037, 12 }, { 54, 0x0038, 12 }, { 55, 0x0027, 12 }, { 56, 0x0028, 12 }, { 57, 0x0058, 12 }, { 58, 0x0059, 12 }, { 59, 0x002b, 12 }, { 60, 0x002c, 12 }, { 61, 0x005a, 12 }, { 62, 0x0066, 12 }, { 63, 0x0067, 12 }, { 64, 0x000f, 10 }, { 128, 0x00c8, 12 }, { 192, 0x00c9, 12 }, { 256, 0x005b, 12 }, { 320, 0x0033, 12 }, { 384, 0x0034, 12 }, { 448, 0x0035, 12 }, { 512, 0x006c, 13 }, { 576, 0x006d, 13 }, { 640, 0x004a, 13 }, { 704, 0x004b, 13 }, { 768, 0x004c, 13 }, { 832, 0x004d, 13 }, { 896, 0x0072, 13 }, { 960, 0x0073, 13 }, { 1024, 0x0074, 13 }, { 1088, 0x0075, 13 }, { 1152, 0x0076, 13 }, { 1216, 0x0077, 13 }, { 1280, 0x0052, 13 }, { 1344, 0x0053, 13 }, { 1408, 0x0054, 13 }, { 1472, 0x0055, 13 }, { 1536, 0x005a, 13 }, { 1600, 0x005b, 13 }, { 1664, 0x0064, 13 }, { 1728, 0x0065, 13 }, { 1792, 0x0008, 11 }, { 1856, 0x000c, 11 }, { 1920, 0x000d, 11 }, { 1984, 0x0012, 12 }, { 2048, 0x0013, 12 }, { 2112, 0x0014, 12 }, { 2176, 0x0015, 12 }, { 2240, 0x0016, 12 }, { 2304, 0x0017, 12 }, { 2368, 0x001c, 12 }, { 2432, 0x001d, 12 }, { 2496, 0x001e, 12 }, { 2560, 0x001f, 12 }, { 9999, 0x0001, 12 } // EOL }; //---------------------------- 2D-Mode -------------------------------- #define CCI2DMODE_UNCOMP 0 #define CCI2DMODE_PASS 1 #define CCI2DMODE_HORZ 2 #define CCI2DMODE_VERT_L3 3 #define CCI2DMODE_VERT_L2 4 #define CCI2DMODE_VERT_L1 5 #define CCI2DMODE_VERT_0 6 #define CCI2DMODE_VERT_R1 7 #define CCI2DMODE_VERT_R2 8 #define CCI2DMODE_VERT_R3 9 #define CCI2DModeTableSize 10 const CCIHuffmanTableEntry CCI2DModeTable[CCI2DModeTableSize]={ { CCI2DMODE_UNCOMP , 0x000f, 10 }, { CCI2DMODE_PASS , 0x0001, 4 }, { CCI2DMODE_HORZ , 0x0001, 3 }, { CCI2DMODE_VERT_L3, 0x0002, 7 }, { CCI2DMODE_VERT_L2, 0x0002, 6 }, { CCI2DMODE_VERT_L1, 0x0002, 3 }, { CCI2DMODE_VERT_0 , 0x0001, 1 }, { CCI2DMODE_VERT_R1, 0x0003, 3 }, { CCI2DMODE_VERT_R2, 0x0003, 6 }, { CCI2DMODE_VERT_R3, 0x0003, 7 } }; //-------------------------- 2D-Uncompressed-Mode ---------------------- #define CCIUNCOMP_0White_1Black 0 #define CCIUNCOMP_1White_1Black 1 #define CCIUNCOMP_2White_1Black 2 #define CCIUNCOMP_3White_1Black 3 #define CCIUNCOMP_4White_1Black 4 #define CCIUNCOMP_5White 5 #define CCIUNCOMP_0White_End 6 #define CCIUNCOMP_1White_End 7 #define CCIUNCOMP_2White_End 8 #define CCIUNCOMP_3White_End 9 #define CCIUNCOMP_4White_End 10 #define CCIUncompTableSize 11 const CCIHuffmanTableEntry CCIUncompTable[CCIUncompTableSize]={ { CCIUNCOMP_0White_1Black, 0x0001, 1 }, { CCIUNCOMP_1White_1Black, 0x0001, 2 }, { CCIUNCOMP_2White_1Black, 0x0001, 3 }, { CCIUNCOMP_3White_1Black, 0x0001, 4 }, { CCIUNCOMP_4White_1Black, 0x0001, 5 }, { CCIUNCOMP_5White , 0x0001, 6 }, { CCIUNCOMP_0White_End , 0x0001, 7 }, { CCIUNCOMP_1White_End , 0x0001, 8 }, { CCIUNCOMP_2White_End , 0x0001, 9 }, { CCIUNCOMP_3White_End , 0x0001, 10 }, { CCIUNCOMP_4White_End , 0x0001, 11 } }; //================== backup of the Huffman tables ============================ // To make sure that the Huffman tables do not contain errors they were entered // from two different sources (Phew) and compared. // Since an error could creep in to the source code while maintaining it // (e.g. an accidental key press in the editor) the tables are listed twice // and are compared during runtime. (If the comparison fails CCIDcompressor // throws an error) The whole thing may appear insane, but an error within the // tables would otherwise be really hard to discover and it's very unlikely that // one or more sample files run through all codes. const CCIHuffmanTableEntry CCIWhiteTableSave[CCIWhiteTableSize]={ { 0, 0x0035, 8 }, { 1, 0x0007, 6 }, { 2, 0x0007, 4 }, { 3, 0x0008, 4 }, { 4, 0x000b, 4 }, { 5, 0x000c, 4 }, { 6, 0x000e, 4 }, { 7, 0x000f, 4 }, { 8, 0x0013, 5 }, { 9, 0x0014, 5 }, { 10, 0x0007, 5 }, { 11, 0x0008, 5 }, { 12, 0x0008, 6 }, { 13, 0x0003, 6 }, { 14, 0x0034, 6 }, { 15, 0x0035, 6 }, { 16, 0x002a, 6 }, { 17, 0x002b, 6 }, { 18, 0x0027, 7 }, { 19, 0x000c, 7 }, { 20, 0x0008, 7 }, { 21, 0x0017, 7 }, { 22, 0x0003, 7 }, { 23, 0x0004, 7 }, { 24, 0x0028, 7 }, { 25, 0x002b, 7 }, { 26, 0x0013, 7 }, { 27, 0x0024, 7 }, { 28, 0x0018, 7 }, { 29, 0x0002, 8 }, { 30, 0x0003, 8 }, { 31, 0x001a, 8 }, { 32, 0x001b, 8 }, { 33, 0x0012, 8 }, { 34, 0x0013, 8 }, { 35, 0x0014, 8 }, { 36, 0x0015, 8 }, { 37, 0x0016, 8 }, { 38, 0x0017, 8 }, { 39, 0x0028, 8 }, { 40, 0x0029, 8 }, { 41, 0x002a, 8 }, { 42, 0x002b, 8 }, { 43, 0x002c, 8 }, { 44, 0x002d, 8 }, { 45, 0x0004, 8 }, { 46, 0x0005, 8 }, { 47, 0x000a, 8 }, { 48, 0x000b, 8 }, { 49, 0x0052, 8 }, { 50, 0x0053, 8 }, { 51, 0x0054, 8 }, { 52, 0x0055, 8 }, { 53, 0x0024, 8 }, { 54, 0x0025, 8 }, { 55, 0x0058, 8 }, { 56, 0x0059, 8 }, { 57, 0x005a, 8 }, { 58, 0x005b, 8 }, { 59, 0x004a, 8 }, { 60, 0x004b, 8 }, { 61, 0x0032, 8 }, { 62, 0x0033, 8 }, { 63, 0x0034, 8 }, { 64, 0x001b, 5 }, { 128, 0x0012, 5 }, { 192, 0x0017, 6 }, { 256, 0x0037, 7 }, { 320, 0x0036, 8 }, { 384, 0x0037, 8 }, { 448, 0x0064, 8 }, { 512, 0x0065, 8 }, { 576, 0x0068, 8 }, { 640, 0x0067, 8 }, { 704, 0x00cc, 9 }, { 768, 0x00cd, 9 }, { 832, 0x00d2, 9 }, { 896, 0x00d3, 9 }, { 960, 0x00d4, 9 }, { 1024, 0x00d5, 9 }, { 1088, 0x00d6, 9 }, { 1152, 0x00d7, 9 }, { 1216, 0x00d8, 9 }, { 1280, 0x00d9, 9 }, { 1344, 0x00da, 9 }, { 1408, 0x00db, 9 }, { 1472, 0x0098, 9 }, { 1536, 0x0099, 9 }, { 1600, 0x009a, 9 }, { 1664, 0x0018, 6 }, { 1728, 0x009b, 9 }, { 1792, 0x0008, 11 }, { 1856, 0x000c, 11 }, { 1920, 0x000d, 11 }, { 1984, 0x0012, 12 }, { 2048, 0x0013, 12 }, { 2112, 0x0014, 12 }, { 2176, 0x0015, 12 }, { 2240, 0x0016, 12 }, { 2304, 0x0017, 12 }, { 2368, 0x001c, 12 }, { 2432, 0x001d, 12 }, { 2496, 0x001e, 12 }, { 2560, 0x001f, 12 }, { 9999, 0x0001, 12 } // EOL }; const CCIHuffmanTableEntry CCIBlackTableSave[CCIBlackTableSize]={ { 0, 0x0037, 10 }, { 1, 0x0002, 3 }, { 2, 0x0003, 2 }, { 3, 0x0002, 2 }, { 4, 0x0003, 3 }, { 5, 0x0003, 4 }, { 6, 0x0002, 4 }, { 7, 0x0003, 5 }, { 8, 0x0005, 6 }, { 9, 0x0004, 6 }, { 10, 0x0004, 7 }, { 11, 0x0005, 7 }, { 12, 0x0007, 7 }, { 13, 0x0004, 8 }, { 14, 0x0007, 8 }, { 15, 0x0018, 9 }, { 16, 0x0017, 10 }, { 17, 0x0018, 10 }, { 18, 0x0008, 10 }, { 19, 0x0067, 11 }, { 20, 0x0068, 11 }, { 21, 0x006c, 11 }, { 22, 0x0037, 11 }, { 23, 0x0028, 11 }, { 24, 0x0017, 11 }, { 25, 0x0018, 11 }, { 26, 0x00ca, 12 }, { 27, 0x00cb, 12 }, { 28, 0x00cc, 12 }, { 29, 0x00cd, 12 }, { 30, 0x0068, 12 }, { 31, 0x0069, 12 }, { 32, 0x006a, 12 }, { 33, 0x006b, 12 }, { 34, 0x00d2, 12 }, { 35, 0x00d3, 12 }, { 36, 0x00d4, 12 }, { 37, 0x00d5, 12 }, { 38, 0x00d6, 12 }, { 39, 0x00d7, 12 }, { 40, 0x006c, 12 }, { 41, 0x006d, 12 }, { 42, 0x00da, 12 }, { 43, 0x00db, 12 }, { 44, 0x0054, 12 }, { 45, 0x0055, 12 }, { 46, 0x0056, 12 }, { 47, 0x0057, 12 }, { 48, 0x0064, 12 }, { 49, 0x0065, 12 }, { 50, 0x0052, 12 }, { 51, 0x0053, 12 }, { 52, 0x0024, 12 }, { 53, 0x0037, 12 }, { 54, 0x0038, 12 }, { 55, 0x0027, 12 }, { 56, 0x0028, 12 }, { 57, 0x0058, 12 }, { 58, 0x0059, 12 }, { 59, 0x002b, 12 }, { 60, 0x002c, 12 }, { 61, 0x005a, 12 }, { 62, 0x0066, 12 }, { 63, 0x0067, 12 }, { 64, 0x000f, 10 }, { 128, 0x00c8, 12 }, { 192, 0x00c9, 12 }, { 256, 0x005b, 12 }, { 320, 0x0033, 12 }, { 384, 0x0034, 12 }, { 448, 0x0035, 12 }, { 512, 0x006c, 13 }, { 576, 0x006d, 13 }, { 640, 0x004a, 13 }, { 704, 0x004b, 13 }, { 768, 0x004c, 13 }, { 832, 0x004d, 13 }, { 896, 0x0072, 13 }, { 960, 0x0073, 13 }, { 1024, 0x0074, 13 }, { 1088, 0x0075, 13 }, { 1152, 0x0076, 13 }, { 1216, 0x0077, 13 }, { 1280, 0x0052, 13 }, { 1344, 0x0053, 13 }, { 1408, 0x0054, 13 }, { 1472, 0x0055, 13 }, { 1536, 0x005a, 13 }, { 1600, 0x005b, 13 }, { 1664, 0x0064, 13 }, { 1728, 0x0065, 13 }, { 1792, 0x0008, 11 }, { 1856, 0x000c, 11 }, { 1920, 0x000d, 11 }, { 1984, 0x0012, 12 }, { 2048, 0x0013, 12 }, { 2112, 0x0014, 12 }, { 2176, 0x0015, 12 }, { 2240, 0x0016, 12 }, { 2304, 0x0017, 12 }, { 2368, 0x001c, 12 }, { 2432, 0x001d, 12 }, { 2496, 0x001e, 12 }, { 2560, 0x001f, 12 }, { 9999, 0x0001, 12 } // EOL }; const CCIHuffmanTableEntry CCI2DModeTableSave[CCI2DModeTableSize]={ { CCI2DMODE_UNCOMP , 0x000f, 10 }, { CCI2DMODE_PASS , 0x0001, 4 }, { CCI2DMODE_HORZ , 0x0001, 3 }, { CCI2DMODE_VERT_L3, 0x0002, 7 }, { CCI2DMODE_VERT_L2, 0x0002, 6 }, { CCI2DMODE_VERT_L1, 0x0002, 3 }, { CCI2DMODE_VERT_0 , 0x0001, 1 }, { CCI2DMODE_VERT_R1, 0x0003, 3 }, { CCI2DMODE_VERT_R2, 0x0003, 6 }, { CCI2DMODE_VERT_R3, 0x0003, 7 } }; const CCIHuffmanTableEntry CCIUncompTableSave[CCIUncompTableSize]={ { CCIUNCOMP_0White_1Black, 0x0001, 1 }, { CCIUNCOMP_1White_1Black, 0x0001, 2 }, { CCIUNCOMP_2White_1Black, 0x0001, 3 }, { CCIUNCOMP_3White_1Black, 0x0001, 4 }, { CCIUNCOMP_4White_1Black, 0x0001, 5 }, { CCIUNCOMP_5White , 0x0001, 6 }, { CCIUNCOMP_0White_End , 0x0001, 7 }, { CCIUNCOMP_1White_End , 0x0001, 8 }, { CCIUNCOMP_2White_End , 0x0001, 9 }, { CCIUNCOMP_3White_End , 0x0001, 10 }, { CCIUNCOMP_4White_End , 0x0001, 11 } }; CCIDecompressor::CCIDecompressor( sal_uLong nOpts, sal_uInt32 nImageWidth ) : bTableBad ( false ), bStatus ( false ), pByteSwap ( nullptr ), pIStream ( nullptr ), nEOLCount ( 0 ), nWidth ( nImageWidth ), nOptions ( nOpts ), bFirstEOL ( false ), nInputBitsBuf( 0 ), nInputBitsBufSize( 0 ), pLastLine ( nullptr ), nLastLineSize( 0 ) { if ( nOpts & CCI_OPTION_INVERSEBITORDER ) { pByteSwap.reset( new sal_uInt8[ 256 ] ); for ( int i = 0; i < 256; i++ ) { pByteSwap[ i ] = sal::static_int_cast< sal_uInt8 >( ( i << 7 ) | ( ( i & 2 ) << 5 ) | ( ( i & 4 ) << 3 ) | ( ( i & 8 ) << 1 ) | ( ( i & 16 ) >> 1 ) | ( ( i & 32 ) >> 3 ) | ( ( i & 64 ) >> 5 ) | ( ( i & 128 ) >> 7 )); } } MakeLookUp(CCIWhiteTable,CCIWhiteTableSave,pWhiteLookUp.data(),CCIWhiteTableSize,13); MakeLookUp(CCIBlackTable,CCIBlackTableSave,pBlackLookUp.data(),CCIBlackTableSize,13); MakeLookUp(CCI2DModeTable,CCI2DModeTableSave,p2DModeLookUp.data(),CCI2DModeTableSize,10); MakeLookUp(CCIUncompTable,CCIUncompTableSave,pUncompLookUp.data(),CCIUncompTableSize,11); } CCIDecompressor::~CCIDecompressor() { } void CCIDecompressor::StartDecompression( SvStream & rIStream ) { pIStream = &rIStream; nInputBitsBufSize = 0; bFirstEOL = true; bStatus = true; nEOLCount = 0; if ( bTableBad ) return; } DecompressStatus CCIDecompressor::DecompressScanline( sal_uInt8 * pTarget, sal_uLong nTargetBits, bool bLastLine ) { //Read[1|2]DScanlineData take a sal_uInt16, so its either limit here or expand there if (nTargetBits > SAL_MAX_UINT16) return DecompressStatus(false, true); if ( nEOLCount >= 5 ) // RTC (Return To Controller) return DecompressStatus(true, true); if ( !bStatus ) return DecompressStatus(false, true); // If EOL-Codes exist, the EOL-Code also appeared in front of the first line. // (and I thought it means 'End of Line'...) // Therefore we read the EOL-Code always at the beginning of each line first: if ( nOptions & CCI_OPTION_EOL ) { if ( bFirstEOL ) { sal_uInt32 nCurPos = pIStream->Tell(); sal_uInt16 nOldInputBitsBufSize = nInputBitsBufSize; sal_uInt32 nOldInputBitsBuf = nInputBitsBuf; if ( !ReadEOL() ) { nInputBitsBufSize = nOldInputBitsBufSize; nInputBitsBuf = nOldInputBitsBuf; pIStream->Seek( nCurPos ); nOptions &=~ CCI_OPTION_EOL; // CCITT Group 3 - Compression Type 2 } bFirstEOL = false; } else { if ( !ReadEOL() ) { return DecompressStatus(bStatus, true); } } } if ( nEOLCount >= 5 ) // RTC (Return To Controller) return DecompressStatus(true, true); // should the situation arise, generate a white previous line for 2D: if ( nOptions & CCI_OPTION_2D ) { if ( pLastLine == nullptr || nLastLineSize != ( ( nTargetBits + 7 ) >> 3 ) ) { nLastLineSize = ( nTargetBits + 7 ) >> 3; pLastLine.reset( new sal_uInt8[ nLastLineSize ] ); memset(pLastLine.get(), 0, nLastLineSize); } } // conditionally align start of line to next byte: if ( nOptions & CCI_OPTION_BYTEALIGNROW ) nInputBitsBufSize &= 0xfff8; bool b2D; // is it a 2D row? if ( nOptions & CCI_OPTION_2D ) { if ( nOptions & CCI_OPTION_EOL ) b2D = Read2DTag(); else b2D = true; } else b2D = false; bool bUnchanged; // read scanline: if ( b2D ) bUnchanged = Read2DScanlineData(pTarget, nTargetBits); else bUnchanged = Read1DScanlineData(pTarget, nTargetBits); // if we're in 2D mode we have to remember the line: if ( nOptions & CCI_OPTION_2D && bStatus ) { memcpy(pLastLine.get(), pTarget, nLastLineSize); } // #i122984# if( !bStatus && bLastLine ) { bStatus = true; } if ( pIStream->GetError() ) bStatus = false; return DecompressStatus(bStatus, bUnchanged); } void CCIDecompressor::MakeLookUp(const CCIHuffmanTableEntry * pHufTab, const CCIHuffmanTableEntry * pHufTabSave, CCILookUpTableEntry * pLookUp, sal_uInt16 nHuffmanTableSize, sal_uInt16 nMaxCodeBits) { sal_uInt16 nLookUpSize = 1 << nMaxCodeBits; memset(pLookUp, 0, nLookUpSize * sizeof(CCILookUpTableEntry)); if (bTableBad) return; sal_uInt16 nMask = 0xffff >> (16-nMaxCodeBits); for (sal_uInt16 i = 0; i < nHuffmanTableSize; ++i) { if ( pHufTab[i].nValue!=pHufTabSave[i].nValue || pHufTab[i].nCode!=pHufTabSave[i].nCode || pHufTab[i].nCodeBits!=pHufTabSave[i].nCodeBits || pHufTab[i].nCodeBits==0 || pHufTab[i].nCodeBits>nMaxCodeBits ) { bTableBad=true; return; } sal_uInt16 nMinCode = nMask & (pHufTab[i].nCode << (nMaxCodeBits-pHufTab[i].nCodeBits)); sal_uInt16 nMaxCode = nMinCode | (nMask >> pHufTab[i].nCodeBits); for (sal_uInt16 j=nMinCode; j<=nMaxCode; ++j) { if (pLookUp[j].nCodeBits!=0) { bTableBad=true; return; } pLookUp[j].nValue=pHufTab[i].nValue; pLookUp[j].nCodeBits=pHufTab[i].nCodeBits; } } } bool CCIDecompressor::ReadEOL() { sal_uInt16 nCode; sal_uInt8 nByte; // if (nOptions&CCI_OPTION_BYTEALIGNEOL) nMaxFillBits=7; else nMaxFillBits=0; // D'oh: Either the option in itiff.cxx is not set correctly (-> error in documentation) // or there exist some nasty export filter who always do align. // In addition files were found in which more than the necessary maximum of 7 filling // bits were found. Therefore we now generally accept up to 32 nonsense bits in front of the EOL-Code: // And I found a file in which up to ??? nonsense bits are written. Furthermore the byte order is switched in it. (SJ) sal_uInt32 nMaxPos = pIStream->Tell(); nMaxPos += nWidth >> 3; for ( ;; ) { while ( nInputBitsBufSize < 12 ) { pIStream->ReadUChar( nByte ); if (!pIStream->good()) return false; if ( pIStream->Tell() > nMaxPos ) return false; if ( nOptions & CCI_OPTION_INVERSEBITORDER ) nByte = pByteSwap[ nByte ]; nInputBitsBuf=(nInputBitsBuf<<8) | (sal_uLong)nByte; nInputBitsBufSize += 8; } nCode = (sal_uInt16)( ( nInputBitsBuf >> ( nInputBitsBufSize - 12 ) ) & 0x0fff ); if ( nCode == 0x0001 ) { nEOLCount++; nInputBitsBufSize -= 12; break; } else nInputBitsBufSize--; } return true; } bool CCIDecompressor::Read2DTag() { sal_uInt8 nByte; // read a bit and return sal_True if it's 0, otherwise return sal_False if (nInputBitsBufSize==0) { pIStream->ReadUChar( nByte ); if ( nOptions & CCI_OPTION_INVERSEBITORDER ) nByte = pByteSwap[ nByte ]; nInputBitsBuf=(sal_uLong)nByte; nInputBitsBufSize=8; } nInputBitsBufSize--; return ((nInputBitsBuf>>nInputBitsBufSize)&0x0001) == 0; } sal_uInt8 CCIDecompressor::ReadBlackOrWhite() { sal_uInt8 nByte; // read a bit and deliver 0x00 if it's 0, otherwise 0xff if (nInputBitsBufSize==0) { pIStream->ReadUChar( nByte ); if ( nOptions & CCI_OPTION_INVERSEBITORDER ) nByte = pByteSwap[ nByte ]; nInputBitsBuf=(sal_uLong)nByte; nInputBitsBufSize=8; } nInputBitsBufSize--; if ( (nInputBitsBuf>>nInputBitsBufSize) & 0x0001 ) return 0xff; else return 0x00; } sal_uInt16 CCIDecompressor::ReadCodeAndDecode(const CCILookUpTableEntry * pLookUp, sal_uInt16 nMaxCodeBits) { // read a Huffman code and decode it: while (nInputBitsBufSizeReadUChar( nByte ); if ( nOptions & CCI_OPTION_INVERSEBITORDER ) nByte = pByteSwap[ nByte ]; nInputBitsBuf=(nInputBitsBuf<<8) | (sal_uLong)nByte; nInputBitsBufSize+=8; } sal_uInt16 nCode = (sal_uInt16)((nInputBitsBuf>>(nInputBitsBufSize-nMaxCodeBits)) &(0xffff>>(16-nMaxCodeBits))); sal_uInt16 nCodeBits = pLookUp[nCode].nCodeBits; if (nCodeBits==0) bStatus=false; nInputBitsBufSize = nInputBitsBufSize - nCodeBits; return pLookUp[nCode].nValue; } void CCIDecompressor::FillBits(sal_uInt8 * pTarget, sal_uInt16 nTargetBits, sal_uInt16 nBitPos, sal_uInt16 nNumBits, sal_uInt8 nBlackOrWhite) { if ( nBitPos >= nTargetBits ) return; if ( nBitPos + nNumBits > nTargetBits ) nNumBits = nTargetBits - nBitPos; pTarget+=nBitPos>>3; nBitPos&=7; if (nBlackOrWhite==0x00) *pTarget &= 0xff << (8-nBitPos); else *pTarget |= 0xff >> nBitPos; if (nNumBits>8-nBitPos) { nNumBits-=8-nBitPos; while (nNumBits>=8) { *(++pTarget)=nBlackOrWhite; nNumBits-=8; } if (nNumBits>0) *(++pTarget)=nBlackOrWhite; } } sal_uInt16 CCIDecompressor::CountBits(const sal_uInt8 * pData, sal_uInt16 nDataSizeBits, sal_uInt16 nBitPos, sal_uInt8 nBlackOrWhite) { // here the number of bits belonging together is being counted // which all have the color nBlackOrWhite (0xff or 0x00) // from the position nBitPos on sal_uInt16 nPos = nBitPos; for (;;) { if (nPos>=nDataSizeBits) { nPos=nDataSizeBits; break; } sal_uInt8 nData = pData[nPos>>3]; sal_uInt16 nLo = nPos & 7; if (nLo==0 && nData==nBlackOrWhite) { //fail on overflow attempt if (nPos > SAL_MAX_UINT16-8) return 0; nPos+=8; } else { if ( ((nData^nBlackOrWhite) & (0x80 >> nLo))!=0) break; ++nPos; } } if (nPos<=nBitPos) return 0; return nPos-nBitPos; } bool CCIDecompressor::Read1DScanlineData(sal_uInt8 * pTarget, sal_uInt16 nBitsToRead) { sal_uInt16 nTargetBits = nBitsToRead; sal_uInt16 nCode,nCodeBits,nDataBits,nTgtFreeByteBits; sal_uInt8 nByte; sal_uInt8 nBlackOrWhite; // is 0xff for black or 0x00 for white bool bTerminatingCode; // the first code is always a "white-code": nBlackOrWhite=0x00; // number of bits that aren't written in the byte *pTarget yet: nTgtFreeByteBits=8; // loop through codes from the input stream: do { // fetch next 13 bits into nCodem but don't remove them from // the input buffer: while (nInputBitsBufSize<13) { pIStream->ReadUChar( nByte ); if ( nOptions & CCI_OPTION_INVERSEBITORDER ) nByte = pByteSwap[ nByte ]; nInputBitsBuf=(nInputBitsBuf<<8) | (sal_uLong)nByte; nInputBitsBufSize+=8; } nCode=(sal_uInt16)((nInputBitsBuf>>(nInputBitsBufSize-13))&0x1fff); // determine the number of DataBits CodeBits: if (nBlackOrWhite) { nCodeBits=pBlackLookUp[nCode].nCodeBits; nDataBits=pBlackLookUp[nCode].nValue; } else { nCodeBits=pWhiteLookUp[nCode].nCodeBits; nDataBits=pWhiteLookUp[nCode].nValue; } // is that an invalid code? if ( nDataBits == 9999 ) { return nTargetBits == nBitsToRead; } if ( nCodeBits == 0 ) { return nTargetBits == nBitsToRead; // could be filling bits now } nEOLCount = 0; // too much data? if (nDataBits>nTargetBits) { // Yes, could be a subsequent error cause by an invalid code // Therefore continue anyhow: nDataBits=nTargetBits; } // is that a 'Terminating-Code'? bTerminatingCode = nDataBits<64; // remove the read bits from the input buffer: nInputBitsBufSize = nInputBitsBufSize - nCodeBits; // write the number of data bits into the scanline: if (nDataBits>0) { nTargetBits = nTargetBits - nDataBits; if (nBlackOrWhite==0x00) *pTarget &= 0xff << nTgtFreeByteBits; else *pTarget |= 0xff >> (8-nTgtFreeByteBits); if (nDataBits<=nTgtFreeByteBits) { if (nDataBits==nTgtFreeByteBits) { pTarget++; nTgtFreeByteBits=8; } else nTgtFreeByteBits = nTgtFreeByteBits - nDataBits; } else { nDataBits = nDataBits - nTgtFreeByteBits; pTarget++; nTgtFreeByteBits=8; if (nDataBits >= 8) { const sal_uInt16 nDataBytes = nDataBits / 8; memset(pTarget, nBlackOrWhite, nDataBytes); pTarget += nDataBytes; nDataBits -= nDataBytes * 8; } if (nDataBits>0) { *pTarget=nBlackOrWhite; nTgtFreeByteBits = nTgtFreeByteBits - nDataBits; } } } // should the situation arise, switch Black <-> White: if (bTerminatingCode) nBlackOrWhite = ~nBlackOrWhite; } while (nTargetBits>0 || !bTerminatingCode); return nTargetBits == nBitsToRead; } bool CCIDecompressor::Read2DScanlineData(sal_uInt8 * pTarget, sal_uInt16 nTargetBits) { sal_uInt16 n2DMode,nBitPos,nUncomp,nRun,nRun2,nt; sal_uInt8 nBlackOrWhite; nBlackOrWhite=0x00; nBitPos=0; while (nBitPos=64); nRun2=0; do { nt=ReadCodeAndDecode(pBlackLookUp.data(),13); nRun2 = nRun2 + nt; } while (nt>=64); } else { nRun=0; do { nt=ReadCodeAndDecode(pBlackLookUp.data(),13); nRun = nRun + nt; } while (nt>=64); nRun2=0; do { nt=ReadCodeAndDecode(pWhiteLookUp.data(),13); nRun2 = nRun2 + nt; } while (nt>=64); } FillBits(pTarget,nTargetBits,nBitPos,nRun,nBlackOrWhite); nBitPos = nBitPos + nRun; FillBits(pTarget,nTargetBits,nBitPos,nRun2,~nBlackOrWhite); nBitPos = nBitPos + nRun2; } else { // it's one of the modes CCI2DMODE_VERT_... if (nBitPos==0 && nBlackOrWhite==0x00 && CountBits(pLastLine.get(), nTargetBits, 0, 0xff)!=0) nRun=0; else { nRun = CountBits(pLastLine.get(), nTargetBits, nBitPos, ~nBlackOrWhite); nRun = nRun + CountBits(pLastLine.get(), nTargetBits, nBitPos + nRun, nBlackOrWhite); } nRun+=n2DMode-CCI2DMODE_VERT_0; FillBits(pTarget,nTargetBits,nBitPos,nRun,nBlackOrWhite); nBitPos = nBitPos + nRun; nBlackOrWhite=~nBlackOrWhite; } } return nBitPos == 0; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */