blob: 91047e396e1318efe25ecfc2b72b2a518616b54e [file] [log] [blame]
/**************************************************************
*
* 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.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_filter.hxx"
#include "ccidecom.hxx"
//=============================== Huffman-Tabellen ========================
//---------------------------- 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 }
};
//================== Sicherheitskopie der Huffman-Tabellen ================
// Um sicher zugehen, dass die Huffman-Tabellen keine Fehler enthalten,
// wurden sie zweimal von unterschiedlichen Quellen eingegeben (Uff) und
// verglichen.
// Da sich aber im Laufe der Pflege des Source-Codes mal ein Fehler
// einschleichen koennte (z.B. versehentlicher druck einer Taste im Editor)
// werden die Tablellen hier weiterhin zweimal aufgefuehrt und zur Laufzeit
// verglichen. (Wenn der Vergleich fehlschlaegt, liefert CCIDecompressor
// immer einen Fehler). Das Ganze mag etwas wahnsinnig erscheinen, aber ein Fehler
// in den Tabellen waere sonst sehr sehr schwer zu erkennen, zumal es
// unwahrscheinlich ist, dass eine oder mehere Beispieldateien alle Codes
// durchlaufen.
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 ( sal_False ),
bStatus ( sal_False ),
pByteSwap ( NULL ),
nWidth ( nImageWidth ),
nOptions ( nOpts ),
pLastLine ( NULL )
{
if ( nOpts & CCI_OPTION_INVERSEBITORDER )
{
pByteSwap = 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 ));
}
}
pWhiteLookUp =new CCILookUpTableEntry[1<<13];
pBlackLookUp =new CCILookUpTableEntry[1<<13];
p2DModeLookUp=new CCILookUpTableEntry[1<<10];
pUncompLookUp=new CCILookUpTableEntry[1<<11];
MakeLookUp(CCIWhiteTable,CCIWhiteTableSave,pWhiteLookUp,CCIWhiteTableSize,13);
MakeLookUp(CCIBlackTable,CCIBlackTableSave,pBlackLookUp,CCIBlackTableSize,13);
MakeLookUp(CCI2DModeTable,CCI2DModeTableSave,p2DModeLookUp,CCI2DModeTableSize,10);
MakeLookUp(CCIUncompTable,CCIUncompTableSave,pUncompLookUp,CCIUncompTableSize,11);
}
CCIDecompressor::~CCIDecompressor()
{
delete[] pByteSwap;
delete[] pLastLine;
delete[] pWhiteLookUp;
delete[] pBlackLookUp;
delete[] p2DModeLookUp;
delete[] pUncompLookUp;
}
void CCIDecompressor::StartDecompression( SvStream & rIStream )
{
pIStream = &rIStream;
nInputBitsBufSize = 0;
bFirstEOL = sal_True;
bStatus = sal_True;
nEOLCount = 0;
if ( bTableBad == sal_True )
return;
}
sal_Bool CCIDecompressor::DecompressScanline( sal_uInt8 * pTarget, sal_uLong nTargetBits )
{
sal_uInt16 i;
sal_uInt8 * pSrc,* pDst;
sal_Bool b2D;
if ( nEOLCount >= 5 ) // RTC( Return To Controller )
return sal_True;
if ( bStatus == sal_False )
return sal_False;
// Wenn EOL-Codes vorhanden sind, steht der EOL-Code auch vor der ersten Zeile.
// (und ich dachte EOL heisst 'End Of Line'...)
// Daher lesen wir den EOL-Code immer vor jeder Zeile als erstes ein:
if ( nOptions & CCI_OPTION_EOL )
{
if ( bFirstEOL )
{
sal_uInt32 nCurPos = pIStream->Tell();
sal_uInt16 nOldInputBitsBufSize = nInputBitsBufSize;
sal_uInt32 nOldInputBitsBuf = nInputBitsBuf;
if ( ReadEOL( 32 ) == sal_False )
{
nInputBitsBufSize = nOldInputBitsBufSize;
nInputBitsBuf = nOldInputBitsBuf;
pIStream->Seek( nCurPos );
nOptions &=~ CCI_OPTION_EOL; // CCITT Group 3 - Compression Type 2
}
bFirstEOL = sal_False;
}
else
{
if ( ReadEOL( nTargetBits ) == sal_False )
{
return bStatus;
}
}
}
if ( nEOLCount >= 5 ) // RTC( Return To Controller )
return sal_True;
// ggf. eine weisse vorherige Zeile herstellen fuer 2D:
if ( nOptions & CCI_OPTION_2D )
{
if ( pLastLine == NULL || nLastLineSize != ( ( nTargetBits + 7 ) >> 3 ) )
{
if ( pLastLine == NULL )
delete[] pLastLine;
nLastLineSize = ( nTargetBits + 7 ) >> 3;
pLastLine = new sal_uInt8[ nLastLineSize ];
pDst = pLastLine;
for ( i = 0; i < nLastLineSize; i++ ) *( pDst++ ) = 0x00;
}
}
// ggf. Zeilen-Anfang auf naechste Byte-Grenze runden:
if ( nOptions & CCI_OPTION_BYTEALIGNROW )
nInputBitsBufSize &= 0xfff8;
// Ist es eine 2D-Zeile ?:
if ( nOptions & CCI_OPTION_2D )
{
if ( nOptions & CCI_OPTION_EOL )
b2D = Read2DTag();
else
b2D = sal_True;
}
else
b2D = sal_False;
// Zeile einlesen:
if ( b2D )
Read2DScanlineData( pTarget, (sal_uInt16)nTargetBits );
else
Read1DScanlineData( pTarget, (sal_uInt16)nTargetBits );
// Wenn wir im 2D-Modus sind, muessen wir uns die Zeile merken:
if ( nOptions & CCI_OPTION_2D && bStatus == sal_True )
{
pSrc = pTarget;
pDst = pLastLine;
for ( i = 0; i < nLastLineSize; i++ ) *(pDst++)=*(pSrc++);
}
if ( pIStream->GetError() )
bStatus = sal_False;
return bStatus;
}
void CCIDecompressor::MakeLookUp(const CCIHuffmanTableEntry * pHufTab,
const CCIHuffmanTableEntry * pHufTabSave,
CCILookUpTableEntry * pLookUp,
sal_uInt16 nHuffmanTableSize,
sal_uInt16 nMaxCodeBits)
{
sal_uInt16 i,j,nMinCode,nMaxCode,nLookUpSize,nMask;
if (bTableBad==sal_True) return;
nLookUpSize=1<<nMaxCodeBits;
nMask=0xffff>>(16-nMaxCodeBits);
for (i=0; i<nLookUpSize; i++) pLookUp[i].nCodeBits=0;
for (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=sal_True;
return;
}
nMinCode = nMask & (pHufTab[i].nCode << (nMaxCodeBits-pHufTab[i].nCodeBits));
nMaxCode = nMinCode | (nMask >> pHufTab[i].nCodeBits);
for (j=nMinCode; j<=nMaxCode; j++) {
if (pLookUp[j].nCodeBits!=0) {
bTableBad=sal_True;
return;
}
pLookUp[j].nValue=pHufTab[i].nValue;
pLookUp[j].nCodeBits=pHufTab[i].nCodeBits;
}
}
}
sal_Bool CCIDecompressor::ReadEOL( sal_uInt32 /*nMaxFillBits*/ )
{
sal_uInt16 nCode;
sal_uInt8 nByte;
// if (nOptions&CCI_OPTION_BYTEALIGNEOL) nMaxFillBits=7; else nMaxFillBits=0;
// Buuuh: Entweder wird die Option in itiff.cxx nicht richtig gesetzt (-> Fehler in Doku)
// oder es gibt tatsaechlich gemeine Export-Filter, die immer ein Align machen.
// Ausserdem wurden Dateien gefunden, in denen mehr als die maximal 7 noetigen
// Fuellbits vor dem EOL-Code stehen. Daher akzeptieren wir nun grundsaetzlich
// bis zu 32-Bloedsinn-Bits vor dem EOL-Code:
// und ich habe eine Datei gefunden in der bis zu ??? Bloedsinn Bits stehen, zudem ist dort die Bit Reihenfolge verdreht (SJ);
sal_uInt32 nMaxPos = pIStream->Tell();
nMaxPos += nWidth >> 3;
for ( ;; )
{
while ( nInputBitsBufSize < 12 )
{
*pIStream >> nByte;
if ( pIStream->IsEof() )
return sal_False;
if ( pIStream->Tell() > nMaxPos )
return sal_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 sal_True;
}
sal_Bool CCIDecompressor::Read2DTag()
{
sal_uInt8 nByte;
// Ein Bit einlesen und sal_True liefern, wenn es 0 ist, sonst sal_False
if (nInputBitsBufSize==0) {
*pIStream >> nByte;
if ( nOptions & CCI_OPTION_INVERSEBITORDER )
nByte = pByteSwap[ nByte ];
nInputBitsBuf=(sal_uLong)nByte;
nInputBitsBufSize=8;
}
nInputBitsBufSize--;
if ( ((nInputBitsBuf>>nInputBitsBufSize)&0x0001) ) return sal_False;
else return sal_True;
}
sal_uInt8 CCIDecompressor::ReadBlackOrWhite()
{
sal_uInt8 nByte;
// Ein Bit einlesen und 0x00 liefern, wenn es 0 ist, sonst 0xff
if (nInputBitsBufSize==0) {
*pIStream >> 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)
{
sal_uInt16 nCode,nCodeBits;
sal_uInt8 nByte;
// Einen Huffman-Code einlesen und dekodieren:
while (nInputBitsBufSize<nMaxCodeBits) {
*pIStream >> nByte;
if ( nOptions & CCI_OPTION_INVERSEBITORDER )
nByte = pByteSwap[ nByte ];
nInputBitsBuf=(nInputBitsBuf<<8) | (sal_uLong)nByte;
nInputBitsBufSize+=8;
}
nCode=(sal_uInt16)((nInputBitsBuf>>(nInputBitsBufSize-nMaxCodeBits))
&(0xffff>>(16-nMaxCodeBits)));
nCodeBits=pLookUp[nCode].nCodeBits;
if (nCodeBits==0) bStatus=sal_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)
{
sal_uInt16 nPos,nLo;
sal_uInt8 nData;
// Hier wird die Anzahl der zusammenhaengenden Bits gezaehlt, die
// ab Position nBitPos in pTarget alle die Farbe nBlackOrWhite
// (0xff oder 0x00) haben.
nPos=nBitPos;
for (;;) {
if (nPos>=nDataSizeBits) {
nPos=nDataSizeBits;
break;
}
nData=pData[nPos>>3];
nLo=nPos & 7;
if ( nLo==0 && nData==nBlackOrWhite) nPos+=8;
else {
if ( ((nData^nBlackOrWhite) & (0x80 >> nLo))!=0) break;
nPos++;
}
}
if (nPos<=nBitPos) return 0;
else return nPos-nBitPos;
}
void CCIDecompressor::Read1DScanlineData(sal_uInt8 * pTarget, sal_uInt16 nTargetBits)
{
sal_uInt16 nCode,nCodeBits,nDataBits,nTgtFreeByteBits;
sal_uInt8 nByte;
sal_uInt8 nBlackOrWhite; // ist 0xff fuer Black oder 0x00 fuer White
sal_Bool bTerminatingCode;
// Der erste Code ist immer eine "White-Code":
nBlackOrWhite=0x00;
// Anzahl der Bits, die im Byte *pTarget noch nicht geschrieben sind:
nTgtFreeByteBits=8;
// Schleife ueber Codes aus dem Eingabe-Stream:
do {
// die naechsten 13 Bits nach nCode holen, aber noch nicht
// aus dem Eingabe-Buffer loeschen:
while (nInputBitsBufSize<13) {
*pIStream >> nByte;
if ( nOptions & CCI_OPTION_INVERSEBITORDER )
nByte = pByteSwap[ nByte ];
nInputBitsBuf=(nInputBitsBuf<<8) | (sal_uLong)nByte;
nInputBitsBufSize+=8;
}
nCode=(sal_uInt16)((nInputBitsBuf>>(nInputBitsBufSize-13))&0x1fff);
// Anzahl der DatenBits und Anzahl der CodeBits ermitteln:
if (nBlackOrWhite) {
nCodeBits=pBlackLookUp[nCode].nCodeBits;
nDataBits=pBlackLookUp[nCode].nValue;
}
else {
nCodeBits=pWhiteLookUp[nCode].nCodeBits;
nDataBits=pWhiteLookUp[nCode].nValue;
}
// Ist es ein Ungueltiger Code ?
if ( nDataBits == 9999 )
{
return;
}
if ( nCodeBits == 0 )
{
return; // das koennen sich jetzt um FuellBits handeln
}
nEOLCount = 0;
// Zuviele Daten ?
if (nDataBits>nTargetBits) {
// Ja, koennte ein Folge-Fehler durch ungueltigen Code sein,
// daher irdenwie weitermachen:
nDataBits=nTargetBits;
}
// Ist es ein 'Terminating-Code' ?
if (nDataBits<64) bTerminatingCode=sal_True; else bTerminatingCode=sal_False;
// Die gelesenen Bits aus dem Eingabe-Buffer entfernen:
nInputBitsBufSize = nInputBitsBufSize - nCodeBits;
// Die Anzahl Daten-Bits in die Scanline schreiben:
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;
while (nDataBits>=8) {
*(pTarget++)=nBlackOrWhite;
nDataBits-=8;
}
if (nDataBits>0) {
*pTarget=nBlackOrWhite;
nTgtFreeByteBits = nTgtFreeByteBits - nDataBits;
}
}
}
// ggf. Umschaltung Black <-> White:
if (bTerminatingCode==sal_True) nBlackOrWhite=~nBlackOrWhite;
} while (nTargetBits>0 || bTerminatingCode==sal_False);
}
void 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<nTargetBits && bStatus==sal_True) {
n2DMode=ReadCodeAndDecode(p2DModeLookUp,10);
if (bStatus==sal_False) return;
if (n2DMode==CCI2DMODE_UNCOMP) {
for (;;) {
nUncomp=ReadCodeAndDecode(pUncompLookUp,11);
if ( nUncomp <= CCIUNCOMP_4White_1Black ) {
nRun=nUncomp-CCIUNCOMP_0White_1Black;
FillBits(pTarget,nTargetBits,nBitPos,nRun,0x00);
nBitPos = nBitPos + nRun;
FillBits(pTarget,nTargetBits,nBitPos,1,0xff);
nBitPos++;
}
else if ( nUncomp == CCIUNCOMP_5White ) {
FillBits(pTarget,nTargetBits,nBitPos,5,0x00);
nBitPos = nBitPos + 5;
}
else {
nRun=nUncomp-CCIUNCOMP_0White_End;
FillBits(pTarget,nTargetBits,nBitPos,nRun,0x00);
nBitPos = nBitPos + nRun;
nBlackOrWhite=ReadBlackOrWhite();
break;
}
}
}
else if (n2DMode==CCI2DMODE_PASS) {
if (nBitPos==0 && nBlackOrWhite==0x00 && CountBits(pLastLine,nTargetBits,0,0xff)!=0) nRun=0;
else {
nRun=CountBits(pLastLine,nTargetBits,nBitPos,~nBlackOrWhite);
nRun = nRun + CountBits(pLastLine,nTargetBits,nBitPos+nRun,nBlackOrWhite);
}
nRun = nRun + CountBits(pLastLine,nTargetBits,nBitPos+nRun,~nBlackOrWhite);
FillBits(pTarget,nTargetBits,nBitPos,nRun,nBlackOrWhite);
nBitPos = nBitPos + nRun;
}
else if (n2DMode==CCI2DMODE_HORZ) {
if (nBlackOrWhite==0x00) {
nRun=0;
do {
nt=ReadCodeAndDecode(pWhiteLookUp,13);
nRun = nRun + nt;
} while (nt>=64);
nRun2=0;
do {
nt=ReadCodeAndDecode(pBlackLookUp,13);
nRun2 = nRun2 + nt;
} while (nt>=64);
}
else {
nRun=0;
do {
nt=ReadCodeAndDecode(pBlackLookUp,13);
nRun = nRun + nt;
} while (nt>=64);
nRun2=0;
do {
nt=ReadCodeAndDecode(pWhiteLookUp,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 { // Es ist einer der Modi CCI2DMODE_VERT_...
if (nBitPos==0 && nBlackOrWhite==0x00 && CountBits(pLastLine,nTargetBits,0,0xff)!=0) nRun=0;
else {
nRun=CountBits(pLastLine,nTargetBits,nBitPos,~nBlackOrWhite);
nRun = nRun + CountBits(pLastLine,nTargetBits,nBitPos+nRun,nBlackOrWhite);
}
nRun+=n2DMode-CCI2DMODE_VERT_0;
FillBits(pTarget,nTargetBits,nBitPos,nRun,nBlackOrWhite);
nBitPos = nBitPos + nRun;
nBlackOrWhite=~nBlackOrWhite;
}
}
}