1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
21 #include <sal/config.h>
22 #include <tools/stream.hxx>
24 #include <rtl/character.hxx>
25 #include <bitmapwriteaccess.hxx>
27 #include "xbmread.hxx"
42 class XBMReader
: public GraphicReader
46 BitmapScopedWriteAccess pAcc1
;
47 std::unique_ptr
<short[]>
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
);
63 explicit XBMReader( SvStream
& rStm
);
65 ReadState
ReadXBM( Graphic
& rGraphic
);
68 XBMReader::XBMReader( SvStream
& rStm
) :
70 nLastPos ( rStm
.Tell() ),
75 pHexTable
.reset( new short[ 256 ] );
76 maUpperName
= "SVIXBM";
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
,
120 sal_Int32 nPos1
, nPos2
;
126 if( !pInStm
->ReadLine( aRet
) )
131 if( ( nPos1
= aRet
.indexOf( pTok1
) ) != -1 )
139 if( ( ( nPos2
= aRet
.indexOf( pTok2
) ) != -1 ) &&
153 int XBMReader::ParseDefine( const sal_Char
* pDefine
)
156 const char* pTmp
= pDefine
;
160 pTmp
+= ( strlen( pDefine
) - 1 );
164 while (pHexTable
[ cTmp
] == -1 && pTmp
>= pDefine
)
167 // move before number
168 while (pHexTable
[ cTmp
] != -1 && pTmp
>= pDefine
)
171 // move to start of number
175 if( ( pTmp
[0] == '0' ) && ( ( pTmp
[1] == 'X' ) || ( pTmp
[1] == 'x' ) ) )
178 nRet
= OString(pTmp
, strlen(pTmp
)).toInt32(16);
182 nRet
= OString(pTmp
, strlen(pTmp
)).toInt32();
188 void XBMReader::ParseData( SvStream
* pInStm
, const OString
& aLastLine
, XBMFormat eFormat
)
193 long nBits
= ( eFormat
== XBM10
) ? 16 : 8;
197 bool bFirstLine
= true;
199 while( nRow
< nHeight
)
205 // delete opening curly bracket
206 if( (nPos
= ( aLine
= aLastLine
).indexOf('{') ) != -1 )
207 aLine
= aLine
.copy(nPos
+ 1);
211 else if( !pInStm
->ReadLine( aLine
) )
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;
226 const unsigned char cChar
= aLine
[nIndex
];
229 if (cChar
==',') // sequence completed, ',' already skipped for next loop
232 const short nTable
= pHexTable
[ cChar
];
234 if( rtl::isAsciiHexDigit( cChar
) || !nTable
)
236 nValue
= ( nValue
<< 4 ) + nTable
;
240 else if( ( nTable
< 0 ) && nDigits
)
249 Scanline pScanline
= pAcc1
->GetScanline(nRow
);
250 while( ( nCol
< nWidth
) && ( nBit
< nBits
) )
251 pAcc1
->SetPixelOnData(pScanline
, nCol
++, ( nValue
& ( 1 << nBit
++ ) ) ? aBlack
: aWhite
);
264 ReadState
XBMReader::ReadXBM( Graphic
& rGraphic
)
266 ReadState eReadState
;
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
);
279 OString aLine
= FindTokenLine( &rIStm
, "#define", "_width" );
284 if ( ( nValue
= ParseDefine( aLine
.getStr() ) ) > 0 )
287 aLine
= FindTokenLine( &rIStm
, "#define", "_height" );
289 // if height was not received, we search again
290 // from start of the file
293 rIStm
.Seek( nLastPos
);
294 aLine
= FindTokenLine( &rIStm
, "#define", "_height" );
302 if ( ( nValue
= ParseDefine( aLine
.getStr() ) ) > 0 )
305 aLine
= FindTokenLine( &rIStm
, "static", "_bits" );
309 XBMFormat eFormat
= XBM10
;
311 if (aLine
.indexOf("short") != -1)
313 else if (aLine
.indexOf("char") != -1)
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)
323 if ( bStatus
&& nWidth
&& nHeight
)
325 aBmp1
= Bitmap( Size( nWidth
, nHeight
), 1 );
326 pAcc1
= BitmapScopedWriteAccess(aBmp1
);
330 aWhite
= pAcc1
->GetBestMatchingColor( COL_WHITE
);
331 aBlack
= pAcc1
->GetBestMatchingColor( COL_BLACK
);
332 ParseData( &rIStm
, aLine
, eFormat
);
342 if (bStatus
&& pAcc1
)
344 Bitmap
aBlackBmp( Size( pAcc1
->Width(), pAcc1
->Height() ), 1 );
347 aBlackBmp
.Erase( COL_BLACK
);
348 rGraphic
= BitmapEx( aBlackBmp
, aBmp1
);
349 eReadState
= XBMREAD_OK
;
352 eReadState
= XBMREAD_ERROR
;
357 eReadState
= XBMREAD_NEED_MORE
;
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() );
370 pContext
= std::make_shared
<XBMReader
>( rStm
);
371 pXBMReader
= static_cast<XBMReader
*>( pContext
.get() );
376 ReadState eReadState
= pXBMReader
->ReadXBM( rGraphic
);
378 if( eReadState
== XBMREAD_ERROR
)
382 else if( eReadState
== XBMREAD_NEED_MORE
)
383 rGraphic
.SetContext( pContext
);
388 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */