diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /lotuswordpro/source/filter/explode.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'lotuswordpro/source/filter/explode.cxx')
-rw-r--r-- | lotuswordpro/source/filter/explode.cxx | 509 |
1 files changed, 509 insertions, 0 deletions
diff --git a/lotuswordpro/source/filter/explode.cxx b/lotuswordpro/source/filter/explode.cxx new file mode 100644 index 000000000..a001254d0 --- /dev/null +++ b/lotuswordpro/source/filter/explode.cxx @@ -0,0 +1,509 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: IBM Corporation + * + * Copyright: 2008 by IBM Corporation + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include "explode.hxx" +#include <tools/stream.hxx> + +#include <algorithm> +#include <assert.h> +#include <math.h> + + const char Tree1String[][32] = { + "101", + "11", + "100", + "011", + "0101", + "0100", + "0011", + "00101", + "00100", + "00011", + "00010", + "000011", + "000010", + "000001", + "0000001", + "0000000", + }; + + const char Tree2String[][32] = { + "11" , + "1011" , + "1010" , + "10011" , + "10010" , + "10001" , + "10000" , + "011111" , + "011110" , + "011101" , + "011100" , + "011011" , + "011010" , + "011001" , + "011000" , + "010111" , + "010110" , + "010101" , + "010100" , + "010011" , + "010010" , + "010001" , + "0100001" , + "0100000" , + "0011111" , + "0011110" , + "0011101" , + "0011100" , + "0011011" , + "0011010" , + "0011001" , + "0011000" , + "0010111" , + "0010110" , + "0010101" , + "0010100" , + "0010011" , + "0010010" , + "0010001" , + "0010000" , + "0001111" , + "0001110" , + "0001101" , + "0001100" , + "0001011" , + "0001010" , + "0001001" , + "0001000" , + "00001111", + "00001110", + "00001101", + "00001100", + "00001011", + "00001010", + "00001001", + "00001000", + "00000111", + "00000110", + "00000101", + "00000100", + "00000011", + "00000010", + "00000001", + "00000000", + }; + +Decompression::Decompression(SvStream * pInStream, SvStream * pOutStream) + : m_pInStream(pInStream) + , m_pOutStream(pOutStream) + , m_nCurrent4Byte(0) + , m_nBitsLeft(0) + , m_pBuffer(m_Buffer) + , m_nBytesLeft(0) + , m_nOutputBufferPos(0) +{ + if (!m_pInStream || !m_pOutStream ) + { + assert(false); + } + ConstructTree1(); + ConstructTree2(); + fillArray(); +} +/** + * @descr read specified bits from input stream + * @argument iCount - number of bits to be read, less than 31 + * @argument nBits - bits read + * @return 0 - read OK, otherwise error + */ +sal_uInt32 Decompression::ReadBits(sal_uInt16 iCount, sal_uInt32 & nBits) +{ + if ( (iCount == 0) || (iCount > 31 ) ) + { + return 1; + } + + /* load at least need bits into val */ + sal_uInt32 val = m_nCurrent4Byte; /* bit accumulator */ + while (m_nBitsLeft < iCount) + { + if (m_nBytesLeft == 0) + { + m_nBytesLeft = m_pInStream->ReadBytes(m_Buffer, CHUNK); + m_pBuffer = m_Buffer; + if (m_nBytesLeft == 0) return 1; + } + val |= static_cast<sal_uInt32>(*m_pBuffer++) << m_nBitsLeft; /* load eight bits */ + m_nBytesLeft --; + m_nBitsLeft += 8; + } + + /* drop need bits and update buffer, always zero to seven bits left */ + m_nCurrent4Byte = val >> iCount; + m_nBitsLeft -= iCount; + + /* return need bits, zeroing the bits above that */ + nBits = val & ((1U << iCount) - 1); + + return 0; +} +/** + * @descr decompress input and write output + * @return 0 - read OK, otherwise error + */ +sal_Int32 Decompression::explode() +{ + /* The first 2 bytes are parameters */ + sal_uInt32 P1; + if (0 != ReadBits(8, P1))/* 0 or 1 */ + return -1; + + /* I think this means 0=binary and 1=ascii file, but in RESOURCEs I saw always 0 */ + if (P1 >= 1) // changed per 's review comments + return -1; + + sal_uInt32 P2; + if (0 != ReadBits(8, P2)) + return -1; + + /* must be 4,5 or 6 and it is a parameter for the decompression algorithm */ + if (P2 < 4 || P2 > 6) + return -2; + + m_nOutputBufferPos = 0; + /* Now, a bit stream follows, which is decoded as described below: */ + /* The algorithm terminates as soon as it runs out of bits. */ + while(true) + { + // read 1 bit (take bits from the lowest value (LSB) to the MSB i.e. bit 0, bit 1 etc ...) + sal_uInt32 iBit; + if (0 != ReadBits(1, iBit)) + break; + if ( 0 == (iBit & 0x01) ) + { + //if the bit is 0 read 8 bits and write it to the output as it is. + sal_uInt32 symbol; + if (0 != ReadBits(8, symbol)) + break; + m_Output[m_nOutputBufferPos++] = static_cast<sal_uInt8>(symbol); + if (m_nOutputBufferPos == MAXWIN) + { + m_pOutStream->WriteBytes(m_Output, m_nOutputBufferPos); + m_nOutputBufferPos = 0; + } + continue; + } + // if the bit is 1 we have here a length/distance pair: + // -decode a number with Hufmman Tree #1; variable bit length, result is 0x00 .. 0x0F -> L1 + sal_uInt32 L1 = Decode(m_Tree1.get()); + sal_uInt32 Length; + if (L1 <= 7) + { + //if L1 <= 7: + // LENGTH = L1 + 2 + Length = L1 + 2; + } + else + { + // if L1 > 7 + // read more (L1-7) bits -> L2 + // LENGTH = L2 + M[L1-7] + 2 + sal_uInt32 L2; + if (0 != ReadBits(static_cast<sal_uInt16>(L1 - 7), L2)) + break; + Length = L2 + 2 + m_iArrayOfM[L1 -7]; + } + if (Length == 519) + { + // end of compressed data + break; + } + + // - decode another number with Hufmann Tree #2 giving result 0x00..0x3F -> D1 + sal_uInt32 D1 = Decode(m_Tree2.get()); + sal_uInt32 D2; + if (Length == 2) + { + // if LENGTH == 2 + // D1 = D1 << 2 + // read 2 bits -> D2 + D1 = D1 << 2; + if (0 != ReadBits(2, D2)) + break; + } + else + { + // else + // D1 = D1 << P2 // the parameter 2 + // read P2 bits -> D2 + D1 = D1 << P2; + if (0 != ReadBits(static_cast<sal_uInt16>(P2), D2)) + break; + } + // DISTANCE = (D1 | D2) + 1 + sal_uInt32 distance = (D1 | D2) + 1; + + // - now copy LENGTH bytes from (output_ptr-DISTANCE) to output_ptr + // write current buffer to output + m_pOutStream->WriteBytes(m_Output, m_nOutputBufferPos); + m_nOutputBufferPos = 0; + + // remember current position + sal_uInt32 nOutputPos = m_pOutStream->Tell(); + if (distance > nOutputPos) + return -3; // format error + + m_pOutStream->FlushBuffer(); + // point back to copy position and read bytes + m_pOutStream->SeekRel(-static_cast<tools::Long>(distance)); + sal_uInt8 sTemp[MAXWIN]; + sal_uInt32 nRead = std::min(distance, Length); + m_pOutStream->ReadBytes(sTemp, nRead); + if (nRead != Length) + { + // fill the buffer with read content repeatedly until full + for (sal_uInt32 i=nRead; i<Length; i++) + { + sTemp[i] = sTemp[i-nRead]; + } + } + + // restore output stream position + m_pOutStream->Seek(nOutputPos); + + // write current buffer to output + m_pOutStream->WriteBytes(sTemp, Length); + } + return 0; +} +/** + * @descr bits to string + * @return + */ +void Decompression::ToString(sal_uInt32 nBits, char *pChar, sal_uInt32 nLen) +{ + sal_uInt32 nBit; + for (sal_uInt32 i=nLen; i > 0; i--) + { + nBit = (nBits >> (i -1) ) & 0x01; + pChar[nLen - i] = nBit ? '1':'0'; + } + pChar[nLen] = '\0'; +} + +/** + * @descr decode tree 1 for length + * @return the decoded value + */ +sal_uInt32 Decompression::Decode(HuffmanTreeNode * pRoot) +{ + sal_uInt32 nRet(0); + sal_uInt32 nRead, nReadAlready; + + if( 0 != ReadBits(1, nReadAlready)) + return 0; // something wrong + + for (sal_uInt16 i=2; i <= 8; i++) + { + if ( 0 != ReadBits(1, nRead)) + return 0; // something wrong + + nReadAlready = (nReadAlready << 1) | (nRead & 0x01); + + char sCode[16]; + ToString(nReadAlready, sCode, i); + nRet = pRoot->QueryValue(sCode); + if (nRet != 0xffffffff) + { + break; + } + } + return nRet; +} +/** + * @descr construct tree 1 for length + * @return + */ +void Decompression::ConstructTree1() +{ // Huffman Tree #1 + // The first huffman tree (the Section called Decompression algorithm HUFFMAN) contains the length values. It is described by the following table: + // value (hex) code (binary) + // 0 101 + // 1 11 + // 2 100 + // 3 011 + // 4 0101 + // 5 0100 + // 6 0011 + // 7 0010 1 + // 8 0010 0 + // 9 0001 1 + // a 0001 0 + // b 0000 11 + // c 0000 10 + // d 0000 01 + // e 0000 001 + // f 0000 000 + m_Tree1.reset( new HuffmanTreeNode()); + for (sal_uInt32 i=0; i< 16; i++) + { + m_Tree1->InsertNode(i, Tree1String[i]); + } + /* + m_Tree1->InsertNode(0, "101"); + m_Tree1->InsertNode(1, "11"); + m_Tree1->InsertNode(2, "100"); + m_Tree1->InsertNode(3, "011"); + m_Tree1->InsertNode(4, "0101"); + m_Tree1->InsertNode(5, "0100"); + m_Tree1->InsertNode(6, "0011"); + m_Tree1->InsertNode(7, "00101"); + m_Tree1->InsertNode(8, "00100"); + m_Tree1->InsertNode(9, "00011"); + m_Tree1->InsertNode(10, "00010"); + m_Tree1->InsertNode(11, "000011"); + m_Tree1->InsertNode(12, "000010"); + m_Tree1->InsertNode(13, "000001"); + m_Tree1->InsertNode(14, "0000001"); + m_Tree1->InsertNode(15, "0000000"); + */ +} +/** + * @descr construct tree 2 for distance + * @return + */ +void Decompression::ConstructTree2() +{ + + m_Tree2.reset(new HuffmanTreeNode()); + for (sal_uInt32 i=0; i< 64; i++) + { + m_Tree2->InsertNode(i, Tree2String[i]); + } + //where bits should be read from the left to the right. +} +/** + * @descr + * @return + */ +void Decompression::fillArray() +{ + m_iArrayOfM[0] = 7; + for (int i=1; i < 16; i++) + { + m_iArrayOfM[i] = m_iArrayOfM[i - 1]+ static_cast<sal_uInt32>(pow(2.0, i-1));//2 + } +} + +HuffmanTreeNode::HuffmanTreeNode(sal_uInt32 nValue):value(nValue) +{ +} +HuffmanTreeNode::~HuffmanTreeNode() +{ +} + +HuffmanTreeNode * HuffmanTreeNode::InsertNode(sal_uInt32 nValue, const char * pInCode) +{ + HuffmanTreeNode *pNew = new HuffmanTreeNode(nValue); + std::string aCode(pInCode); + + // query its parents + const char cLast = aCode.back(); + aCode.pop_back(); + HuffmanTreeNode * pParent = QueryNode(aCode.c_str()); + if (!pParent) + { + pParent = InsertNode(0xffffffff, aCode.c_str()); + } + if (cLast == '0') + pParent->left.reset(pNew); + else // (cChar == '1') + pParent->right.reset(pNew); + + return pNew; +} + +HuffmanTreeNode * HuffmanTreeNode::QueryNode(const char * pCode) +{ + sal_uInt32 nLen = strlen(pCode); + + HuffmanTreeNode * pNode = this; // this is the root + for(sal_uInt32 i=0; i<nLen && pNode; i++) + { + char cChar= pCode[i]; + if (cChar == '0') + { + pNode = pNode->left.get(); + } + else // (cChar == '1') + { + pNode = pNode->right.get(); + } + } + return pNode; +} + +sal_uInt32 HuffmanTreeNode::QueryValue(const char * pCode) +{ + HuffmanTreeNode * pNode =QueryNode(pCode); + if (pNode) + return pNode->value; + + return 0xffffffff; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |