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 
28 
29 #include "xbmread.hxx"
30 
31 namespace {
32 
34 {
35  XBM10,
36  XBM11
37 };
38 
40 {
41  XBMREAD_OK,
42  XBMREAD_ERROR,
43  XBMREAD_NEED_MORE
44 };
45 
46 class XBMReader : public GraphicReader
47 {
48  SvStream& rIStm;
49  Bitmap aBmp1;
51  std::unique_ptr<short[]>
52  pHexTable;
53  BitmapColor aWhite;
54  BitmapColor aBlack;
55  tools::Long nLastPos;
56  tools::Long nWidth;
57  tools::Long nHeight;
58  bool bStatus;
59 
60  void InitTable();
61  OString FindTokenLine( SvStream* pInStm, const char* pTok1, const char* pTok2 );
62  int ParseDefine( const char* pDefine );
63  void ParseData( SvStream* pInStm, const OString& aLastLine, XBMFormat eFormat );
64 
65 public:
66 
67  explicit XBMReader( SvStream& rStm );
68 
69  ReadState ReadXBM( Graphic& rGraphic );
70 };
71 
72 }
73 
74 XBMReader::XBMReader( SvStream& rStm ) :
75  rIStm ( rStm ),
76  nLastPos ( rStm.Tell() ),
77  nWidth ( 0 ),
78  nHeight ( 0 ),
79  bStatus ( true )
80 {
81  pHexTable.reset( new short[ 256 ] );
82  maUpperName = "SVIXBM";
83  InitTable();
84 }
85 
86 void XBMReader::InitTable()
87 {
88  memset( pHexTable.get(), 0, sizeof( short ) * 256 );
89 
90  pHexTable[int('0')] = 0;
91  pHexTable[int('1')] = 1;
92  pHexTable[int('2')] = 2;
93  pHexTable[int('3')] = 3;
94  pHexTable[int('4')] = 4;
95  pHexTable[int('5')] = 5;
96  pHexTable[int('6')] = 6;
97  pHexTable[int('7')] = 7;
98  pHexTable[int('8')] = 8;
99  pHexTable[int('9')] = 9;
100  pHexTable[int('A')] = 10;
101  pHexTable[int('B')] = 11;
102  pHexTable[int('C')] = 12;
103  pHexTable[int('D')] = 13;
104  pHexTable[int('E')] = 14;
105  pHexTable[int('F')] = 15;
106  pHexTable[int('X')] = 0;
107  pHexTable[int('a')] = 10;
108  pHexTable[int('b')] = 11;
109  pHexTable[int('c')] = 12;
110  pHexTable[int('d')] = 13;
111  pHexTable[int('e')] = 14;
112  pHexTable[int('f')] = 15;
113  pHexTable[int('x')] = 0;
114  pHexTable[int(' ')] = -1;
115  pHexTable[int(',')] = -1;
116  pHexTable[int('}')] = -1;
117  pHexTable[int('\n')] = -1;
118  pHexTable[int('\t')] = -1;
119  pHexTable[int('\0')] = -1;
120 }
121 
122 OString XBMReader::FindTokenLine( SvStream* pInStm, const char* pTok1,
123  const char* pTok2 )
124 {
125  OString aRet;
126  sal_Int32 nPos1, nPos2;
127 
128  bStatus = false;
129 
130  do
131  {
132  if( !pInStm->ReadLine( aRet ) )
133  break;
134 
135  if( pTok1 )
136  {
137  if( ( nPos1 = aRet.indexOf( pTok1 ) ) != -1 )
138  {
139  bStatus = true;
140 
141  if( pTok2 )
142  {
143  bStatus = false;
144 
145  nPos2 = aRet.indexOf( pTok2 );
146  if( ( nPos2 != -1 ) && ( nPos2 > nPos1 ) )
147  {
148  bStatus = true;
149  }
150  }
151  }
152  }
153  }
154  while( !bStatus );
155 
156  return aRet;
157 }
158 
159 int XBMReader::ParseDefine( const char* pDefine )
160 {
161  sal_Int32 nRet = 0;
162  const char* pTmp = pDefine;
163  unsigned char cTmp;
164 
165  // move to end
166  pTmp += ( strlen( pDefine ) - 1 );
167  cTmp = *pTmp--;
168 
169  // search last digit
170  while (pHexTable[ cTmp ] == -1 && pTmp >= pDefine)
171  cTmp = *pTmp--;
172 
173  // move before number
174  while (pHexTable[ cTmp ] != -1 && pTmp >= pDefine)
175  cTmp = *pTmp--;
176 
177  // move to start of number
178  pTmp += 2;
179 
180  // read Hex
181  if( ( pTmp[0] == '0' ) && ( ( pTmp[1] == 'X' ) || ( pTmp[1] == 'x' ) ) )
182  {
183  pTmp += 2;
184  nRet = OString(pTmp, strlen(pTmp)).toInt32(16);
185  }
186  else // read decimal
187  {
188  nRet = OString(pTmp, strlen(pTmp)).toInt32();
189  }
190 
191  return nRet;
192 }
193 
194 void XBMReader::ParseData( SvStream* pInStm, const OString& aLastLine, XBMFormat eFormat )
195 {
196  OString aLine;
197  tools::Long nRow = 0;
198  tools::Long nCol = 0;
199  tools::Long nBits = ( eFormat == XBM10 ) ? 16 : 8;
201  sal_uInt16 nValue;
202  sal_uInt16 nDigits;
203  bool bFirstLine = true;
204 
205  while( nRow < nHeight )
206  {
207  if( bFirstLine )
208  {
209  sal_Int32 nPos;
210 
211  // delete opening curly bracket
212  aLine = aLastLine;
213  nPos = aLine.indexOf('{');
214  if( nPos != -1 )
215  aLine = aLine.copy(nPos + 1);
216 
217  bFirstLine = false;
218  }
219  else if( !pInStm->ReadLine( aLine ) )
220  break;
221 
222  if (!aLine.isEmpty())
223  {
224  sal_Int32 nIndex = 0;
225  const sal_Int32 nLen {aLine.getLength()};
226  while (nRow<nHeight && nIndex<nLen)
227  {
228  bool bProcessed = false;
229 
230  nBit = nDigits = nValue = 0;
231 
232  while (nIndex<nLen)
233  {
234  const unsigned char cChar = aLine[nIndex];
235 
236  ++nIndex;
237  if (cChar==',') // sequence completed, ',' already skipped for next loop
238  break;
239 
240  const short nTable = pHexTable[ cChar ];
241 
242  if( rtl::isAsciiHexDigit( cChar ) || !nTable )
243  {
244  nValue = ( nValue << 4 ) + nTable;
245  nDigits++;
246  bProcessed = true;
247  }
248  else if( ( nTable < 0 ) && nDigits )
249  {
250  bProcessed = true;
251  break;
252  }
253  }
254 
255  if( bProcessed )
256  {
257  Scanline pScanline = pAcc1->GetScanline(nRow);
258  while( ( nCol < nWidth ) && ( nBit < nBits ) )
259  pAcc1->SetPixelOnData(pScanline, nCol++, ( nValue & ( 1 << nBit++ ) ) ? aBlack : aWhite);
260 
261  if( nCol == nWidth )
262  {
263  nCol = 0;
264  nRow++;
265  }
266  }
267  }
268  }
269  }
270 }
271 
272 ReadState XBMReader::ReadXBM( Graphic& rGraphic )
273 {
274  ReadState eReadState;
275  sal_uInt8 cDummy;
276 
277  // check if we can read ALL
278  rIStm.Seek( STREAM_SEEK_TO_END );
279  rIStm.ReadUChar( cDummy );
280 
281  // if we cannot read all
282  // we return and wait for new data
283  if ( rIStm.GetError() != ERRCODE_IO_PENDING )
284  {
285  rIStm.Seek( nLastPos );
286  bStatus = false;
287  OString aLine = FindTokenLine( &rIStm, "#define", "_width" );
288 
289  if ( bStatus )
290  {
291  int nValue;
292  if ( ( nValue = ParseDefine( aLine.getStr() ) ) > 0 )
293  {
294  nWidth = nValue;
295  aLine = FindTokenLine( &rIStm, "#define", "_height" );
296 
297  // if height was not received, we search again
298  // from start of the file
299  if ( !bStatus )
300  {
301  rIStm.Seek( nLastPos );
302  aLine = FindTokenLine( &rIStm, "#define", "_height" );
303  }
304  }
305  else
306  bStatus = false;
307 
308  if ( bStatus )
309  {
310  if ( ( nValue = ParseDefine( aLine.getStr() ) ) > 0 )
311  {
312  nHeight = nValue;
313  aLine = FindTokenLine( &rIStm, "static", "_bits" );
314 
315  if ( bStatus )
316  {
317  XBMFormat eFormat = XBM10;
318 
319  if (aLine.indexOf("short") != -1)
320  eFormat = XBM10;
321  else if (aLine.indexOf("char") != -1)
322  eFormat = XBM11;
323  else
324  bStatus = false;
325 
326  //xbms are a minimum of one character per 8 pixels, so if the file isn't
327  //even that long, it's not all there
328  if (rIStm.remainingSize() < (static_cast<sal_uInt64>(nWidth) * nHeight) / 8)
329  bStatus = false;
330 
331  if ( bStatus && nWidth && nHeight )
332  {
333  aBmp1 = Bitmap(Size(nWidth, nHeight), vcl::PixelFormat::N1_BPP);
334  pAcc1 = BitmapScopedWriteAccess(aBmp1);
335 
336  if( pAcc1 )
337  {
338  aWhite = pAcc1->GetBestMatchingColor( COL_WHITE );
339  aBlack = pAcc1->GetBestMatchingColor( COL_BLACK );
340  ParseData( &rIStm, aLine, eFormat );
341  }
342  else
343  bStatus = false;
344  }
345  }
346  }
347  }
348  }
349 
350  if (bStatus && pAcc1)
351  {
352  Bitmap aBlackBmp(Size(pAcc1->Width(), pAcc1->Height()), vcl::PixelFormat::N1_BPP);
353 
354  pAcc1.reset();
355  aBlackBmp.Erase( COL_BLACK );
356  rGraphic = BitmapEx( aBlackBmp, aBmp1 );
357  eReadState = XBMREAD_OK;
358  }
359  else
360  eReadState = XBMREAD_ERROR;
361  }
362  else
363  {
364  rIStm.ResetError();
365  eReadState = XBMREAD_NEED_MORE;
366  }
367 
368  return eReadState;
369 }
370 
371 VCL_DLLPUBLIC bool ImportXBM( SvStream& rStm, Graphic& rGraphic )
372 {
373  std::shared_ptr<GraphicReader> pContext = rGraphic.GetReaderContext();
374  rGraphic.SetReaderContext(nullptr);
375  XBMReader* pXBMReader = dynamic_cast<XBMReader*>( pContext.get() );
376  if (!pXBMReader)
377  {
378  pContext = std::make_shared<XBMReader>( rStm );
379  pXBMReader = static_cast<XBMReader*>( pContext.get() );
380  }
381 
382  bool bRet = true;
383 
384  ReadState eReadState = pXBMReader->ReadXBM( rGraphic );
385 
386  if( eReadState == XBMREAD_ERROR )
387  {
388  bRet = false;
389  }
390  else if( eReadState == XBMREAD_NEED_MORE )
391  rGraphic.SetReaderContext( pContext );
392 
393  return bRet;
394 }
395 
396 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_Int32 nIndex
#define VCL_DLLPUBLIC
Definition: dllapi.h:29
long Long
const wchar_t *typedef int(__stdcall *DllNativeUnregProc)(int
ReadState
Definition: gifread.cxx:44
This template handles BitmapAccess the RAII way.
vcl::ScopedBitmapAccess< BitmapWriteAccess, Bitmap,&Bitmap::AcquireWriteAccess > BitmapScopedWriteAccess
void SetReaderContext(const std::shared_ptr< GraphicReader > &pReader)
Definition: graph.cxx:482
bool ReadLine(OString &rStr, sal_Int32 nMaxBytesToRead=0xFFFE)
XBMFormat
Definition: xbmread.cxx:33
sal_uInt8 * Scanline
Definition: Scanline.hxx:26
VCL_DLLPUBLIC bool ImportXBM(SvStream &rStm, Graphic &rGraphic)
Definition: xbmread.cxx:371
unsigned char sal_uInt8
std::shared_ptr< GraphicReader > & GetReaderContext()
Definition: graph.cxx:477
#define ERRCODE_IO_PENDING
Definition: errcode.hxx:225
sal_uInt16 nPos
sal_Int16 nValue