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