1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_filter.hxx"
26 
27 #include <tools/stream.hxx>
28 #include "giflzwc.hxx"
29 
30 // ----------------------------
31 // - GIFImageDataOutputStream -
32 // ----------------------------
33 
34 class GIFImageDataOutputStream
35 {
36 private:
37 
38 	void		FlushBlockBuf();
39 	inline void	FlushBitsBufsFullBytes();
40 
41 	SvStream&	rStream;
42 	sal_uInt8*		pBlockBuf;
43 	sal_uInt8		nBlockBufSize;
44 	sal_uLong		nBitsBuf;
45 	sal_uInt16		nBitsBufSize;
46 
47 public:
48 
49 				GIFImageDataOutputStream( SvStream & rGIF, sal_uInt8 nLZWDataSize );
50 				~GIFImageDataOutputStream();
51 
52 	inline void	WriteBits( sal_uInt16 nCode, sal_uInt16 nCodeLen );
53 };
54 
55 // ------------------------------------------------------------------------
56 
FlushBitsBufsFullBytes()57 inline void GIFImageDataOutputStream::FlushBitsBufsFullBytes()
58 {
59 	while (nBitsBufSize>=8)
60 	{
61 		if( nBlockBufSize==255 )
62 			FlushBlockBuf();
63 
64 		pBlockBuf[nBlockBufSize++] = (sal_uInt8) nBitsBuf;
65 		nBitsBuf >>= 8;
66 		nBitsBufSize -= 8;
67 	}
68 }
69 
70 // ------------------------------------------------------------------------
71 
WriteBits(sal_uInt16 nCode,sal_uInt16 nCodeLen)72 inline void GIFImageDataOutputStream::WriteBits( sal_uInt16 nCode, sal_uInt16 nCodeLen )
73 {
74 	if( nBitsBufSize+nCodeLen>32 )
75 		FlushBitsBufsFullBytes();
76 
77 	nBitsBuf |= (sal_uLong) nCode << nBitsBufSize;
78 	nBitsBufSize = nBitsBufSize + nCodeLen;
79 }
80 
81 // ------------------------------------------------------------------------
82 
GIFImageDataOutputStream(SvStream & rGIF,sal_uInt8 nLZWDataSize)83 GIFImageDataOutputStream::GIFImageDataOutputStream( SvStream & rGIF, sal_uInt8 nLZWDataSize ) :
84 		rStream(rGIF)
85 {
86 	pBlockBuf = new sal_uInt8[ 255 ];
87 	nBlockBufSize = 0;
88 	nBitsBufSize = 0;
89 	nBitsBuf = 0;
90 	rStream << nLZWDataSize;
91 }
92 
93 // ------------------------------------------------------------------------
94 
95 
~GIFImageDataOutputStream()96 GIFImageDataOutputStream::~GIFImageDataOutputStream()
97 {
98 	WriteBits(0,7);
99 	FlushBitsBufsFullBytes();
100 	FlushBlockBuf();
101 	rStream << (sal_uInt8)0;
102 	delete[] pBlockBuf;
103 }
104 
105 // ------------------------------------------------------------------------
106 
FlushBlockBuf()107 void GIFImageDataOutputStream::FlushBlockBuf()
108 {
109 	if( nBlockBufSize )
110 	{
111 		rStream << (sal_uInt8) nBlockBufSize;
112 		rStream.Write( pBlockBuf,nBlockBufSize );
113 		nBlockBufSize = 0;
114 	}
115 }
116 
117 // -------------------
118 // - GIFLZWCTreeNode -
119 // -------------------
120 
121 struct GIFLZWCTreeNode
122 {
123 
124 	GIFLZWCTreeNode*	pBrother;		// naechster Knoten, der den selben Vater hat
125 	GIFLZWCTreeNode*	pFirstChild;	// erster Sohn
126 	sal_uInt16				nCode;			// Der Code fuer den String von Pixelwerten, der sich ergibt, wenn
127 	sal_uInt16				nValue;			// Der Pixelwert
128 };
129 
130 // --------------------
131 // - GIFLZWCompressor -
132 // --------------------
133 
GIFLZWCompressor()134 GIFLZWCompressor::GIFLZWCompressor()
135 {
136 	pIDOS=NULL;
137 }
138 
139 // ------------------------------------------------------------------------
140 
~GIFLZWCompressor()141 GIFLZWCompressor::~GIFLZWCompressor()
142 {
143 	if (pIDOS!=NULL) EndCompression();
144 }
145 
146 // ------------------------------------------------------------------------
147 
StartCompression(SvStream & rGIF,sal_uInt16 nPixelSize)148 void GIFLZWCompressor::StartCompression( SvStream& rGIF, sal_uInt16 nPixelSize )
149 {
150 	if( !pIDOS )
151 	{
152 		sal_uInt16 i;
153 
154 		nDataSize = nPixelSize;
155 
156 		if( nDataSize < 2 )
157 			nDataSize=2;
158 
159 		nClearCode=1<<nDataSize;
160 		nEOICode=nClearCode+1;
161 		nTableSize=nEOICode+1;
162 		nCodeSize=nDataSize+1;
163 
164 		pIDOS=new GIFImageDataOutputStream(rGIF,(sal_uInt8)nDataSize);
165 		pTable=new GIFLZWCTreeNode[4096];
166 
167 		for (i=0; i<4096; i++)
168 		{
169 			pTable[i].pBrother = pTable[i].pFirstChild = NULL;
170 			pTable[i].nValue = (sal_uInt8) ( pTable[i].nCode = i );
171 		}
172 
173 		pPrefix = NULL;
174 		pIDOS->WriteBits( nClearCode,nCodeSize );
175 	}
176 }
177 
178 // ------------------------------------------------------------------------
179 
Compress(HPBYTE pSrc,sal_uLong nSize)180 void GIFLZWCompressor::Compress( HPBYTE pSrc, sal_uLong nSize )
181 {
182 	if( pIDOS )
183 	{
184 		GIFLZWCTreeNode*	p;
185 		sal_uInt16				i;
186 		sal_uInt8				nV;
187 
188 		if( !pPrefix && nSize )
189 		{
190 			pPrefix=pTable+(*pSrc++);
191 			nSize--;
192 		}
193 
194 		while( nSize )
195 		{
196 			nSize--;
197 			nV=*pSrc++;
198 			for( p=pPrefix->pFirstChild; p!=NULL; p=p->pBrother )
199 			{
200 				if (p->nValue==nV)
201 					break;
202 			}
203 
204 			if( p)
205 				pPrefix=p;
206 			else
207 			{
208 				pIDOS->WriteBits(pPrefix->nCode,nCodeSize);
209 
210 				if (nTableSize==4096)
211 				{
212 					pIDOS->WriteBits(nClearCode,nCodeSize);
213 
214 					for (i=0; i<nClearCode; i++)
215 						pTable[i].pFirstChild=NULL;
216 
217 					nCodeSize=nDataSize+1;
218 					nTableSize=nEOICode+1;
219 				}
220 				else
221 				{
222 					if(nTableSize==(sal_uInt16)(1<<nCodeSize))
223 						nCodeSize++;
224 
225 					p=pTable+(nTableSize++);
226 					p->pBrother=pPrefix->pFirstChild;
227 					pPrefix->pFirstChild=p;
228 					p->nValue=nV;
229 					p->pFirstChild=NULL;
230 				}
231 
232 				pPrefix=pTable+nV;
233 			}
234 		}
235 	}
236 }
237 
238 // ------------------------------------------------------------------------
239 
EndCompression()240 void GIFLZWCompressor::EndCompression()
241 {
242 	if( pIDOS )
243 	{
244 		if( pPrefix )
245 			pIDOS->WriteBits(pPrefix->nCode,nCodeSize);
246 
247 		pIDOS->WriteBits( nEOICode,nCodeSize );
248 		delete[] pTable;
249 		delete pIDOS;
250 		pIDOS=NULL;
251 	}
252 }
253