bump product version to 6.1.0.2
[LibreOffice.git] / lotuswordpro / source / filter / explode.cxx
blob731c6bc099d9e7105b1f122e2b6001510d12f51d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * The Contents of this file are made available subject to the terms of
5 * either of the following licenses
7 * - GNU Lesser General Public License Version 2.1
8 * - Sun Industry Standards Source License Version 1.1
10 * Sun Microsystems Inc., October, 2000
12 * GNU Lesser General Public License Version 2.1
13 * =============================================
14 * Copyright 2000 by Sun Microsystems, Inc.
15 * 901 San Antonio Road, Palo Alto, CA 94303, USA
17 * This library is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU Lesser General Public
19 * License version 2.1, as published by the Free Software Foundation.
21 * This library is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * Lesser General Public License for more details.
26 * You should have received a copy of the GNU Lesser General Public
27 * License along with this library; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
29 * MA 02111-1307 USA
32 * Sun Industry Standards Source License Version 1.1
33 * =================================================
34 * The contents of this file are subject to the Sun Industry Standards
35 * Source License Version 1.1 (the "License"); You may not use this file
36 * except in compliance with the License. You may obtain a copy of the
37 * License at http://www.openoffice.org/license.html.
39 * Software provided under this License is provided on an "AS IS" basis,
40 * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
41 * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
42 * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
43 * See the License for the specific provisions governing your rights and
44 * obligations concerning the Software.
46 * The Initial Developer of the Original Code is: IBM Corporation
48 * Copyright: 2008 by IBM Corporation
50 * All Rights Reserved.
52 * Contributor(s): _______________________________________
55 ************************************************************************/
57 #include "explode.hxx"
58 #include <tools/stream.hxx>
60 #include <algorithm>
61 #include <assert.h>
62 #include <math.h>
64 const static char Tree1String[][32] = {
65 "101",
66 "11",
67 "100",
68 "011",
69 "0101",
70 "0100",
71 "0011",
72 "00101",
73 "00100",
74 "00011",
75 "00010",
76 "000011",
77 "000010",
78 "000001",
79 "0000001",
80 "0000000",
83 const static char Tree2String[][32] = {
84 "11" ,
85 "1011" ,
86 "1010" ,
87 "10011" ,
88 "10010" ,
89 "10001" ,
90 "10000" ,
91 "011111" ,
92 "011110" ,
93 "011101" ,
94 "011100" ,
95 "011011" ,
96 "011010" ,
97 "011001" ,
98 "011000" ,
99 "010111" ,
100 "010110" ,
101 "010101" ,
102 "010100" ,
103 "010011" ,
104 "010010" ,
105 "010001" ,
106 "0100001" ,
107 "0100000" ,
108 "0011111" ,
109 "0011110" ,
110 "0011101" ,
111 "0011100" ,
112 "0011011" ,
113 "0011010" ,
114 "0011001" ,
115 "0011000" ,
116 "0010111" ,
117 "0010110" ,
118 "0010101" ,
119 "0010100" ,
120 "0010011" ,
121 "0010010" ,
122 "0010001" ,
123 "0010000" ,
124 "0001111" ,
125 "0001110" ,
126 "0001101" ,
127 "0001100" ,
128 "0001011" ,
129 "0001010" ,
130 "0001001" ,
131 "0001000" ,
132 "00001111",
133 "00001110",
134 "00001101",
135 "00001100",
136 "00001011",
137 "00001010",
138 "00001001",
139 "00001000",
140 "00000111",
141 "00000110",
142 "00000101",
143 "00000100",
144 "00000011",
145 "00000010",
146 "00000001",
147 "00000000",
150 Decompression::Decompression(SvStream * pInStream, SvStream * pOutStream)
151 : m_pInStream(pInStream)
152 , m_pOutStream(pOutStream)
153 , m_nCurrent4Byte(0)
154 , m_nBitsLeft(0)
155 , m_pBuffer(m_Buffer)
156 , m_nBytesLeft(0)
157 , m_nOutputBufferPos(0)
159 if (!m_pInStream || !m_pOutStream )
161 assert(false);
163 ConstructTree1();
164 ConstructTree2();
165 fillArray();
168 * @descr read specified bits from input stream
169 * @argument iCount - number of bits to be read, less than 31
170 * @argument nBits - bits read
171 * @return 0 - read OK, otherwise error
173 sal_uInt32 Decompression::ReadBits(sal_uInt16 iCount, sal_uInt32 & nBits)
175 if ( (iCount == 0) || (iCount > 31 ) )
177 return 1;
180 sal_uInt32 val = 0; /* bit accumulator */
182 /* load at least need bits into val */
183 val = m_nCurrent4Byte;
184 while (m_nBitsLeft < iCount)
186 if (m_nBytesLeft == 0)
188 m_nBytesLeft = m_pInStream->ReadBytes(m_Buffer, CHUNK);
189 m_pBuffer = m_Buffer;
190 if (m_nBytesLeft == 0) return 1;
192 val |= static_cast<sal_uInt32>(*m_pBuffer++) << m_nBitsLeft; /* load eight bits */
193 m_nBytesLeft --;
194 m_nBitsLeft += 8;
197 /* drop need bits and update buffer, always zero to seven bits left */
198 m_nCurrent4Byte = val >> iCount;
199 m_nBitsLeft -= iCount;
201 /* return need bits, zeroing the bits above that */
202 nBits = val & ((1 << iCount) - 1);
204 return 0;
207 * @descr decompress input and write output
208 * @return 0 - read OK, otherwise error
210 sal_Int32 Decompression::explode()
212 /* The first 2 bytes are parameters */
213 sal_uInt32 P1;
214 if (0 != ReadBits(8, P1))/* 0 or 1 */
215 return -1;
217 /* I think this means 0=binary and 1=ascii file, but in RESOURCEs I saw always 0 */
218 if (P1 >= 1) // changed per 's review comments
219 return -1;
221 sal_uInt32 P2;
222 if (0 != ReadBits(8, P2))
223 return -1;
225 /* must be 4,5 or 6 and it is a parameter for the decompression algorithm */
226 if (P2 < 4 || P2 > 6)
227 return -2;
229 m_nOutputBufferPos = 0;
230 /* Now, a bit stream follows, which is decoded as described below: */
231 /* The algorithm terminates as soon as it runs out of bits. */
232 while(true)
234 // read 1 bit (take bits from the lowest value (LSB) to the MSB i.e. bit 0, bit 1 etc ...)
235 sal_uInt32 iBit;
236 if (0 != ReadBits(1, iBit))
237 break;
238 if ( 0 == (iBit & 0x01) )
240 //if the bit is 0 read 8 bits and write it to the output as it is.
241 sal_uInt32 symbol;
242 if (0 != ReadBits(8, symbol))
243 break;
244 m_Output[m_nOutputBufferPos++] = static_cast<sal_uInt8>(symbol);
245 if (m_nOutputBufferPos == MAXWIN)
247 m_pOutStream->WriteBytes(m_Output, m_nOutputBufferPos);
248 m_nOutputBufferPos = 0;
250 continue;
252 // if the bit is 1 we have here a length/distance pair:
253 // -decode a number with Hufmman Tree #1; variable bit length, result is 0x00 .. 0x0F -> L1
254 sal_uInt32 L1 = Decode(m_Tree1.get());
255 sal_uInt32 Length;
256 if (L1 <= 7)
258 //if L1 <= 7:
259 // LENGTH = L1 + 2
260 Length = L1 + 2;
262 else
264 // if L1 > 7
265 // read more (L1-7) bits -> L2
266 // LENGTH = L2 + M[L1-7] + 2
267 sal_uInt32 L2;
268 if (0 != ReadBits(static_cast<sal_uInt16>(L1 - 7), L2))
269 break;
270 Length = L2 + 2 + m_iArrayOfM[L1 -7];
272 if (Length == 519)
274 // end of compressed data
275 break;
278 // - decode another number with Hufmann Tree #2 giving result 0x00..0x3F -> D1
279 sal_uInt32 D1 = Decode(m_Tree2.get());
280 sal_uInt32 D2;
281 if (Length == 2)
283 // if LENGTH == 2
284 // D1 = D1 << 2
285 // read 2 bits -> D2
286 D1 = D1 << 2;
287 if (0 != ReadBits(2, D2))
288 break;
290 else
292 // else
293 // D1 = D1 << P2 // the parameter 2
294 // read P2 bits -> D2
295 D1 = D1 << P2;
296 if (0 != ReadBits(static_cast<sal_uInt16>(P2), D2))
297 break;
299 // DISTANCE = (D1 | D2) + 1
300 sal_uInt32 distance = (D1 | D2) + 1;
302 // - now copy LENGTH bytes from (output_ptr-DISTANCE) to output_ptr
303 // write current buffer to output
304 m_pOutStream->WriteBytes(m_Output, m_nOutputBufferPos);
305 m_nOutputBufferPos = 0;
307 // remember current position
308 sal_uInt32 nOutputPos = m_pOutStream->Tell();
309 if (distance > nOutputPos)
310 return -3; // format error
312 m_pOutStream->Flush();
313 // point back to copy position and read bytes
314 m_pOutStream->SeekRel(-static_cast<long>(distance));
315 sal_uInt8 sTemp[MAXWIN];
316 sal_uInt32 nRead = std::min(distance, Length);
317 m_pOutStream->ReadBytes(sTemp, nRead);
318 if (nRead != Length)
320 // fill the buffer with read content repeatedly until full
321 for (sal_uInt32 i=nRead; i<Length; i++)
323 sTemp[i] = sTemp[i-nRead];
327 // restore output stream position
328 m_pOutStream->Seek(nOutputPos);
330 // write current buffer to output
331 m_pOutStream->WriteBytes(sTemp, Length);
333 return 0;
336 * @descr bits to string
337 * @return
339 void Decompression::ToString(sal_uInt32 nBits, sal_Char *pChar, sal_uInt32 nLen)
341 sal_uInt32 nBit;
342 for (sal_uInt32 i=nLen; i > 0; i--)
344 nBit = (nBits >> (i -1) ) & 0x01;
345 pChar[nLen - i] = nBit ? '1':'0';
347 pChar[nLen] = '\0';
351 * @descr decode tree 1 for length
352 * @return the decoded value
354 sal_uInt32 Decompression::Decode(HuffmanTreeNode * pRoot)
356 sal_uInt32 nRet(0);
357 sal_uInt32 nRead, nReadAlready;
359 if( 0 != ReadBits(1, nReadAlready))
360 return 0; // something wrong
362 for (sal_uInt16 i=2; i <= 8; i++)
364 if ( 0 != ReadBits(1, nRead))
365 return 0; // something wrong
367 nReadAlready = (nReadAlready << 1) | (nRead & 0x01);
369 sal_Char sCode[16];
370 ToString(nReadAlready, sCode, i);
371 nRet = pRoot->QueryValue(sCode);
372 if (nRet != 0xffffffff)
374 break;
377 return nRet;
380 * @descr construct tree 1 for length
381 * @return
383 void Decompression::ConstructTree1()
384 { // Huffman Tree #1
385 // The first huffman tree (the Section called Decompression algorithm HUFFMAN) contains the length values. It is described by the following table:
386 // value (hex) code (binary)
387 // 0 101
388 // 1 11
389 // 2 100
390 // 3 011
391 // 4 0101
392 // 5 0100
393 // 6 0011
394 // 7 0010 1
395 // 8 0010 0
396 // 9 0001 1
397 // a 0001 0
398 // b 0000 11
399 // c 0000 10
400 // d 0000 01
401 // e 0000 001
402 // f 0000 000
403 m_Tree1.reset( new HuffmanTreeNode());
404 for (sal_uInt32 i=0; i< 16; i++)
406 m_Tree1->InsertNode(i, Tree1String[i]);
409 m_Tree1->InsertNode(0, "101");
410 m_Tree1->InsertNode(1, "11");
411 m_Tree1->InsertNode(2, "100");
412 m_Tree1->InsertNode(3, "011");
413 m_Tree1->InsertNode(4, "0101");
414 m_Tree1->InsertNode(5, "0100");
415 m_Tree1->InsertNode(6, "0011");
416 m_Tree1->InsertNode(7, "00101");
417 m_Tree1->InsertNode(8, "00100");
418 m_Tree1->InsertNode(9, "00011");
419 m_Tree1->InsertNode(10, "00010");
420 m_Tree1->InsertNode(11, "000011");
421 m_Tree1->InsertNode(12, "000010");
422 m_Tree1->InsertNode(13, "000001");
423 m_Tree1->InsertNode(14, "0000001");
424 m_Tree1->InsertNode(15, "0000000");
428 * @descr construct tree 2 for distance
429 * @return
431 void Decompression::ConstructTree2()
434 m_Tree2.reset(new HuffmanTreeNode());
435 for (sal_uInt32 i=0; i< 64; i++)
437 m_Tree2->InsertNode(i, Tree2String[i]);
439 //where bits should be read from the left to the right.
442 * @descr
443 * @return
445 void Decompression::fillArray()
447 m_iArrayOfM[0] = 7;
448 for (int i=1; i < 16; i++)
450 m_iArrayOfM[i] = m_iArrayOfM[i - 1]+ static_cast<sal_uInt32>(pow(2.0, i-1));//2
454 HuffmanTreeNode::HuffmanTreeNode(sal_uInt32 nValue):value(nValue)
457 HuffmanTreeNode::~HuffmanTreeNode()
461 HuffmanTreeNode * HuffmanTreeNode::InsertNode(sal_uInt32 nValue, const sal_Char * pInCode)
463 HuffmanTreeNode *pNew = new HuffmanTreeNode(nValue);
464 std::string aCode(pInCode);
466 // query its parents
467 const sal_Char cLast = aCode.back();
468 aCode.pop_back();
469 HuffmanTreeNode * pParent = QueryNode(aCode.c_str());
470 if (!pParent)
472 pParent = InsertNode(0xffffffff, aCode.c_str());
474 if (cLast == '0')
475 pParent->left.reset(pNew);
476 else // (cChar == '1')
477 pParent->right.reset(pNew);
479 return pNew;
482 HuffmanTreeNode * HuffmanTreeNode::QueryNode(const sal_Char * pCode)
484 sal_uInt32 nLen = strlen(pCode);
486 HuffmanTreeNode * pNode = this; // this is the root
487 for(sal_uInt32 i=0; i<nLen && pNode; i++)
489 sal_Char cChar= pCode[i];
490 if (cChar == '0')
492 pNode = pNode->left.get();
494 else // (cChar == '1')
496 pNode = pNode->right.get();
499 return pNode;
502 sal_uInt32 HuffmanTreeNode::QueryValue(const sal_Char * pCode)
504 HuffmanTreeNode * pNode =QueryNode(pCode);
505 if (pNode)
506 return pNode->value;
508 return 0xffffffff;
511 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */