tdf#154285 Check upper bound of arguments in SbRtl_Minute function
[LibreOffice.git] / vcl / source / filter / ixbm / xbmread.cxx
blob2a701e4ce0253e2ad530a584f1b0ed3af5e670fa
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>
23 #include <o3tl/string_view.hxx>
24 #include <rtl/character.hxx>
26 #include <vcl/BitmapWriteAccess.hxx>
28 #include "xbmread.hxx"
30 namespace
33 enum XBMFormat
35 XBM10,
36 XBM11
39 enum ReadState
41 XBMREAD_OK,
42 XBMREAD_ERROR
45 class XBMReader
47 SvStream& mrStream;
48 Bitmap maBitmap;
49 BitmapScopedWriteAccess mpWriteAccess;
50 std::array<short, 256> mpHexTable = { 0 };
51 BitmapColor maWhite;
52 BitmapColor maBlack;
53 sal_uInt64 mnLastPosition = 0;
54 tools::Long nWidth = 0;
55 tools::Long nHeight = 0;
56 bool bStatus = true;
58 void InitTable();
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);
63 public:
65 explicit XBMReader(SvStream& rStream);
67 ReadState ReadXBM(BitmapEx& rBitmapEx);
72 XBMReader::XBMReader(SvStream& rStream)
73 : mrStream(rStream)
74 , mnLastPosition(rStream.Tell())
76 InitTable();
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,
114 const char* pTok2 )
116 OString aRet;
117 sal_Int32 nPos1, nPos2;
119 bStatus = false;
123 if( !pInStm->ReadLine( aRet ) )
124 break;
126 if( pTok1 )
128 if( ( nPos1 = aRet.indexOf( pTok1 ) ) != -1 )
130 bStatus = true;
132 if( pTok2 )
134 bStatus = false;
136 nPos2 = aRet.indexOf( pTok2 );
137 if( ( nPos2 != -1 ) && ( nPos2 > nPos1 ) )
139 bStatus = true;
145 while( !bStatus );
147 return aRet;
150 int XBMReader::ParseDefine( const char* pDefine )
152 sal_Int32 nRet = 0;
153 const char* pTmp = pDefine;
154 unsigned char cTmp;
156 // move to end
157 pTmp += ( strlen( pDefine ) - 1 );
158 cTmp = *pTmp--;
160 // search last digit
161 while (mpHexTable[ cTmp ] == -1 && pTmp >= pDefine)
162 cTmp = *pTmp--;
164 // move before number
165 while (mpHexTable[ cTmp ] != -1 && pTmp >= pDefine)
166 cTmp = *pTmp--;
168 // move to start of number
169 pTmp += 2;
171 // read Hex
172 if( ( pTmp[0] == '0' ) && ( ( pTmp[1] == 'X' ) || ( pTmp[1] == 'x' ) ) )
174 pTmp += 2;
175 nRet = o3tl::toInt32(std::string_view(pTmp), 16);
177 else // read decimal
179 nRet = o3tl::toInt32(std::string_view(pTmp));
182 return nRet;
185 void XBMReader::ParseData( SvStream* pInStm, const OString& aLastLine, XBMFormat eFormat )
187 OString aLine;
188 tools::Long nRow = 0;
189 tools::Long nCol = 0;
190 tools::Long nBits = ( eFormat == XBM10 ) ? 16 : 8;
191 tools::Long nBit;
192 sal_uInt16 nValue;
193 sal_uInt16 nDigits;
194 bool bFirstLine = true;
196 while( nRow < nHeight )
198 if( bFirstLine )
200 sal_Int32 nPos;
202 // delete opening curly bracket
203 aLine = aLastLine;
204 nPos = aLine.indexOf('{');
205 if( nPos != -1 )
206 aLine = aLine.copy(nPos + 1);
208 bFirstLine = false;
210 else if( !pInStm->ReadLine( aLine ) )
211 break;
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;
223 while (nIndex<nLen)
225 const unsigned char cChar = aLine[nIndex];
227 ++nIndex;
228 if (cChar==',') // sequence completed, ',' already skipped for next loop
229 break;
231 const short nTable = mpHexTable[cChar];
233 if( rtl::isAsciiHexDigit( cChar ) || !nTable )
235 nValue = ( nValue << 4 ) + nTable;
236 nDigits++;
237 bProcessed = true;
239 else if( ( nTable < 0 ) && nDigits )
241 bProcessed = true;
242 break;
246 if( bProcessed )
248 Scanline pScanline = mpWriteAccess->GetScanline(nRow);
249 while( ( nCol < nWidth ) && ( nBit < nBits ) )
250 mpWriteAccess->SetPixelOnData(pScanline, nCol++, ( nValue & ( 1 << nBit++ ) ) ? maBlack : maWhite);
252 if( nCol == nWidth )
254 nCol = 0;
255 nRow++;
263 ReadState XBMReader::ReadXBM(BitmapEx& rBitmapEx)
265 if (!mrStream.good())
266 return XBMREAD_ERROR;
268 ReadState eReadState = XBMREAD_ERROR;
270 mrStream.Seek(mnLastPosition);
271 bStatus = false;
272 OString aLine = FindTokenLine(&mrStream, "#define", "_width");
274 if ( bStatus )
276 int nValue;
277 if ( ( nValue = ParseDefine( aLine.getStr() ) ) > 0 )
279 nWidth = nValue;
280 aLine = FindTokenLine(&mrStream, "#define", "_height");
282 // if height was not received, we search again
283 // from start of the file
284 if ( !bStatus )
286 mrStream.Seek(mnLastPosition);
287 aLine = FindTokenLine(&mrStream, "#define", "_height");
290 else
291 bStatus = false;
293 if ( bStatus )
295 if ( ( nValue = ParseDefine( aLine.getStr() ) ) > 0 )
297 nHeight = nValue;
298 aLine = FindTokenLine(&mrStream, "static", "_bits");
300 if ( bStatus )
302 XBMFormat eFormat = XBM10;
304 if (aLine.indexOf("short") != -1)
305 eFormat = XBM10;
306 else if (aLine.indexOf("char") != -1)
307 eFormat = XBM11;
308 else
309 bStatus = false;
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)
314 bStatus = false;
316 if ( bStatus && nWidth && nHeight )
318 maBitmap = Bitmap(Size(nWidth, nHeight), vcl::PixelFormat::N8_BPP, &Bitmap::GetGreyPalette(256));
319 mpWriteAccess = maBitmap;
321 if (mpWriteAccess)
323 maWhite = mpWriteAccess->GetBestMatchingColor(COL_WHITE);
324 maBlack = mpWriteAccess->GetBestMatchingColor(COL_BLACK);
325 ParseData(&mrStream, aLine, eFormat);
327 else
328 bStatus = false;
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;
345 return eReadState;
348 VCL_DLLPUBLIC bool ImportXBM(SvStream& rStmeam, Graphic& rGraphic)
350 XBMReader aXBMReader(rStmeam);
351 BitmapEx aBitmapEx;
352 ReadState eReadState = aXBMReader.ReadXBM(aBitmapEx);
353 if (eReadState == XBMREAD_ERROR)
354 return false;
355 rGraphic = Graphic(aBitmapEx);
356 return true;
359 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */