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