LibreOffice Module vcl (master)  1
xbmread.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <memory>
21 #include <sal/config.h>
22 #include <tools/stream.hxx>
23 
24 #include <rtl/character.hxx>
25 #include <bitmapwriteaccess.hxx>
26 
27 #include "xbmread.hxx"
28 
30 {
33 };
34 
36 {
40 };
41 
42 class XBMReader : public GraphicReader
43 {
47  std::unique_ptr<short[]>
51  long const nLastPos;
52  long nWidth;
53  long nHeight;
54  bool bStatus;
55 
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 );
60 
61 public:
62 
63  explicit XBMReader( SvStream& rStm );
64 
65  ReadState ReadXBM( Graphic& rGraphic );
66 };
67 
69  rIStm ( rStm ),
70  nLastPos ( rStm.Tell() ),
71  nWidth ( 0 ),
72  nHeight ( 0 ),
73  bStatus ( true )
74 {
75  pHexTable.reset( new short[ 256 ] );
76  maUpperName = "SVIXBM";
77  InitTable();
78 }
79 
81 {
82  memset( pHexTable.get(), 0, sizeof( short ) * 256 );
83 
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;
114 }
115 
116 OString XBMReader::FindTokenLine( SvStream* pInStm, const char* pTok1,
117  const char* pTok2 )
118 {
119  OString aRet;
120  sal_Int32 nPos1, nPos2;
121 
122  bStatus = false;
123 
124  do
125  {
126  if( !pInStm->ReadLine( aRet ) )
127  break;
128 
129  if( pTok1 )
130  {
131  if( ( nPos1 = aRet.indexOf( pTok1 ) ) != -1 )
132  {
133  bStatus = true;
134 
135  if( pTok2 )
136  {
137  bStatus = false;
138 
139  if( ( ( nPos2 = aRet.indexOf( pTok2 ) ) != -1 ) &&
140  ( nPos2 > nPos1 ) )
141  {
142  bStatus = true;
143  }
144  }
145  }
146  }
147  }
148  while( !bStatus );
149 
150  return aRet;
151 }
152 
153 int XBMReader::ParseDefine( const sal_Char* pDefine )
154 {
155  sal_Int32 nRet = 0;
156  const char* pTmp = pDefine;
157  unsigned char cTmp;
158 
159  // move to end
160  pTmp += ( strlen( pDefine ) - 1 );
161  cTmp = *pTmp--;
162 
163  // search last digit
164  while (pHexTable[ cTmp ] == -1 && pTmp >= pDefine)
165  cTmp = *pTmp--;
166 
167  // move before number
168  while (pHexTable[ cTmp ] != -1 && pTmp >= pDefine)
169  cTmp = *pTmp--;
170 
171  // move to start of number
172  pTmp += 2;
173 
174  // read Hex
175  if( ( pTmp[0] == '0' ) && ( ( pTmp[1] == 'X' ) || ( pTmp[1] == 'x' ) ) )
176  {
177  pTmp += 2;
178  nRet = OString(pTmp, strlen(pTmp)).toInt32(16);
179  }
180  else // read decimal
181  {
182  nRet = OString(pTmp, strlen(pTmp)).toInt32();
183  }
184 
185  return nRet;
186 }
187 
188 void XBMReader::ParseData( SvStream* pInStm, const OString& aLastLine, XBMFormat eFormat )
189 {
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;
198 
199  while( nRow < nHeight )
200  {
201  if( bFirstLine )
202  {
203  sal_Int32 nPos;
204 
205  // delete opening curly bracket
206  if( (nPos = ( aLine = aLastLine ).indexOf('{') ) != -1 )
207  aLine = aLine.copy(nPos + 1);
208 
209  bFirstLine = false;
210  }
211  else if( !pInStm->ReadLine( aLine ) )
212  break;
213 
214  if (!aLine.isEmpty())
215  {
216  sal_Int32 nIndex = 0;
217  const sal_Int32 nLen {aLine.getLength()};
218  while (nRow<nHeight && nIndex<nLen)
219  {
220  bool bProcessed = false;
221 
222  nBit = nDigits = nValue = 0;
223 
224  while (nIndex<nLen)
225  {
226  const unsigned char cChar = aLine[nIndex];
227 
228  ++nIndex;
229  if (cChar==',') // sequence completed, ',' already skipped for next loop
230  break;
231 
232  const short nTable = pHexTable[ cChar ];
233 
234  if( rtl::isAsciiHexDigit( cChar ) || !nTable )
235  {
236  nValue = ( nValue << 4 ) + nTable;
237  nDigits++;
238  bProcessed = true;
239  }
240  else if( ( nTable < 0 ) && nDigits )
241  {
242  bProcessed = true;
243  break;
244  }
245  }
246 
247  if( bProcessed )
248  {
249  Scanline pScanline = pAcc1->GetScanline(nRow);
250  while( ( nCol < nWidth ) && ( nBit < nBits ) )
251  pAcc1->SetPixelOnData(pScanline, nCol++, ( nValue & ( 1 << nBit++ ) ) ? aBlack : aWhite);
252 
253  if( nCol == nWidth )
254  {
255  nCol = 0;
256  nRow++;
257  }
258  }
259  }
260  }
261  }
262 }
263 
265 {
266  ReadState eReadState;
267  sal_uInt8 cDummy;
268 
269  // check if we can read ALL
271  rIStm.ReadUChar( cDummy );
272 
273  // if we cannot read all
274  // we return and wait for new data
275  if ( rIStm.GetError() != ERRCODE_IO_PENDING )
276  {
277  rIStm.Seek( nLastPos );
278  bStatus = false;
279  OString aLine = FindTokenLine( &rIStm, "#define", "_width" );
280 
281  if ( bStatus )
282  {
283  int nValue;
284  if ( ( nValue = ParseDefine( aLine.getStr() ) ) > 0 )
285  {
286  nWidth = nValue;
287  aLine = FindTokenLine( &rIStm, "#define", "_height" );
288 
289  // if height was not received, we search again
290  // from start of the file
291  if ( !bStatus )
292  {
293  rIStm.Seek( nLastPos );
294  aLine = FindTokenLine( &rIStm, "#define", "_height" );
295  }
296  }
297  else
298  bStatus = false;
299 
300  if ( bStatus )
301  {
302  if ( ( nValue = ParseDefine( aLine.getStr() ) ) > 0 )
303  {
304  nHeight = nValue;
305  aLine = FindTokenLine( &rIStm, "static", "_bits" );
306 
307  if ( bStatus )
308  {
309  XBMFormat eFormat = XBM10;
310 
311  if (aLine.indexOf("short") != -1)
312  eFormat = XBM10;
313  else if (aLine.indexOf("char") != -1)
314  eFormat = XBM11;
315  else
316  bStatus = false;
317 
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;
322 
323  if ( bStatus && nWidth && nHeight )
324  {
325  aBmp1 = Bitmap( Size( nWidth, nHeight ), 1 );
327 
328  if( pAcc1 )
329  {
332  ParseData( &rIStm, aLine, eFormat );
333  }
334  else
335  bStatus = false;
336  }
337  }
338  }
339  }
340  }
341 
342  if (bStatus && pAcc1)
343  {
344  Bitmap aBlackBmp( Size( pAcc1->Width(), pAcc1->Height() ), 1 );
345 
346  pAcc1.reset();
347  aBlackBmp.Erase( COL_BLACK );
348  rGraphic = BitmapEx( aBlackBmp, aBmp1 );
349  eReadState = XBMREAD_OK;
350  }
351  else
352  eReadState = XBMREAD_ERROR;
353  }
354  else
355  {
356  rIStm.ResetError();
357  eReadState = XBMREAD_NEED_MORE;
358  }
359 
360  return eReadState;
361 }
362 
363 VCL_DLLPUBLIC bool ImportXBM( SvStream& rStm, Graphic& rGraphic )
364 {
365  std::shared_ptr<GraphicReader> pContext = rGraphic.GetContext();
366  rGraphic.SetContext(nullptr);
367  XBMReader* pXBMReader = dynamic_cast<XBMReader*>( pContext.get() );
368  if (!pXBMReader)
369  {
370  pContext = std::make_shared<XBMReader>( rStm );
371  pXBMReader = static_cast<XBMReader*>( pContext.get() );
372  }
373 
374  bool bRet = true;
375 
376  ReadState eReadState = pXBMReader->ReadXBM( rGraphic );
377 
378  if( eReadState == XBMREAD_ERROR )
379  {
380  bRet = false;
381  }
382  else if( eReadState == XBMREAD_NEED_MORE )
383  rGraphic.SetContext( pContext );
384 
385  return bRet;
386 }
387 
388 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
BitmapColor aWhite
Definition: xbmread.cxx:49
constexpr::Color COL_BLACK(0x00, 0x00, 0x00)
void InitTable()
Definition: xbmread.cxx:80
Scanline GetScanline(long nY) const
int ParseDefine(const sal_Char *pDefine)
Definition: xbmread.cxx:153
void SetContext(const std::shared_ptr< GraphicReader > &pReader)
Definition: graph.cxx:501
XBMReader(SvStream &rStm)
Definition: xbmread.cxx:68
#define VCL_DLLPUBLIC
Definition: dllapi.h:29
const wchar_t *typedef int(__stdcall *DllNativeUnregProc)(int
vcl::ScopedBitmapAccess< BitmapWriteAccess, Bitmap,&Bitmap::AcquireWriteAccess > BitmapScopedWriteAccess
std::shared_ptr< GraphicReader > & GetContext()
Definition: graph.cxx:496
#define STREAM_SEEK_TO_END
sal_uInt64 Seek(sal_uInt64 nPos)
ReadState
Definition: gifread.cxx:41
ReadState ReadXBM(Graphic &rGraphic)
Definition: xbmread.cxx:264
long Width() const
OUString maUpperName
Definition: graph.hxx:68
long nHeight
Definition: xbmread.cxx:53
Bitmap aBmp1
Definition: xbmread.cxx:45
bool bStatus
Definition: xbmread.cxx:54
ErrCode GetError() const
char sal_Char
bool ReadLine(OString &rStr, sal_Int32 nMaxBytesToRead=0xFFFE)
XBMFormat
Definition: xbmread.cxx:29
long nWidth
Definition: xbmread.cxx:52
void SetPixelOnData(sal_uInt8 *pData, long nX, const BitmapColor &rBitmapColor)
sal_uInt64 remainingSize()
std::unique_ptr< short[]> pHexTable
Definition: xbmread.cxx:48
sal_uInt8 * Scanline
Definition: Scanline.hxx:25
BitmapScopedWriteAccess pAcc1
Definition: xbmread.cxx:46
long const nLastPos
Definition: xbmread.cxx:51
VCL_DLLPUBLIC bool ImportXBM(SvStream &rStm, Graphic &rGraphic)
Definition: xbmread.cxx:363
SvStream & ReadUChar(unsigned char &rChar)
void ParseData(SvStream *pInStm, const OString &aLastLine, XBMFormat eFormat)
Definition: xbmread.cxx:188
long Height() const
unsigned char sal_uInt8
constexpr::Color COL_WHITE(0xFF, 0xFF, 0xFF)
OString FindTokenLine(SvStream *pInStm, const char *pTok1, const char *pTok2)
Definition: xbmread.cxx:116
bool Erase(const Color &rFillColor)
Fill the entire bitmap with the given color.
Definition: bitmappaint.cxx:34
#define ERRCODE_IO_PENDING
Definition: errcode.hxx:227
virtual void ResetError()
SvStream & rIStm
Definition: xbmread.cxx:44
BitmapColor aBlack
Definition: xbmread.cxx:50
sal_Int32 nPos
BitmapColor GetBestMatchingColor(const BitmapColor &rBitmapColor)