Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #define _XBMPRIVATE
21 : #include <ctype.h>
22 : #include <comphelper/string.hxx>
23 : #include "xbmread.hxx"
24 :
25 0 : XBMReader::XBMReader( SvStream& rStm ) :
26 : rIStm ( rStm ),
27 : pAcc1 ( NULL ),
28 0 : nLastPos ( rStm.Tell() ),
29 : nWidth ( 0 ),
30 : nHeight ( 0 ),
31 0 : bStatus ( true )
32 : {
33 0 : pHexTable = new short[ 256 ];
34 0 : maUpperName = "SVIXBM";
35 0 : InitTable();
36 0 : }
37 :
38 0 : XBMReader::~XBMReader()
39 : {
40 0 : delete[] pHexTable;
41 :
42 0 : if( pAcc1 )
43 0 : aBmp1.ReleaseAccess( pAcc1 );
44 0 : }
45 :
46 0 : void XBMReader::InitTable()
47 : {
48 0 : memset( pHexTable, 0, sizeof( short ) * 256 );
49 :
50 0 : pHexTable[(int)'0'] = 0;
51 0 : pHexTable[(int)'1'] = 1;
52 0 : pHexTable[(int)'2'] = 2;
53 0 : pHexTable[(int)'3'] = 3;
54 0 : pHexTable[(int)'4'] = 4;
55 0 : pHexTable[(int)'5'] = 5;
56 0 : pHexTable[(int)'6'] = 6;
57 0 : pHexTable[(int)'7'] = 7;
58 0 : pHexTable[(int)'8'] = 8;
59 0 : pHexTable[(int)'9'] = 9;
60 0 : pHexTable[(int)'A'] = 10;
61 0 : pHexTable[(int)'B'] = 11;
62 0 : pHexTable[(int)'C'] = 12;
63 0 : pHexTable[(int)'D'] = 13;
64 0 : pHexTable[(int)'E'] = 14;
65 0 : pHexTable[(int)'F'] = 15;
66 0 : pHexTable[(int)'X'] = 0;
67 0 : pHexTable[(int)'a'] = 10;
68 0 : pHexTable[(int)'b'] = 11;
69 0 : pHexTable[(int)'c'] = 12;
70 0 : pHexTable[(int)'d'] = 13;
71 0 : pHexTable[(int)'e'] = 14;
72 0 : pHexTable[(int)'f'] = 15;
73 0 : pHexTable[(int)'x'] = 0;
74 0 : pHexTable[(int)' '] = -1;
75 0 : pHexTable[(int)','] = -1;
76 0 : pHexTable[(int)'}'] = -1;
77 0 : pHexTable[(int)'\n'] = -1;
78 0 : pHexTable[(int)'\t'] = -1;
79 0 : pHexTable[(int)'\0'] = -1;
80 0 : }
81 :
82 0 : OString XBMReader::FindTokenLine( SvStream* pInStm, const char* pTok1,
83 : const char* pTok2, const char* pTok3 )
84 : {
85 0 : OString aRet;
86 : sal_Int32 nPos1, nPos2, nPos3;
87 :
88 0 : bStatus = false;
89 :
90 0 : do
91 : {
92 0 : if( !pInStm->ReadLine( aRet ) )
93 0 : break;
94 :
95 0 : if( pTok1 )
96 : {
97 0 : if( ( nPos1 = aRet.indexOf( pTok1 ) ) != -1 )
98 : {
99 0 : bStatus = true;
100 :
101 0 : if( pTok2 )
102 : {
103 0 : bStatus = false;
104 :
105 0 : if( ( ( nPos2 = aRet.indexOf( pTok2 ) ) != -1 ) &&
106 : ( nPos2 > nPos1 ) )
107 : {
108 0 : bStatus = true;
109 :
110 0 : if( pTok3 )
111 : {
112 0 : bStatus = false;
113 :
114 0 : if( ( ( nPos3 = aRet.indexOf( pTok3 ) ) != -1 ) && ( nPos3 > nPos2 ) )
115 0 : bStatus = true;
116 : }
117 : }
118 : }
119 : }
120 : }
121 : }
122 0 : while( !bStatus );
123 :
124 0 : return aRet;
125 : }
126 :
127 0 : long XBMReader::ParseDefine( const sal_Char* pDefine )
128 : {
129 0 : long nRet = 0;
130 0 : char* pTmp = (char*) pDefine;
131 : unsigned char cTmp;
132 :
133 : // move to end
134 0 : pTmp += ( strlen( pDefine ) - 1 );
135 0 : cTmp = *pTmp--;
136 :
137 : // search last digit
138 0 : while( pHexTable[ cTmp ] == -1 )
139 0 : cTmp = *pTmp--;
140 :
141 : // move before number
142 0 : while( pHexTable[ cTmp ] != -1 )
143 0 : cTmp = *pTmp--;
144 :
145 : // move to start of number
146 0 : pTmp += 2;
147 :
148 : // read Hex
149 0 : if( ( pTmp[0] == '0' ) && ( ( pTmp[1] == 'X' ) || ( pTmp[1] == 'x' ) ) )
150 : {
151 0 : pTmp += 2;
152 0 : cTmp = *pTmp++;
153 :
154 0 : while ( pHexTable[ cTmp ] != -1 )
155 : {
156 0 : nRet = ( nRet << 4 ) + pHexTable[ cTmp ];
157 0 : cTmp = *pTmp++;
158 : }
159 : }
160 : // read decimal
161 : else
162 : {
163 0 : cTmp = *pTmp++;
164 0 : while( ( cTmp >= '0' ) && ( cTmp <= '9' ) )
165 : {
166 0 : nRet = nRet * 10 + ( cTmp - '0' );
167 0 : cTmp = *pTmp++;
168 : }
169 : }
170 :
171 0 : return nRet;
172 : }
173 :
174 0 : bool XBMReader::ParseData( SvStream* pInStm, const OString& aLastLine, XBMFormat eFormat )
175 : {
176 0 : OString aLine;
177 0 : long nRow = 0;
178 0 : long nCol = 0;
179 0 : long nBits = ( eFormat == XBM10 ) ? 16 : 8;
180 : long nBit;
181 : sal_uInt16 nValue;
182 : sal_uInt16 nDigits;
183 0 : bool bFirstLine = true;
184 :
185 0 : while( nRow < nHeight )
186 : {
187 0 : if( bFirstLine )
188 : {
189 : sal_Int32 nPos;
190 :
191 : // delete opening curly bracket
192 0 : if( (nPos = ( aLine = aLastLine ).indexOf('{') ) != -1 )
193 0 : aLine = aLine.copy(nPos + 1);
194 :
195 0 : bFirstLine = false;
196 : }
197 0 : else if( !pInStm->ReadLine( aLine ) )
198 0 : break;
199 :
200 0 : if (!aLine.isEmpty())
201 : {
202 0 : const sal_Int32 nCount = comphelper::string::getTokenCount(aLine, ',');
203 :
204 0 : for( sal_Int32 i = 0; ( i < nCount ) && ( nRow < nHeight ); ++i )
205 : {
206 0 : const OString aToken(comphelper::string::getToken(aLine,i, ','));
207 0 : const sal_Int32 nLen = aToken.getLength();
208 0 : bool bProcessed = false;
209 :
210 0 : nBit = nDigits = nValue = 0;
211 :
212 0 : for (sal_Int32 n = 0; n < nLen; ++n)
213 : {
214 0 : const unsigned char cChar = aToken[n];
215 0 : const short nTable = pHexTable[ cChar ];
216 :
217 0 : if( isxdigit( cChar ) || !nTable )
218 : {
219 0 : nValue = ( nValue << 4 ) + nTable;
220 0 : nDigits++;
221 0 : bProcessed = true;
222 : }
223 0 : else if( ( nTable < 0 ) && nDigits )
224 : {
225 0 : bProcessed = true;
226 0 : break;
227 : }
228 : }
229 :
230 0 : if( bProcessed )
231 : {
232 0 : while( ( nCol < nWidth ) && ( nBit < nBits ) )
233 0 : pAcc1->SetPixel( nRow, nCol++, ( nValue & ( 1 << nBit++ ) ) ? aBlack : aWhite );
234 :
235 0 : if( nCol == nWidth )
236 0 : nCol = 0, nRow++;
237 : }
238 0 : }
239 : }
240 : }
241 :
242 0 : return true;
243 : }
244 :
245 0 : ReadState XBMReader::ReadXBM( Graphic& rGraphic )
246 : {
247 : ReadState eReadState;
248 : sal_uInt8 cDummy;
249 :
250 : // check if we can read ALL
251 0 : rIStm.Seek( STREAM_SEEK_TO_END );
252 0 : rIStm.ReadUChar( cDummy );
253 :
254 : // if we cannot read all
255 : // we returnn and wait for new data
256 0 : if ( rIStm.GetError() != ERRCODE_IO_PENDING )
257 : {
258 0 : rIStm.Seek( nLastPos );
259 0 : bStatus = false;
260 0 : OString aLine = FindTokenLine( &rIStm, "#define", "_width" );
261 :
262 0 : if ( bStatus )
263 : {
264 : int nValue;
265 0 : if ( ( nValue = (int) ParseDefine( aLine.getStr() ) ) > 0 )
266 : {
267 0 : nWidth = nValue;
268 0 : aLine = FindTokenLine( &rIStm, "#define", "_height" );
269 :
270 : // if height was not received, we search again
271 : // from start of the file
272 0 : if ( !bStatus )
273 : {
274 0 : rIStm.Seek( nLastPos );
275 0 : aLine = FindTokenLine( &rIStm, "#define", "_height" );
276 : }
277 : }
278 : else
279 0 : bStatus = false;
280 :
281 0 : if ( bStatus )
282 : {
283 0 : if ( ( nValue = (int) ParseDefine( aLine.getStr() ) ) > 0 )
284 : {
285 0 : nHeight = nValue;
286 0 : aLine = FindTokenLine( &rIStm, "static", "_bits" );
287 :
288 0 : if ( bStatus )
289 : {
290 0 : XBMFormat eFormat = XBM10;
291 :
292 0 : if (aLine.indexOf("short") != -1)
293 0 : eFormat = XBM10;
294 0 : else if (aLine.indexOf("char") != -1)
295 0 : eFormat = XBM11;
296 : else
297 0 : bStatus = false;
298 :
299 0 : if ( bStatus && nWidth && nHeight )
300 : {
301 0 : aBmp1 = Bitmap( Size( nWidth, nHeight ), 1 );
302 0 : pAcc1 = aBmp1.AcquireWriteAccess();
303 :
304 0 : if( pAcc1 )
305 : {
306 0 : aWhite = pAcc1->GetBestMatchingColor( Color( COL_WHITE ) );
307 0 : aBlack = pAcc1->GetBestMatchingColor( Color( COL_BLACK ) );
308 0 : bStatus = ParseData( &rIStm, aLine, eFormat );
309 : }
310 : else
311 0 : bStatus = false;
312 : }
313 : }
314 : }
315 : }
316 : }
317 :
318 0 : if( bStatus )
319 : {
320 0 : Bitmap aBlackBmp( Size( pAcc1->Width(), pAcc1->Height() ), 1 );
321 :
322 0 : aBmp1.ReleaseAccess( pAcc1 ), pAcc1 = NULL;
323 0 : aBlackBmp.Erase( Color( COL_BLACK ) );
324 0 : rGraphic = BitmapEx( aBlackBmp, aBmp1 );
325 0 : eReadState = XBMREAD_OK;
326 : }
327 : else
328 0 : eReadState = XBMREAD_ERROR;
329 : }
330 : else
331 : {
332 0 : rIStm.ResetError();
333 0 : eReadState = XBMREAD_NEED_MORE;
334 : }
335 :
336 0 : return eReadState;
337 : }
338 :
339 0 : bool ImportXBM( SvStream& rStm, Graphic& rGraphic )
340 : {
341 0 : XBMReader* pXBMReader = static_cast<XBMReader*>( rGraphic.GetContext() );
342 : ReadState eReadState;
343 0 : bool bRet = true;
344 :
345 0 : if( !pXBMReader )
346 0 : pXBMReader = new XBMReader( rStm );
347 :
348 0 : rGraphic.SetContext( NULL );
349 0 : eReadState = pXBMReader->ReadXBM( rGraphic );
350 :
351 0 : if( eReadState == XBMREAD_ERROR )
352 : {
353 0 : bRet = false;
354 0 : delete pXBMReader;
355 : }
356 0 : else if( eReadState == XBMREAD_OK )
357 0 : delete pXBMReader;
358 : else
359 0 : rGraphic.SetContext( pXBMReader );
360 :
361 0 : return bRet;
362 1233 : }
363 :
364 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|