bump product version to 6.4.0.3
[LibreOffice.git] / vcl / source / filter / ixbm / xbmread.cxx
blob6d88ec57a640992998b8eb306e1460880a61d557
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <memory>
21 #include <sal/config.h>
22 #include <tools/stream.hxx>
24 #include <rtl/character.hxx>
25 #include <bitmapwriteaccess.hxx>
27 #include "xbmread.hxx"
29 enum XBMFormat
31 XBM10,
32 XBM11
35 enum ReadState
37 XBMREAD_OK,
38 XBMREAD_ERROR,
39 XBMREAD_NEED_MORE
42 class XBMReader : public GraphicReader
44 SvStream& rIStm;
45 Bitmap aBmp1;
46 BitmapScopedWriteAccess pAcc1;
47 std::unique_ptr<short[]>
48 pHexTable;
49 BitmapColor aWhite;
50 BitmapColor aBlack;
51 long const nLastPos;
52 long nWidth;
53 long nHeight;
54 bool bStatus;
56 void InitTable();
57 OString FindTokenLine( SvStream* pInStm, const char* pTok1, const char* pTok2 );
58 int ParseDefine( const sal_Char* pDefine );
59 void ParseData( SvStream* pInStm, const OString& aLastLine, XBMFormat eFormat );
61 public:
63 explicit XBMReader( SvStream& rStm );
65 ReadState ReadXBM( Graphic& rGraphic );
68 XBMReader::XBMReader( SvStream& rStm ) :
69 rIStm ( rStm ),
70 nLastPos ( rStm.Tell() ),
71 nWidth ( 0 ),
72 nHeight ( 0 ),
73 bStatus ( true )
75 pHexTable.reset( new short[ 256 ] );
76 maUpperName = "SVIXBM";
77 InitTable();
80 void XBMReader::InitTable()
82 memset( pHexTable.get(), 0, sizeof( short ) * 256 );
84 pHexTable[int('0')] = 0;
85 pHexTable[int('1')] = 1;
86 pHexTable[int('2')] = 2;
87 pHexTable[int('3')] = 3;
88 pHexTable[int('4')] = 4;
89 pHexTable[int('5')] = 5;
90 pHexTable[int('6')] = 6;
91 pHexTable[int('7')] = 7;
92 pHexTable[int('8')] = 8;
93 pHexTable[int('9')] = 9;
94 pHexTable[int('A')] = 10;
95 pHexTable[int('B')] = 11;
96 pHexTable[int('C')] = 12;
97 pHexTable[int('D')] = 13;
98 pHexTable[int('E')] = 14;
99 pHexTable[int('F')] = 15;
100 pHexTable[int('X')] = 0;
101 pHexTable[int('a')] = 10;
102 pHexTable[int('b')] = 11;
103 pHexTable[int('c')] = 12;
104 pHexTable[int('d')] = 13;
105 pHexTable[int('e')] = 14;
106 pHexTable[int('f')] = 15;
107 pHexTable[int('x')] = 0;
108 pHexTable[int(' ')] = -1;
109 pHexTable[int(',')] = -1;
110 pHexTable[int('}')] = -1;
111 pHexTable[int('\n')] = -1;
112 pHexTable[int('\t')] = -1;
113 pHexTable[int('\0')] = -1;
116 OString XBMReader::FindTokenLine( SvStream* pInStm, const char* pTok1,
117 const char* pTok2 )
119 OString aRet;
120 sal_Int32 nPos1, nPos2;
122 bStatus = false;
126 if( !pInStm->ReadLine( aRet ) )
127 break;
129 if( pTok1 )
131 if( ( nPos1 = aRet.indexOf( pTok1 ) ) != -1 )
133 bStatus = true;
135 if( pTok2 )
137 bStatus = false;
139 if( ( ( nPos2 = aRet.indexOf( pTok2 ) ) != -1 ) &&
140 ( nPos2 > nPos1 ) )
142 bStatus = true;
148 while( !bStatus );
150 return aRet;
153 int XBMReader::ParseDefine( const sal_Char* pDefine )
155 sal_Int32 nRet = 0;
156 const char* pTmp = pDefine;
157 unsigned char cTmp;
159 // move to end
160 pTmp += ( strlen( pDefine ) - 1 );
161 cTmp = *pTmp--;
163 // search last digit
164 while (pHexTable[ cTmp ] == -1 && pTmp >= pDefine)
165 cTmp = *pTmp--;
167 // move before number
168 while (pHexTable[ cTmp ] != -1 && pTmp >= pDefine)
169 cTmp = *pTmp--;
171 // move to start of number
172 pTmp += 2;
174 // read Hex
175 if( ( pTmp[0] == '0' ) && ( ( pTmp[1] == 'X' ) || ( pTmp[1] == 'x' ) ) )
177 pTmp += 2;
178 nRet = OString(pTmp, strlen(pTmp)).toInt32(16);
180 else // read decimal
182 nRet = OString(pTmp, strlen(pTmp)).toInt32();
185 return nRet;
188 void XBMReader::ParseData( SvStream* pInStm, const OString& aLastLine, XBMFormat eFormat )
190 OString aLine;
191 long nRow = 0;
192 long nCol = 0;
193 long nBits = ( eFormat == XBM10 ) ? 16 : 8;
194 long nBit;
195 sal_uInt16 nValue;
196 sal_uInt16 nDigits;
197 bool bFirstLine = true;
199 while( nRow < nHeight )
201 if( bFirstLine )
203 sal_Int32 nPos;
205 // delete opening curly bracket
206 if( (nPos = ( aLine = aLastLine ).indexOf('{') ) != -1 )
207 aLine = aLine.copy(nPos + 1);
209 bFirstLine = false;
211 else if( !pInStm->ReadLine( aLine ) )
212 break;
214 if (!aLine.isEmpty())
216 sal_Int32 nIndex = 0;
217 const sal_Int32 nLen {aLine.getLength()};
218 while (nRow<nHeight && nIndex<nLen)
220 bool bProcessed = false;
222 nBit = nDigits = nValue = 0;
224 while (nIndex<nLen)
226 const unsigned char cChar = aLine[nIndex];
228 ++nIndex;
229 if (cChar==',') // sequence completed, ',' already skipped for next loop
230 break;
232 const short nTable = pHexTable[ cChar ];
234 if( rtl::isAsciiHexDigit( cChar ) || !nTable )
236 nValue = ( nValue << 4 ) + nTable;
237 nDigits++;
238 bProcessed = true;
240 else if( ( nTable < 0 ) && nDigits )
242 bProcessed = true;
243 break;
247 if( bProcessed )
249 Scanline pScanline = pAcc1->GetScanline(nRow);
250 while( ( nCol < nWidth ) && ( nBit < nBits ) )
251 pAcc1->SetPixelOnData(pScanline, nCol++, ( nValue & ( 1 << nBit++ ) ) ? aBlack : aWhite);
253 if( nCol == nWidth )
255 nCol = 0;
256 nRow++;
264 ReadState XBMReader::ReadXBM( Graphic& rGraphic )
266 ReadState eReadState;
267 sal_uInt8 cDummy;
269 // check if we can read ALL
270 rIStm.Seek( STREAM_SEEK_TO_END );
271 rIStm.ReadUChar( cDummy );
273 // if we cannot read all
274 // we return and wait for new data
275 if ( rIStm.GetError() != ERRCODE_IO_PENDING )
277 rIStm.Seek( nLastPos );
278 bStatus = false;
279 OString aLine = FindTokenLine( &rIStm, "#define", "_width" );
281 if ( bStatus )
283 int nValue;
284 if ( ( nValue = ParseDefine( aLine.getStr() ) ) > 0 )
286 nWidth = nValue;
287 aLine = FindTokenLine( &rIStm, "#define", "_height" );
289 // if height was not received, we search again
290 // from start of the file
291 if ( !bStatus )
293 rIStm.Seek( nLastPos );
294 aLine = FindTokenLine( &rIStm, "#define", "_height" );
297 else
298 bStatus = false;
300 if ( bStatus )
302 if ( ( nValue = ParseDefine( aLine.getStr() ) ) > 0 )
304 nHeight = nValue;
305 aLine = FindTokenLine( &rIStm, "static", "_bits" );
307 if ( bStatus )
309 XBMFormat eFormat = XBM10;
311 if (aLine.indexOf("short") != -1)
312 eFormat = XBM10;
313 else if (aLine.indexOf("char") != -1)
314 eFormat = XBM11;
315 else
316 bStatus = false;
318 //xbms are a minimum of one character per 8 pixels, so if the file isn't
319 //even that long, it's not all there
320 if (rIStm.remainingSize() < (static_cast<sal_uInt64>(nWidth) * nHeight) / 8)
321 bStatus = false;
323 if ( bStatus && nWidth && nHeight )
325 aBmp1 = Bitmap( Size( nWidth, nHeight ), 1 );
326 pAcc1 = BitmapScopedWriteAccess(aBmp1);
328 if( pAcc1 )
330 aWhite = pAcc1->GetBestMatchingColor( COL_WHITE );
331 aBlack = pAcc1->GetBestMatchingColor( COL_BLACK );
332 ParseData( &rIStm, aLine, eFormat );
334 else
335 bStatus = false;
342 if (bStatus && pAcc1)
344 Bitmap aBlackBmp( Size( pAcc1->Width(), pAcc1->Height() ), 1 );
346 pAcc1.reset();
347 aBlackBmp.Erase( COL_BLACK );
348 rGraphic = BitmapEx( aBlackBmp, aBmp1 );
349 eReadState = XBMREAD_OK;
351 else
352 eReadState = XBMREAD_ERROR;
354 else
356 rIStm.ResetError();
357 eReadState = XBMREAD_NEED_MORE;
360 return eReadState;
363 VCL_DLLPUBLIC bool ImportXBM( SvStream& rStm, Graphic& rGraphic )
365 std::shared_ptr<GraphicReader> pContext = rGraphic.GetContext();
366 rGraphic.SetContext(nullptr);
367 XBMReader* pXBMReader = dynamic_cast<XBMReader*>( pContext.get() );
368 if (!pXBMReader)
370 pContext = std::make_shared<XBMReader>( rStm );
371 pXBMReader = static_cast<XBMReader*>( pContext.get() );
374 bool bRet = true;
376 ReadState eReadState = pXBMReader->ReadXBM( rGraphic );
378 if( eReadState == XBMREAD_ERROR )
380 bRet = false;
382 else if( eReadState == XBMREAD_NEED_MORE )
383 rGraphic.SetContext( pContext );
385 return bRet;
388 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */