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_svtools.hxx"
26 
27 #define XBMMINREAD 512
28 
29 #define _XBMPRIVATE
30 #include <ctype.h>
31 #include "xbmread.hxx"
32 
33 // -------------
34 // - XBMReader -
35 // -------------
36 
XBMReader(SvStream & rStm)37 XBMReader::XBMReader( SvStream& rStm ) :
38 			rIStm			( rStm ),
39 			pAcc1			( NULL ),
40 			nLastPos		( rStm.Tell() ),
41 			nWidth			( 0 ),
42 			nHeight			( 0 ),
43 			bStatus			( sal_True )
44 {
45 	pHexTable = new short[ 256 ];
46 	maUpperName = String::CreateFromAscii( "SVIXBM", 6 );
47 	InitTable();
48 }
49 
50 // ------------------------------------------------------------------------
51 
~XBMReader()52 XBMReader::~XBMReader()
53 {
54 	delete[] pHexTable;
55 
56 	if( pAcc1 )
57 		aBmp1.ReleaseAccess( pAcc1 );
58 }
59 
60 // ------------------------------------------------------------------------
61 
InitTable()62 void XBMReader::InitTable()
63 {
64 	memset( pHexTable, 0, sizeof( short ) );
65 
66 	pHexTable['0'] = 0;
67 	pHexTable['1'] = 1;
68 	pHexTable['2'] = 2;
69 	pHexTable['3'] = 3;
70 	pHexTable['4'] = 4;
71 	pHexTable['5'] = 5;
72 	pHexTable['6'] = 6;
73 	pHexTable['7'] = 7;
74 	pHexTable['8'] = 8;
75 	pHexTable['9'] = 9;
76 	pHexTable['A'] = 10;
77 	pHexTable['B'] = 11;
78 	pHexTable['C'] = 12;
79 	pHexTable['D'] = 13;
80 	pHexTable['E'] = 14;
81 	pHexTable['F'] = 15;
82 	pHexTable['X'] = 0;
83 	pHexTable['a'] = 10;
84 	pHexTable['b'] = 11;
85 	pHexTable['c'] = 12;
86 	pHexTable['d'] = 13;
87 	pHexTable['e'] = 14;
88 	pHexTable['f'] = 15;
89 	pHexTable['x'] = 0;
90 	pHexTable[' '] =	 -1;
91 	pHexTable[','] = -1;
92 	pHexTable['}'] = -1;
93 	pHexTable['\n'] = -1;
94 	pHexTable['\t'] = -1;
95 	pHexTable['\0'] = -1;
96 }
97 
98 // ------------------------------------------------------------------------
99 
FindTokenLine(SvStream * pInStm,const char * pTok1,const char * pTok2,const char * pTok3)100 ByteString XBMReader::FindTokenLine( SvStream* pInStm, const char* pTok1,
101 								 const char* pTok2, const char* pTok3 )
102 {
103 	ByteString	aRet;
104 	long		nPos1;
105 	long		nPos2;
106 	long		nPos3;
107 
108 	bStatus = sal_False;
109 
110 	do
111 	{
112 		if( !pInStm->ReadLine( aRet ) )
113 			break;
114 
115 		if( pTok1 )
116 		{
117 			if( ( nPos1 = aRet.Search( pTok1 ) ) != STRING_NOTFOUND )
118 			{
119 				bStatus = sal_True;
120 
121 				if( pTok2 )
122 				{
123 					bStatus = sal_False;
124 
125 					if( ( ( nPos2 = aRet.Search( pTok2 ) ) != STRING_NOTFOUND ) &&
126 						 ( nPos2 > nPos1 ) )
127 					{
128 						bStatus = sal_True;
129 
130 						if( pTok3 )
131 						{
132 							bStatus = sal_False;
133 
134 							if( ( ( nPos3 = aRet.Search( pTok3 ) ) != STRING_NOTFOUND ) && ( nPos3 > nPos2 ) )
135 								bStatus = sal_True;
136 						}
137 					}
138 				}
139 			}
140 		}
141 	}
142 	while( !bStatus );
143 
144 	return aRet;
145 }
146 
147 // ------------------------------------------------------------------------
148 
ParseDefine(const sal_Char * pDefine)149 long XBMReader::ParseDefine( const sal_Char* pDefine )
150 {
151 	long	nRet = 0;
152 	char*	pTmp = (char*) pDefine;
153 	unsigned char	cTmp;
154 
155 	// bis zum Ende gehen
156 	pTmp += ( strlen( pDefine ) - 1 );
157 	cTmp = *pTmp--;
158 
159 	// letzte Ziffer suchen
160 	while( pHexTable[ cTmp ] == -1 )
161 		cTmp = *pTmp--;
162 
163 	// bis vor die Zahl laufen
164 	while( pHexTable[ cTmp ] != -1 )
165 		cTmp = *pTmp--;
166 
167 	// auf Anfang der Zahl gehen
168 	pTmp += 2;
169 
170 	// Hex lesen
171 	if( ( pTmp[0] == '0' ) && ( ( pTmp[1] == 'X' ) || ( pTmp[1] == 'x' ) ) )
172 	{
173 		pTmp += 2;
174 		cTmp = *pTmp++;
175 
176 		while ( pHexTable[ cTmp ] != -1 )
177 		{
178 			nRet = ( nRet << 4 ) + pHexTable[ cTmp ];
179 			cTmp = *pTmp++;
180 		}
181 	}
182 	// Dezimal lesen
183 	else
184 	{
185 		cTmp = *pTmp++;
186 		while( ( cTmp >= '0' ) && ( cTmp <= '9' ) )
187 		{
188 			nRet = nRet * 10 + ( cTmp - '0' );
189 			cTmp = *pTmp++;
190 		}
191 	}
192 
193 	return nRet;
194 }
195 
196 // ------------------------------------------------------------------------
197 
ParseData(SvStream * pInStm,const ByteString & aLastLine,XBMFormat eFormat)198 sal_Bool XBMReader::ParseData( SvStream* pInStm, const ByteString& aLastLine, XBMFormat eFormat )
199 {
200 	ByteString		aLine;
201 	long			nRow = 0;
202 	long			nCol = 0;
203 	long			nBits = ( eFormat == XBM10 ) ? 16 : 8;
204 	long			nBit;
205 	sal_uInt16			nValue;
206 	sal_uInt16			nDigits;
207 	sal_Bool			bFirstLine = sal_True;
208 
209 	while( nRow < nHeight )
210 	{
211 		if( bFirstLine )
212 		{
213 			xub_StrLen nPos;
214 
215 			// einfuehrende geschweifte Klammer loeschen
216 			if( (nPos = ( aLine = aLastLine ).Search( '{' ) ) != STRING_NOTFOUND )
217 				aLine.Erase( 0, nPos + 1 );
218 
219 			bFirstLine = sal_False;
220 		}
221 		else if( !pInStm->ReadLine( aLine ) )
222 			break;
223 
224 		if( aLine.Len() )
225 		{
226 			const sal_uInt16 nCount = aLine.GetTokenCount( ',' );
227 
228 			for( sal_uInt16 i = 0; ( i < nCount ) && ( nRow < nHeight ); i++ )
229 			{
230 				const ByteString	aToken( aLine.GetToken( i, ',' ) );
231 				const xub_StrLen nLen = aToken.Len();
232 				sal_Bool				bProcessed = sal_False;
233 
234 				nBit = nDigits = nValue = 0;
235 
236 				for( xub_StrLen n = 0UL; n < nLen; n++ )
237 				{
238 					const unsigned char cChar = aToken.GetChar( n );
239 					const short			nTable = pHexTable[ cChar ];
240 
241 					if( isxdigit( cChar ) || !nTable )
242 					{
243 						nValue = ( nValue << 4 ) + nTable;
244 						nDigits++;
245 						bProcessed = sal_True;
246 					}
247 					else if( ( nTable < 0 ) && nDigits )
248 					{
249 						bProcessed = sal_True;
250 						break;
251 					}
252 				}
253 
254 				if( bProcessed )
255 				{
256 					while( ( nCol < nWidth ) && ( nBit < nBits ) )
257 						pAcc1->SetPixel( nRow, nCol++, ( nValue & ( 1 << nBit++ ) ) ? aBlack : aWhite );
258 
259 					if( nCol == nWidth )
260 						nCol = 0, nRow++;
261 				}
262 			}
263 		}
264 	}
265 
266 	return sal_True;
267 }
268 
269 // ------------------------------------------------------------------------
270 
ReadXBM(Graphic & rGraphic)271 ReadState XBMReader::ReadXBM( Graphic& rGraphic )
272 {
273 	ReadState	eReadState;
274 	sal_uInt8		cDummy;
275 
276 	// sehen, ob wir _alles_ lesen koennen
277 	rIStm.Seek( STREAM_SEEK_TO_END );
278 	rIStm >> cDummy;
279 
280 	// falls wir nicht alles lesen koennen
281 	// kehren wir zurueck und warten auf neue Daten
282 	if ( rIStm.GetError() != ERRCODE_IO_PENDING )
283 	{
284 		ByteString	aLine;
285 		int			nValue;
286 
287 		rIStm.Seek( nLastPos );
288 		bStatus = sal_False;
289 		aLine = FindTokenLine( &rIStm, "#define", "_width" );
290 
291 		if ( bStatus )
292 		{
293 			if ( ( nValue = (int) ParseDefine( aLine.GetBuffer() ) ) > 0 )
294 			{
295 				nWidth = nValue;
296 				aLine = FindTokenLine( &rIStm, "#define", "_height" );
297 
298 				// Falls die Hoehe nicht folgt, suchen wir noch
299 				// einmal vom Anfang der Datei an
300 				if ( !bStatus )
301 				{
302 					rIStm.Seek( nLastPos );
303 					aLine = FindTokenLine( &rIStm, "#define", "_height" );
304 				}
305 			}
306 			else
307 				bStatus = sal_False;
308 
309 			if ( bStatus )
310 			{
311 				if ( ( nValue = (int) ParseDefine( aLine.GetBuffer() ) ) > 0 )
312 				{
313 					nHeight = nValue;
314 					aLine = FindTokenLine( &rIStm, "static", "_bits" );
315 
316 					if ( bStatus )
317 					{
318 						XBMFormat eFormat = XBM10;
319 
320 						if ( aLine.Search( "short" ) != STRING_NOTFOUND )
321 							eFormat = XBM10;
322 						else if ( aLine.Search( "char" ) != STRING_NOTFOUND )
323 							eFormat = XBM11;
324 						else
325 							bStatus = sal_False;
326 
327 						if ( bStatus && nWidth && nHeight )
328 						{
329 							aBmp1 = Bitmap( Size( nWidth, nHeight ), 1 );
330 							pAcc1 = aBmp1.AcquireWriteAccess();
331 
332 							if( pAcc1 )
333 							{
334 								aWhite = pAcc1->GetBestMatchingColor( Color( COL_WHITE ) );
335 								aBlack = pAcc1->GetBestMatchingColor( Color( COL_BLACK ) );
336 								bStatus = ParseData( &rIStm, aLine, eFormat );
337 							}
338 							else
339 								bStatus = sal_False;
340 						}
341 					}
342 				}
343 			}
344 		}
345 
346 		if( bStatus )
347 		{
348 			Bitmap aBlackBmp( Size( pAcc1->Width(), pAcc1->Height() ), 1 );
349 
350 			aBmp1.ReleaseAccess( pAcc1 ), pAcc1 = NULL;
351 			aBlackBmp.Erase( Color( COL_BLACK ) );
352 			rGraphic = BitmapEx( aBlackBmp, aBmp1 );
353 			eReadState = XBMREAD_OK;
354 		}
355 		else
356 			eReadState = XBMREAD_ERROR;
357 	}
358 	else
359 	{
360 		rIStm.ResetError();
361 		eReadState = XBMREAD_NEED_MORE;
362 	}
363 
364 	return eReadState;
365 }
366 
367 // -------------
368 // - ImportXBM -
369 // -------------
370 
ImportXBM(SvStream & rStm,Graphic & rGraphic)371 sal_Bool ImportXBM( SvStream& rStm, Graphic& rGraphic )
372 {
373 	XBMReader*	pXBMReader = (XBMReader*) rGraphic.GetContext();
374 	ReadState	eReadState;
375 	sal_Bool		bRet = sal_True;
376 
377 	if( !pXBMReader )
378 		pXBMReader = new XBMReader( rStm );
379 
380 	rGraphic.SetContext( NULL );
381 	eReadState = pXBMReader->ReadXBM( rGraphic );
382 
383 	if( eReadState == XBMREAD_ERROR )
384 	{
385 		bRet = sal_False;
386 		delete pXBMReader;
387 	}
388 	else if( eReadState == XBMREAD_OK )
389 		delete pXBMReader;
390 	else
391 		rGraphic.SetContext( pXBMReader );
392 
393 	return bRet;
394 }
395