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>
23 #include <o3tl/string_view.hxx>
24 #include <rtl/character.hxx>
26 #include <vcl/BitmapWriteAccess.hxx>
28 #include "xbmread.hxx"
49 BitmapScopedWriteAccess mpWriteAccess
;
50 std::array
<short, 256> mpHexTable
= { 0 };
53 sal_uInt64 mnLastPosition
= 0;
54 tools::Long nWidth
= 0;
55 tools::Long nHeight
= 0;
59 OString
FindTokenLine(SvStream
* pInStm
, const char* pTok1
, const char* pTok2
);
60 int ParseDefine(const char* pDefine
);
61 void ParseData(SvStream
* pInStm
, const OString
& aLastLine
, XBMFormat eFormat
);
65 explicit XBMReader(SvStream
& rStream
);
67 ReadState
ReadXBM(BitmapEx
& rBitmapEx
);
72 XBMReader::XBMReader(SvStream
& rStream
)
74 , mnLastPosition(rStream
.Tell())
79 void XBMReader::InitTable()
81 mpHexTable
[int('0')] = 0;
82 mpHexTable
[int('1')] = 1;
83 mpHexTable
[int('2')] = 2;
84 mpHexTable
[int('3')] = 3;
85 mpHexTable
[int('4')] = 4;
86 mpHexTable
[int('5')] = 5;
87 mpHexTable
[int('6')] = 6;
88 mpHexTable
[int('7')] = 7;
89 mpHexTable
[int('8')] = 8;
90 mpHexTable
[int('9')] = 9;
91 mpHexTable
[int('A')] = 10;
92 mpHexTable
[int('B')] = 11;
93 mpHexTable
[int('C')] = 12;
94 mpHexTable
[int('D')] = 13;
95 mpHexTable
[int('E')] = 14;
96 mpHexTable
[int('F')] = 15;
97 mpHexTable
[int('X')] = 0;
98 mpHexTable
[int('a')] = 10;
99 mpHexTable
[int('b')] = 11;
100 mpHexTable
[int('c')] = 12;
101 mpHexTable
[int('d')] = 13;
102 mpHexTable
[int('e')] = 14;
103 mpHexTable
[int('f')] = 15;
104 mpHexTable
[int('x')] = 0;
105 mpHexTable
[int(' ')] = -1;
106 mpHexTable
[int(',')] = -1;
107 mpHexTable
[int('}')] = -1;
108 mpHexTable
[int('\n')] = -1;
109 mpHexTable
[int('\t')] = -1;
110 mpHexTable
[int('\0')] = -1;
113 OString
XBMReader::FindTokenLine( SvStream
* pInStm
, const char* pTok1
,
117 sal_Int32 nPos1
, nPos2
;
123 if( !pInStm
->ReadLine( aRet
) )
128 if( ( nPos1
= aRet
.indexOf( pTok1
) ) != -1 )
136 nPos2
= aRet
.indexOf( pTok2
);
137 if( ( nPos2
!= -1 ) && ( nPos2
> nPos1
) )
150 int XBMReader::ParseDefine( const char* pDefine
)
153 const char* pTmp
= pDefine
;
157 pTmp
+= ( strlen( pDefine
) - 1 );
161 while (mpHexTable
[ cTmp
] == -1 && pTmp
>= pDefine
)
164 // move before number
165 while (mpHexTable
[ cTmp
] != -1 && pTmp
>= pDefine
)
168 // move to start of number
172 if( ( pTmp
[0] == '0' ) && ( ( pTmp
[1] == 'X' ) || ( pTmp
[1] == 'x' ) ) )
175 nRet
= o3tl::toInt32(std::string_view(pTmp
), 16);
179 nRet
= o3tl::toInt32(std::string_view(pTmp
));
185 void XBMReader::ParseData( SvStream
* pInStm
, const OString
& aLastLine
, XBMFormat eFormat
)
188 tools::Long nRow
= 0;
189 tools::Long nCol
= 0;
190 tools::Long nBits
= ( eFormat
== XBM10
) ? 16 : 8;
194 bool bFirstLine
= true;
196 while( nRow
< nHeight
)
202 // delete opening curly bracket
204 nPos
= aLine
.indexOf('{');
206 aLine
= aLine
.copy(nPos
+ 1);
210 else if( !pInStm
->ReadLine( aLine
) )
213 if (!aLine
.isEmpty())
215 sal_Int32 nIndex
= 0;
216 const sal_Int32 nLen
{aLine
.getLength()};
217 while (nRow
<nHeight
&& nIndex
<nLen
)
219 bool bProcessed
= false;
221 nBit
= nDigits
= nValue
= 0;
225 const unsigned char cChar
= aLine
[nIndex
];
228 if (cChar
==',') // sequence completed, ',' already skipped for next loop
231 const short nTable
= mpHexTable
[cChar
];
233 if( rtl::isAsciiHexDigit( cChar
) || !nTable
)
235 nValue
= ( nValue
<< 4 ) + nTable
;
239 else if( ( nTable
< 0 ) && nDigits
)
248 Scanline pScanline
= mpWriteAccess
->GetScanline(nRow
);
249 while( ( nCol
< nWidth
) && ( nBit
< nBits
) )
250 mpWriteAccess
->SetPixelOnData(pScanline
, nCol
++, ( nValue
& ( 1 << nBit
++ ) ) ? maBlack
: maWhite
);
263 ReadState
XBMReader::ReadXBM(BitmapEx
& rBitmapEx
)
265 if (!mrStream
.good())
266 return XBMREAD_ERROR
;
268 ReadState eReadState
= XBMREAD_ERROR
;
270 mrStream
.Seek(mnLastPosition
);
272 OString aLine
= FindTokenLine(&mrStream
, "#define", "_width");
277 if ( ( nValue
= ParseDefine( aLine
.getStr() ) ) > 0 )
280 aLine
= FindTokenLine(&mrStream
, "#define", "_height");
282 // if height was not received, we search again
283 // from start of the file
286 mrStream
.Seek(mnLastPosition
);
287 aLine
= FindTokenLine(&mrStream
, "#define", "_height");
295 if ( ( nValue
= ParseDefine( aLine
.getStr() ) ) > 0 )
298 aLine
= FindTokenLine(&mrStream
, "static", "_bits");
302 XBMFormat eFormat
= XBM10
;
304 if (aLine
.indexOf("short") != -1)
306 else if (aLine
.indexOf("char") != -1)
311 //xbms are a minimum of one character per 8 pixels, so if the file isn't
312 //even that long, it's not all there
313 if (mrStream
.remainingSize() < (static_cast<sal_uInt64
>(nWidth
) * nHeight
) / 8)
316 if ( bStatus
&& nWidth
&& nHeight
)
318 maBitmap
= Bitmap(Size(nWidth
, nHeight
), vcl::PixelFormat::N8_BPP
, &Bitmap::GetGreyPalette(256));
319 mpWriteAccess
= maBitmap
;
323 maWhite
= mpWriteAccess
->GetBestMatchingColor(COL_WHITE
);
324 maBlack
= mpWriteAccess
->GetBestMatchingColor(COL_BLACK
);
325 ParseData(&mrStream
, aLine
, eFormat
);
335 if (bStatus
&& mpWriteAccess
)
337 Bitmap
aBlackBmp(Size(mpWriteAccess
->Width(), mpWriteAccess
->Height()), vcl::PixelFormat::N8_BPP
, &Bitmap::GetGreyPalette(256));
339 mpWriteAccess
.reset();
340 aBlackBmp
.Erase( COL_BLACK
);
341 rBitmapEx
= BitmapEx(aBlackBmp
, maBitmap
);
342 eReadState
= XBMREAD_OK
;
348 VCL_DLLPUBLIC
bool ImportXBM(SvStream
& rStmeam
, Graphic
& rGraphic
)
350 XBMReader
aXBMReader(rStmeam
);
352 ReadState eReadState
= aXBMReader
.ReadXBM(aBitmapEx
);
353 if (eReadState
== XBMREAD_ERROR
)
355 rGraphic
= Graphic(aBitmapEx
);
359 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */