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 <comphelper/string.hxx>
22 #include "xbmread.hxx"
37 class XBMReader
: public GraphicReader
41 Bitmap::ScopedWriteAccess pAcc1
;
42 std::unique_ptr
<short[]>
52 OString
FindTokenLine( SvStream
* pInStm
, const char* pTok1
, const char* pTok2
);
53 long ParseDefine( const sal_Char
* pDefine
);
54 bool ParseData( SvStream
* pInStm
, const OString
& aLastLine
, XBMFormat eFormat
);
58 explicit XBMReader( SvStream
& rStm
);
60 ReadState
ReadXBM( Graphic
& rGraphic
);
63 XBMReader::XBMReader( SvStream
& rStm
) :
65 nLastPos ( rStm
.Tell() ),
70 pHexTable
.reset( new short[ 256 ] );
71 maUpperName
= "SVIXBM";
75 void XBMReader::InitTable()
77 memset( pHexTable
.get(), 0, sizeof( short ) * 256 );
79 pHexTable
[(int)'0'] = 0;
80 pHexTable
[(int)'1'] = 1;
81 pHexTable
[(int)'2'] = 2;
82 pHexTable
[(int)'3'] = 3;
83 pHexTable
[(int)'4'] = 4;
84 pHexTable
[(int)'5'] = 5;
85 pHexTable
[(int)'6'] = 6;
86 pHexTable
[(int)'7'] = 7;
87 pHexTable
[(int)'8'] = 8;
88 pHexTable
[(int)'9'] = 9;
89 pHexTable
[(int)'A'] = 10;
90 pHexTable
[(int)'B'] = 11;
91 pHexTable
[(int)'C'] = 12;
92 pHexTable
[(int)'D'] = 13;
93 pHexTable
[(int)'E'] = 14;
94 pHexTable
[(int)'F'] = 15;
95 pHexTable
[(int)'X'] = 0;
96 pHexTable
[(int)'a'] = 10;
97 pHexTable
[(int)'b'] = 11;
98 pHexTable
[(int)'c'] = 12;
99 pHexTable
[(int)'d'] = 13;
100 pHexTable
[(int)'e'] = 14;
101 pHexTable
[(int)'f'] = 15;
102 pHexTable
[(int)'x'] = 0;
103 pHexTable
[(int)' '] = -1;
104 pHexTable
[(int)','] = -1;
105 pHexTable
[(int)'}'] = -1;
106 pHexTable
[(int)'\n'] = -1;
107 pHexTable
[(int)'\t'] = -1;
108 pHexTable
[(int)'\0'] = -1;
111 OString
XBMReader::FindTokenLine( SvStream
* pInStm
, const char* pTok1
,
115 sal_Int32 nPos1
, nPos2
;
121 if( !pInStm
->ReadLine( aRet
) )
126 if( ( nPos1
= aRet
.indexOf( pTok1
) ) != -1 )
134 if( ( ( nPos2
= aRet
.indexOf( pTok2
) ) != -1 ) &&
148 long XBMReader::ParseDefine( const sal_Char
* pDefine
)
151 char* pTmp
= const_cast<char*>(pDefine
);
155 pTmp
+= ( strlen( pDefine
) - 1 );
159 while (pHexTable
[ cTmp
] == -1 && pTmp
>= pDefine
)
162 // move before number
163 while (pHexTable
[ cTmp
] != -1 && pTmp
>= pDefine
)
166 // move to start of number
170 if( ( pTmp
[0] == '0' ) && ( ( pTmp
[1] == 'X' ) || ( pTmp
[1] == 'x' ) ) )
175 while ( pHexTable
[ cTmp
] != -1 )
177 nRet
= ( nRet
<< 4 ) + pHexTable
[ cTmp
];
185 while( ( cTmp
>= '0' ) && ( cTmp
<= '9' ) )
187 nRet
= nRet
* 10 + ( cTmp
- '0' );
195 bool XBMReader::ParseData( SvStream
* pInStm
, const OString
& aLastLine
, XBMFormat eFormat
)
200 long nBits
= ( eFormat
== XBM10
) ? 16 : 8;
204 bool bFirstLine
= true;
206 while( nRow
< nHeight
)
212 // delete opening curly bracket
213 if( (nPos
= ( aLine
= aLastLine
).indexOf('{') ) != -1 )
214 aLine
= aLine
.copy(nPos
+ 1);
218 else if( !pInStm
->ReadLine( aLine
) )
221 if (!aLine
.isEmpty())
223 const sal_Int32 nCount
= comphelper::string::getTokenCount(aLine
, ',');
225 for( sal_Int32 i
= 0; ( i
< nCount
) && ( nRow
< nHeight
); ++i
)
227 const OString
aToken(aLine
.getToken(i
, ','));
228 const sal_Int32 nLen
= aToken
.getLength();
229 bool bProcessed
= false;
231 nBit
= nDigits
= nValue
= 0;
233 for (sal_Int32 n
= 0; n
< nLen
; ++n
)
235 const unsigned char cChar
= aToken
[n
];
236 const short nTable
= pHexTable
[ cChar
];
238 if( isxdigit( cChar
) || !nTable
)
240 nValue
= ( nValue
<< 4 ) + nTable
;
244 else if( ( nTable
< 0 ) && nDigits
)
253 while( ( nCol
< nWidth
) && ( nBit
< nBits
) )
254 pAcc1
->SetPixel( nRow
, nCol
++, ( nValue
& ( 1 << nBit
++ ) ) ? aBlack
: aWhite
);
269 ReadState
XBMReader::ReadXBM( Graphic
& rGraphic
)
271 ReadState eReadState
;
274 // check if we can read ALL
275 rIStm
.Seek( STREAM_SEEK_TO_END
);
276 rIStm
.ReadUChar( cDummy
);
278 // if we cannot read all
279 // we return and wait for new data
280 if ( rIStm
.GetError() != ERRCODE_IO_PENDING
)
282 rIStm
.Seek( nLastPos
);
284 OString aLine
= FindTokenLine( &rIStm
, "#define", "_width" );
289 if ( ( nValue
= (int) ParseDefine( aLine
.getStr() ) ) > 0 )
292 aLine
= FindTokenLine( &rIStm
, "#define", "_height" );
294 // if height was not received, we search again
295 // from start of the file
298 rIStm
.Seek( nLastPos
);
299 aLine
= FindTokenLine( &rIStm
, "#define", "_height" );
307 if ( ( nValue
= (int) ParseDefine( aLine
.getStr() ) ) > 0 )
310 aLine
= FindTokenLine( &rIStm
, "static", "_bits" );
314 XBMFormat eFormat
= XBM10
;
316 if (aLine
.indexOf("short") != -1)
318 else if (aLine
.indexOf("char") != -1)
323 if ( bStatus
&& nWidth
&& nHeight
)
325 aBmp1
= Bitmap( Size( nWidth
, nHeight
), 1 );
326 pAcc1
= Bitmap::ScopedWriteAccess(aBmp1
);
330 aWhite
= pAcc1
->GetBestMatchingColor( Color( COL_WHITE
) );
331 aBlack
= pAcc1
->GetBestMatchingColor( Color( COL_BLACK
) );
332 bStatus
= ParseData( &rIStm
, aLine
, eFormat
);
342 if (bStatus
&& pAcc1
)
344 Bitmap
aBlackBmp( Size( pAcc1
->Width(), pAcc1
->Height() ), 1 );
347 aBlackBmp
.Erase( Color( 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: */