LibreOffice Module vcl (master) 1
xbmread.cxx
Go to the documentation of this file.
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#include <memory>
21#include <sal/config.h>
22#include <tools/stream.hxx>
23
24#include <rtl/character.hxx>
25
28
29#include "xbmread.hxx"
30
31namespace {
32
33enum XBMFormat
34{
35 XBM10,
36 XBM11
37};
38
39enum ReadState
40{
41 XBMREAD_OK,
42 XBMREAD_ERROR,
43 XBMREAD_NEED_MORE
44};
45
46class XBMReader : public GraphicReader
47{
48 SvStream& rIStm;
49 Bitmap aBmp1;
51 std::unique_ptr<short[]>
52 pHexTable;
53 BitmapColor aWhite;
54 BitmapColor aBlack;
55 tools::Long nLastPos;
56 tools::Long nWidth;
57 tools::Long nHeight;
58 bool bStatus;
59
60 void InitTable();
61 OString FindTokenLine( SvStream* pInStm, const char* pTok1, const char* pTok2 );
62 int ParseDefine( const char* pDefine );
63 void ParseData( SvStream* pInStm, const OString& aLastLine, XBMFormat eFormat );
64
65public:
66
67 explicit XBMReader( SvStream& rStm );
68
69 ReadState ReadXBM( Graphic& rGraphic );
70};
71
72}
73
74XBMReader::XBMReader( SvStream& rStm ) :
75 rIStm ( rStm ),
76 nLastPos ( rStm.Tell() ),
77 nWidth ( 0 ),
78 nHeight ( 0 ),
79 bStatus ( true )
80{
81 pHexTable.reset( new short[ 256 ] );
82 maUpperName = "SVIXBM";
83 InitTable();
84}
85
86void XBMReader::InitTable()
87{
88 memset( pHexTable.get(), 0, sizeof( short ) * 256 );
89
90 pHexTable[int('0')] = 0;
91 pHexTable[int('1')] = 1;
92 pHexTable[int('2')] = 2;
93 pHexTable[int('3')] = 3;
94 pHexTable[int('4')] = 4;
95 pHexTable[int('5')] = 5;
96 pHexTable[int('6')] = 6;
97 pHexTable[int('7')] = 7;
98 pHexTable[int('8')] = 8;
99 pHexTable[int('9')] = 9;
100 pHexTable[int('A')] = 10;
101 pHexTable[int('B')] = 11;
102 pHexTable[int('C')] = 12;
103 pHexTable[int('D')] = 13;
104 pHexTable[int('E')] = 14;
105 pHexTable[int('F')] = 15;
106 pHexTable[int('X')] = 0;
107 pHexTable[int('a')] = 10;
108 pHexTable[int('b')] = 11;
109 pHexTable[int('c')] = 12;
110 pHexTable[int('d')] = 13;
111 pHexTable[int('e')] = 14;
112 pHexTable[int('f')] = 15;
113 pHexTable[int('x')] = 0;
114 pHexTable[int(' ')] = -1;
115 pHexTable[int(',')] = -1;
116 pHexTable[int('}')] = -1;
117 pHexTable[int('\n')] = -1;
118 pHexTable[int('\t')] = -1;
119 pHexTable[int('\0')] = -1;
120}
121
122OString XBMReader::FindTokenLine( SvStream* pInStm, const char* pTok1,
123 const char* pTok2 )
124{
125 OString aRet;
126 sal_Int32 nPos1, nPos2;
127
128 bStatus = false;
129
130 do
131 {
132 if( !pInStm->ReadLine( aRet ) )
133 break;
134
135 if( pTok1 )
136 {
137 if( ( nPos1 = aRet.indexOf( pTok1 ) ) != -1 )
138 {
139 bStatus = true;
140
141 if( pTok2 )
142 {
143 bStatus = false;
144
145 nPos2 = aRet.indexOf( pTok2 );
146 if( ( nPos2 != -1 ) && ( nPos2 > nPos1 ) )
147 {
148 bStatus = true;
149 }
150 }
151 }
152 }
153 }
154 while( !bStatus );
155
156 return aRet;
157}
158
159int XBMReader::ParseDefine( const char* pDefine )
160{
161 sal_Int32 nRet = 0;
162 const char* pTmp = pDefine;
163 unsigned char cTmp;
164
165 // move to end
166 pTmp += ( strlen( pDefine ) - 1 );
167 cTmp = *pTmp--;
168
169 // search last digit
170 while (pHexTable[ cTmp ] == -1 && pTmp >= pDefine)
171 cTmp = *pTmp--;
172
173 // move before number
174 while (pHexTable[ cTmp ] != -1 && pTmp >= pDefine)
175 cTmp = *pTmp--;
176
177 // move to start of number
178 pTmp += 2;
179
180 // read Hex
181 if( ( pTmp[0] == '0' ) && ( ( pTmp[1] == 'X' ) || ( pTmp[1] == 'x' ) ) )
182 {
183 pTmp += 2;
184 nRet = OString(pTmp, strlen(pTmp)).toInt32(16);
185 }
186 else // read decimal
187 {
188 nRet = OString(pTmp, strlen(pTmp)).toInt32();
189 }
190
191 return nRet;
192}
193
194void XBMReader::ParseData( SvStream* pInStm, const OString& aLastLine, XBMFormat eFormat )
195{
196 OString aLine;
197 tools::Long nRow = 0;
198 tools::Long nCol = 0;
199 tools::Long nBits = ( eFormat == XBM10 ) ? 16 : 8;
201 sal_uInt16 nValue;
202 sal_uInt16 nDigits;
203 bool bFirstLine = true;
204
205 while( nRow < nHeight )
206 {
207 if( bFirstLine )
208 {
209 sal_Int32 nPos;
210
211 // delete opening curly bracket
212 aLine = aLastLine;
213 nPos = aLine.indexOf('{');
214 if( nPos != -1 )
215 aLine = aLine.copy(nPos + 1);
216
217 bFirstLine = false;
218 }
219 else if( !pInStm->ReadLine( aLine ) )
220 break;
221
222 if (!aLine.isEmpty())
223 {
224 sal_Int32 nIndex = 0;
225 const sal_Int32 nLen {aLine.getLength()};
226 while (nRow<nHeight && nIndex<nLen)
227 {
228 bool bProcessed = false;
229
230 nBit = nDigits = nValue = 0;
231
232 while (nIndex<nLen)
233 {
234 const unsigned char cChar = aLine[nIndex];
235
236 ++nIndex;
237 if (cChar==',') // sequence completed, ',' already skipped for next loop
238 break;
239
240 const short nTable = pHexTable[ cChar ];
241
242 if( rtl::isAsciiHexDigit( cChar ) || !nTable )
243 {
244 nValue = ( nValue << 4 ) + nTable;
245 nDigits++;
246 bProcessed = true;
247 }
248 else if( ( nTable < 0 ) && nDigits )
249 {
250 bProcessed = true;
251 break;
252 }
253 }
254
255 if( bProcessed )
256 {
257 Scanline pScanline = pAcc1->GetScanline(nRow);
258 while( ( nCol < nWidth ) && ( nBit < nBits ) )
259 pAcc1->SetPixelOnData(pScanline, nCol++, ( nValue & ( 1 << nBit++ ) ) ? aBlack : aWhite);
260
261 if( nCol == nWidth )
262 {
263 nCol = 0;
264 nRow++;
265 }
266 }
267 }
268 }
269 }
270}
271
272ReadState XBMReader::ReadXBM( Graphic& rGraphic )
273{
274 ReadState eReadState;
275 sal_uInt8 cDummy;
276
277 // check if we can read ALL
278 rIStm.Seek( STREAM_SEEK_TO_END );
279 rIStm.ReadUChar( cDummy );
280
281 // if we cannot read all
282 // we return and wait for new data
283 if ( rIStm.GetError() != ERRCODE_IO_PENDING )
284 {
285 rIStm.Seek( nLastPos );
286 bStatus = false;
287 OString aLine = FindTokenLine( &rIStm, "#define", "_width" );
288
289 if ( bStatus )
290 {
291 int nValue;
292 if ( ( nValue = ParseDefine( aLine.getStr() ) ) > 0 )
293 {
294 nWidth = nValue;
295 aLine = FindTokenLine( &rIStm, "#define", "_height" );
296
297 // if height was not received, we search again
298 // from start of the file
299 if ( !bStatus )
300 {
301 rIStm.Seek( nLastPos );
302 aLine = FindTokenLine( &rIStm, "#define", "_height" );
303 }
304 }
305 else
306 bStatus = false;
307
308 if ( bStatus )
309 {
310 if ( ( nValue = ParseDefine( aLine.getStr() ) ) > 0 )
311 {
312 nHeight = nValue;
313 aLine = FindTokenLine( &rIStm, "static", "_bits" );
314
315 if ( bStatus )
316 {
317 XBMFormat eFormat = XBM10;
318
319 if (aLine.indexOf("short") != -1)
320 eFormat = XBM10;
321 else if (aLine.indexOf("char") != -1)
322 eFormat = XBM11;
323 else
324 bStatus = false;
325
326 //xbms are a minimum of one character per 8 pixels, so if the file isn't
327 //even that long, it's not all there
328 if (rIStm.remainingSize() < (static_cast<sal_uInt64>(nWidth) * nHeight) / 8)
329 bStatus = false;
330
331 if ( bStatus && nWidth && nHeight )
332 {
333 aBmp1 = Bitmap(Size(nWidth, nHeight), vcl::PixelFormat::N1_BPP);
334 pAcc1 = BitmapScopedWriteAccess(aBmp1);
335
336 if( pAcc1 )
337 {
338 aWhite = pAcc1->GetBestMatchingColor( COL_WHITE );
339 aBlack = pAcc1->GetBestMatchingColor( COL_BLACK );
340 ParseData( &rIStm, aLine, eFormat );
341 }
342 else
343 bStatus = false;
344 }
345 }
346 }
347 }
348 }
349
350 if (bStatus && pAcc1)
351 {
352 Bitmap aBlackBmp(Size(pAcc1->Width(), pAcc1->Height()), vcl::PixelFormat::N1_BPP);
353
354 pAcc1.reset();
355 aBlackBmp.Erase( COL_BLACK );
356 rGraphic = BitmapEx( aBlackBmp, aBmp1 );
357 eReadState = XBMREAD_OK;
358 }
359 else
360 eReadState = XBMREAD_ERROR;
361 }
362 else
363 {
364 rIStm.ResetError();
365 eReadState = XBMREAD_NEED_MORE;
366 }
367
368 return eReadState;
369}
370
371VCL_DLLPUBLIC bool ImportXBM( SvStream& rStm, Graphic& rGraphic )
372{
373 std::shared_ptr<GraphicReader> pContext = rGraphic.GetReaderContext();
374 rGraphic.SetReaderContext(nullptr);
375 XBMReader* pXBMReader = dynamic_cast<XBMReader*>( pContext.get() );
376 if (!pXBMReader)
377 {
378 pContext = std::make_shared<XBMReader>( rStm );
379 pXBMReader = static_cast<XBMReader*>( pContext.get() );
380 }
381
382 bool bRet = true;
383
384 ReadState eReadState = pXBMReader->ReadXBM( rGraphic );
385
386 if( eReadState == XBMREAD_ERROR )
387 {
388 bRet = false;
389 }
390 else if( eReadState == XBMREAD_NEED_MORE )
391 rGraphic.SetReaderContext( pContext );
392
393 return bRet;
394}
395
396/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
vcl::ScopedBitmapAccess< BitmapWriteAccess, Bitmap, &Bitmap::AcquireWriteAccess > BitmapScopedWriteAccess
ReadState
Definition: JpegReader.hxx:32
sal_uInt8 * Scanline
Definition: Scanline.hxx:26
void SetReaderContext(const std::shared_ptr< GraphicReader > &pReader)
Definition: graph.cxx:483
std::shared_ptr< GraphicReader > & GetReaderContext()
Definition: graph.cxx:478
bool ReadLine(OStringBuffer &rStr, sal_Int32 nMaxBytesToRead=0xFFFE)
This template handles BitmapAccess the RAII way.
#define VCL_DLLPUBLIC
Definition: dllapi.h:29
#define ERRCODE_IO_PENDING
Definition: errcode.hxx:225
sal_Int16 nValue
sal_Int32 nIndex
sal_uInt16 nPos
sal_Int16 nBit
long Long
const wchar_t *typedef int(__stdcall *DllNativeUnregProc)(int
unsigned char sal_uInt8
VCL_DLLPUBLIC bool ImportXBM(SvStream &rStm, Graphic &rGraphic)
Definition: xbmread.cxx:371