LibreOffice Module vcl (master)  1
xpmread.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 <bitmapwriteaccess.hxx>
21 #include <vcl/graph.hxx>
22 #include <tools/stream.hxx>
23 #include "rgbtable.hxx"
24 #include "xpmread.hxx"
25 #include <cstring>
26 #include <array>
27 #include <map>
28 
29 #define XPMTEMPBUFSIZE 0x00008000
30 #define XPMSTRINGBUF 0x00008000
31 
32 #define XPMIDENTIFIER 0x00000001 // mnIdentifier includes one of the six phases
33 #define XPMDEFINITION 0x00000002 // the XPM format consists of
34 #define XPMVALUES 0x00000003
35 #define XPMCOLORS 0x00000004
36 #define XPMPIXELS 0x00000005
37 #define XPMEXTENSIONS 0x00000006
38 #define XPMENDEXT 0x00000007
39 
40 #define XPMREMARK 0x00000001 // defines used by mnStatus
41 #define XPMDOUBLE 0x00000002
42 #define XPMSTRING 0x00000004
43 #define XPMFINISHED 0x00000008
44 
45 namespace {
46 
48 {
49  XPMREAD_OK,
50  XPMREAD_ERROR,
51  XPMREAD_NEED_MORE
52 };
53 
54 }
55 
56 class BitmapWriteAccess;
57 class Graphic;
58 
59 namespace {
60 
61 class XPMReader : public GraphicReader
62 {
63 private:
64 
65  SvStream& mrIStm;
66  Bitmap maBmp;
68  Bitmap maMaskBmp;
69  BitmapScopedWriteAccess mpMaskAcc;
70  long const mnLastPos;
71 
74  sal_uLong mnColors;
75  sal_uInt32 mnCpp; // characters per pix
76  bool mbTransparent;
77  bool mbStatus;
78  sal_uLong mnStatus;
79  sal_uLong mnIdentifier;
80  sal_uInt8 mcThisByte;
81  sal_uInt8 mcLastByte;
82  sal_uLong mnTempAvail;
83  sal_uInt8* mpTempBuf;
84  sal_uInt8* mpTempPtr;
85  // each key is ( mnCpp )Byte(s)-> ASCII entry assigned to the colour
86  // each colordata is
87  // 1 Byte -> 0xFF if colour is transparent
88  // 3 Bytes -> RGB value of the colour
89  typedef std::array<sal_uInt8,4> colordata;
90  typedef std::map<OString, colordata> colormap;
91  colormap maColMap;
92  sal_uLong mnStringSize;
93  sal_uInt8* mpStringBuf;
94  sal_uLong mnParaSize;
95  sal_uInt8* mpPara;
96 
97  bool ImplGetString();
98  bool ImplGetColor();
99  bool ImplGetScanLine( sal_uLong );
100  bool ImplGetColSub(colordata &rDest);
101  bool ImplGetColKey( sal_uInt8 );
102  void ImplGetRGBHex(colordata &rDest, sal_uLong);
103  bool ImplGetPara( sal_uLong numb );
104  static bool ImplCompare(sal_uInt8 const *, sal_uInt8 const *, sal_uLong);
105  sal_uLong ImplGetULONG( sal_uLong nPara );
106 
107 public:
108  explicit XPMReader( SvStream& rStm );
109 
110  ReadState ReadXPM( Graphic& rGraphic );
111 };
112 
113 }
114 
115 XPMReader::XPMReader(SvStream& rStm)
116  : mrIStm(rStm)
117  , mnLastPos(rStm.Tell())
118  , mnWidth(0)
119  , mnHeight(0)
120  , mnColors(0)
121  , mnCpp(0)
122  , mbTransparent(false)
123  , mbStatus(true)
124  , mnStatus( 0 )
125  , mnIdentifier(XPMIDENTIFIER)
126  , mcThisByte(0)
127  , mcLastByte(0)
128  , mnTempAvail(0)
129  , mpTempBuf(nullptr)
130  , mpTempPtr(nullptr)
131  , mnStringSize(0)
132  , mpStringBuf(nullptr)
133  , mnParaSize(0)
134  , mpPara(nullptr)
135 {
136 }
137 
138 ReadState XPMReader::ReadXPM( Graphic& rGraphic )
139 {
140  ReadState eReadState;
141  sal_uInt8 cDummy;
142 
143  // check if we can real ALL
144  mrIStm.Seek( STREAM_SEEK_TO_END );
145  mrIStm.ReadUChar( cDummy );
146 
147  // if we could not read all
148  // return and wait for new data
149  if ( mrIStm.GetError() != ERRCODE_IO_PENDING )
150  {
151  mrIStm.Seek( mnLastPos );
152  mbStatus = true;
153 
154  if ( mbStatus )
155  {
156  mpStringBuf = new sal_uInt8 [ XPMSTRINGBUF ];
157  mpTempBuf = new sal_uInt8 [ XPMTEMPBUFSIZE ];
158 
159  mbStatus = ImplGetString();
160  if ( mbStatus )
161  {
162  mnIdentifier = XPMVALUES; // fetch Bitmap information
163  mnWidth = ImplGetULONG( 0 );
164  mnHeight = ImplGetULONG( 1 );
165  mnColors = ImplGetULONG( 2 );
166  mnCpp = ImplGetULONG( 3 );
167  }
168  if ( mnColors > ( SAL_MAX_UINT32 / ( 4 + mnCpp ) ) )
169  mbStatus = false;
170  if ( ( mnWidth * mnCpp ) >= XPMSTRINGBUF )
171  mbStatus = false;
172  //xpms are a minimum of one character (one byte) per pixel, so if the file isn't
173  //even that long, it's not all there
174  if (mrIStm.remainingSize() + mnTempAvail < static_cast<sal_uInt64>(mnWidth) * mnHeight)
175  mbStatus = false;
176  if ( mbStatus && mnWidth && mnHeight && mnColors && mnCpp )
177  {
178  mnIdentifier = XPMCOLORS;
179 
180  for (sal_uLong i = 0; i < mnColors; ++i)
181  {
182  if (!ImplGetColor())
183  {
184  mbStatus = false;
185  break;
186  }
187  }
188 
189  if ( mbStatus )
190  {
191  // create a 24bit graphic when more as 256 colours present
192  sal_uInt16 nBits = 1;
193  if ( mnColors > 256 )
194  nBits = 24;
195  else if ( mnColors > 16 )
196  nBits = 8;
197  else if ( mnColors > 2 )
198  nBits = 4;
199  else
200  nBits = 1;
201 
202  maBmp = Bitmap( Size( mnWidth, mnHeight ), nBits );
203  mpAcc = BitmapScopedWriteAccess(maBmp);
204 
205  // mbTransparent is TRUE if at least one colour is transparent
206  if ( mbTransparent )
207  {
208  maMaskBmp = Bitmap( Size( mnWidth, mnHeight ), 1 );
209  mpMaskAcc = BitmapScopedWriteAccess(maMaskBmp);
210  if ( !mpMaskAcc )
211  mbStatus = false;
212  }
213  if( mpAcc && mbStatus )
214  {
215  if (mnColors <= 256) // palette is only needed by using less than 257
216  { // colors
217  sal_uInt8 i = 0;
218  for (auto& elem : maColMap)
219  {
220  mpAcc->SetPaletteColor(i, Color(elem.second[1], elem.second[2], elem.second[3]));
221  //reuse map entry, overwrite color with palette index
222  elem.second[1] = i;
223  i++;
224  }
225  }
226 
227  // now we get the bitmap data
228  mnIdentifier = XPMPIXELS;
229  for (sal_uLong i = 0; i < mnHeight; ++i)
230  {
231  if ( !ImplGetScanLine( i ) )
232  {
233  mbStatus = false;
234  break;
235  }
236  }
237  mnIdentifier = XPMEXTENSIONS;
238  }
239  }
240  }
241 
242  delete[] mpStringBuf;
243  delete[] mpTempBuf;
244 
245  }
246  if( mbStatus )
247  {
248  mpAcc.reset();
249  if ( mpMaskAcc )
250  {
251  mpMaskAcc.reset();
252  rGraphic = Graphic( BitmapEx( maBmp, maMaskBmp ) );
253  }
254  else
255  {
256  rGraphic = maBmp;
257  }
258  eReadState = XPMREAD_OK;
259  }
260  else
261  {
262  mpMaskAcc.reset();
263  mpAcc.reset();
264 
265  eReadState = XPMREAD_ERROR;
266  }
267  }
268  else
269  {
270  mrIStm.ResetError();
271  eReadState = XPMREAD_NEED_MORE;
272  }
273  return eReadState;
274 }
275 
276 // ImplGetColor returns various colour values,
277 // returns TRUE if various colours could be assigned
278 bool XPMReader::ImplGetColor()
279 {
280  sal_uInt8* pString = mpStringBuf;
281  if (!ImplGetString())
282  return false;
283 
284  if (mnStringSize < mnCpp)
285  return false;
286 
287  OString aKey(reinterpret_cast<char*>(pString), mnCpp);
288  colordata aValue;
289  bool bStatus = ImplGetColSub(aValue);
290  if (bStatus)
291  {
292  maColMap[aKey] = aValue;
293  }
294  return bStatus;
295 }
296 
297 // ImpGetScanLine reads the string mpBufSize and writes the pixel in the
298 // Bitmap. Parameter nY is the horizontal position.
299 bool XPMReader::ImplGetScanLine( sal_uLong nY )
300 {
301  bool bStatus = ImplGetString();
302  sal_uInt8* pString = mpStringBuf;
303  BitmapColor aWhite;
304  BitmapColor aBlack;
305 
306  if ( bStatus )
307  {
308  if ( mpMaskAcc )
309  {
310  aWhite = mpMaskAcc->GetBestMatchingColor( COL_WHITE );
311  aBlack = mpMaskAcc->GetBestMatchingColor( COL_BLACK );
312  }
313  if ( mnStringSize != ( mnWidth * mnCpp ))
314  bStatus = false;
315  else
316  {
317  Scanline pScanline = mpAcc->GetScanline(nY);
318  Scanline pMaskScanline = mpMaskAcc ? mpMaskAcc->GetScanline(nY) : nullptr;
319  for (sal_uLong i = 0; i < mnWidth; ++i)
320  {
321  OString aKey(reinterpret_cast<char*>(pString), mnCpp);
322  auto it = maColMap.find(aKey);
323  if (it != maColMap.end())
324  {
325  if (mnColors > 256)
326  mpAcc->SetPixelOnData(pScanline, i, Color(it->second[1], it->second[2], it->second[3]));
327  else
328  mpAcc->SetPixelOnData(pScanline, i, BitmapColor(it->second[1]));
329  if (pMaskScanline)
330  mpMaskAcc->SetPixelOnData(pMaskScanline, i, it->second[0] ? aWhite : aBlack);
331  }
332  pString += mnCpp;
333  }
334  }
335  }
336  return bStatus;
337 }
338 
339 // tries to determine a colour value from mpStringBuf
340 // if a colour was found the RGB value is written a pDest[1]..pDest[2]
341 // pDest[0] contains 0xFF if the colour is transparent otherwise 0
342 
343 bool XPMReader::ImplGetColSub(colordata &rDest)
344 {
345  unsigned char cTransparent[] = "None";
346 
347  bool bColStatus = false;
348 
349  if ( ImplGetColKey( 'c' ) || ImplGetColKey( 'm' ) || ImplGetColKey( 'g' ) )
350  {
351  // hexentry for RGB or HSV color ?
352  if (*mpPara == '#')
353  {
354  rDest[0] = 0;
355  bColStatus = true;
356  switch ( mnParaSize )
357  {
358  case 25 :
359  ImplGetRGBHex(rDest, 6);
360  break;
361  case 13 :
362  ImplGetRGBHex(rDest, 2);
363  break;
364  case 7 :
365  ImplGetRGBHex(rDest, 0);
366  break;
367  default:
368  bColStatus = false;
369  break;
370  }
371  }
372  // maybe pixel is transparent
373  else if ( ImplCompare( &cTransparent[0], mpPara, 4 ))
374  {
375  rDest[0] = 0xff;
376  bColStatus = true;
377  mbTransparent = true;
378  }
379  // last we will try to get the colorname
380  else if ( mnParaSize > 2 ) // name must enlarge the minimum size
381  {
382  sal_uLong i = 0;
383  while ( true )
384  {
385  if ( pRGBTable[ i ].name == nullptr )
386  break;
387  if ( std::strlen(pRGBTable[i].name) > mnParaSize &&
388  pRGBTable[ i ].name[ mnParaSize ] == 0 )
389  {
390  if ( ImplCompare ( reinterpret_cast<unsigned char const *>(pRGBTable[ i ].name),
391  mpPara, mnParaSize ) )
392  {
393  bColStatus = true;
394  rDest[0] = 0;
395  rDest[1] = pRGBTable[i].red;
396  rDest[2] = pRGBTable[i].green;
397  rDest[3] = pRGBTable[i].blue;
398  break;
399  }
400  }
401  i++;
402  }
403  }
404  }
405  return bColStatus;
406 }
407 
408 // ImplGetColKey searches string mpStringBuf for a parameter 'nKey'
409 // and returns a boolean. (if TRUE mpPara and mnParaSize will be set)
410 
411 bool XPMReader::ImplGetColKey( sal_uInt8 nKey )
412 {
413  sal_uInt8 nTemp, nPrev = ' ';
414 
415  if (mnStringSize < mnCpp + 1)
416  return false;
417 
418  mpPara = mpStringBuf + mnCpp + 1;
419  mnParaSize = 0;
420 
421  while ( *mpPara != 0 )
422  {
423  if ( *mpPara == nKey )
424  {
425  nTemp = *( mpPara + 1 );
426  if ( nTemp == ' ' || nTemp == 0x09 )
427  {
428  if ( nPrev == ' ' || nPrev == 0x09 )
429  break;
430  }
431  }
432  nPrev = *mpPara;
433  mpPara++;
434  }
435  if ( *mpPara )
436  {
437  mpPara++;
438  while ( (*mpPara == ' ') || (*mpPara == 0x09) )
439  {
440  mpPara++;
441  }
442  if ( *mpPara != 0 )
443  {
444  while ( *(mpPara+mnParaSize) != ' ' && *(mpPara+mnParaSize) != 0x09 &&
445  *(mpPara+mnParaSize) != 0 )
446  {
447  mnParaSize++;
448  }
449  }
450  }
451  return mnParaSize != 0;
452 }
453 
454 // ImplGetRGBHex translates the ASCII-Hexadecimalvalue belonging to mpPara
455 // in a RGB value and writes this to rDest
456 // below formats should be contained in mpPara:
457 // if nAdd = 0 : '#12ab12' -> RGB = 0x12, 0xab, 0x12
458 // 2 : '#1234abcd1234' " " " "
459 // 6 : '#12345678abcdefab12345678' " " " "
460 
461 void XPMReader::ImplGetRGBHex(colordata &rDest, sal_uLong nAdd)
462 {
463  sal_uInt8* pPtr = mpPara+1;
464 
465  for (sal_uLong i = 1; i < 4; ++i)
466  {
467  sal_uInt8 nHex = (*pPtr++) - '0';
468  if ( nHex > 9 )
469  nHex = ((nHex - 'A' + '0') & 7) + 10;
470 
471  sal_uInt8 nTemp = (*pPtr++) - '0';
472  if ( nTemp > 9 )
473  nTemp = ((nTemp - 'A' + '0') & 7) + 10;
474  nHex = ( nHex << 4 ) + nTemp;
475 
476  pPtr += nAdd;
477  rDest[i] = nHex;
478  }
479 }
480 
481 // ImplGetUlong returns the value of a up to 6-digit long ASCII-decimal number.
482 
483 sal_uLong XPMReader::ImplGetULONG( sal_uLong nPara )
484 {
485  if ( ImplGetPara ( nPara ) )
486  {
487  sal_uLong nRetValue = 0;
488  sal_uInt8* pPtr = mpPara;
489 
490  if ( ( mnParaSize > 6 ) || ( mnParaSize == 0 ) ) return 0;
491  for ( sal_uLong i = 0; i < mnParaSize; i++ )
492  {
493  sal_uInt8 j = (*pPtr++) - 48;
494  if ( j > 9 ) return 0; // ascii is invalid
495  nRetValue*=10;
496  nRetValue+=j;
497  }
498  return nRetValue;
499  }
500  else return 0;
501 }
502 
503 bool XPMReader::ImplCompare(sal_uInt8 const * pSource, sal_uInt8 const * pDest, sal_uLong nSize)
504 {
505  for (sal_uLong i = 0; i < nSize; ++i)
506  {
507  if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
508  {
509  return false;
510  }
511  }
512  return true;
513 }
514 
515 // ImplGetPara tries to retrieve nNumb (0...x) parameters from mpStringBuf.
516 // Parameters are separated by spaces or tabs.
517 // If a parameter was found then the return value is TRUE and mpPara + mnParaSize
518 // are set.
519 
520 bool XPMReader::ImplGetPara ( sal_uLong nNumb )
521 {
522  sal_uInt8 nByte;
523  sal_uLong nSize = 0;
524  sal_uInt8* pPtr = mpStringBuf;
525  sal_uLong nCount = 0;
526 
527  if ( ( *pPtr != ' ' ) && ( *pPtr != 0x09 ) )
528  {
529  mpPara = pPtr;
530  mnParaSize = 0;
531  nCount = 0;
532  }
533  else
534  {
535  mpPara = nullptr;
536  nCount = 0xffffffff;
537  }
538 
539  while ( nSize < mnStringSize )
540  {
541  nByte = *pPtr;
542 
543  if ( mpPara )
544  {
545  if ( ( nByte == ' ' ) || ( nByte == 0x09 ) )
546  {
547  if ( nCount == nNumb )
548  break;
549  else
550  mpPara = nullptr;
551  }
552  else
553  mnParaSize++;
554  }
555  else
556  {
557  if ( ( nByte != ' ' ) && ( nByte != 0x09 ) )
558  {
559  mpPara = pPtr;
560  mnParaSize = 1;
561  nCount++;
562  }
563  }
564  nSize++;
565  pPtr++;
566  }
567  return ( ( nCount == nNumb ) && mpPara );
568 }
569 
570 // The next string is read and stored in mpStringBuf (terminated with 0);
571 // mnStringSize contains the size of the string read.
572 // Comments like '//' and '/*...*/' are skipped.
573 
574 bool XPMReader::ImplGetString()
575 {
576  sal_uInt8 const sID[] = "/* XPM */";
577  sal_uInt8* pString = mpStringBuf;
578 
579  mnStringSize = 0;
580  mpStringBuf[0] = 0;
581 
582  while( mbStatus && ( mnStatus != XPMFINISHED ) )
583  {
584  if ( mnTempAvail == 0 )
585  {
586  mnTempAvail = mrIStm.ReadBytes( mpTempBuf, XPMTEMPBUFSIZE );
587  if ( mnTempAvail == 0 )
588  break;
589 
590  mpTempPtr = mpTempBuf;
591 
592  if ( mnIdentifier == XPMIDENTIFIER )
593  {
594  if ( mnTempAvail <= 50 )
595  {
596  mbStatus = false; // file is too short to be a correct XPM format
597  break;
598  }
599  for ( int i = 0; i < 9; i++ ) // searching for "/* XPM */"
600  if ( *mpTempPtr++ != sID[i] )
601  {
602  mbStatus = false;
603  break;
604  }
605  mnTempAvail-=9;
606  mnIdentifier++;
607  }
608  }
609  mcLastByte = mcThisByte;
610  mcThisByte = *mpTempPtr++;
611  mnTempAvail--;
612 
613  if ( mnStatus & XPMDOUBLE )
614  {
615  if ( mcThisByte == 0x0a )
616  mnStatus &=~XPMDOUBLE;
617  continue;
618  }
619  if ( mnStatus & XPMREMARK )
620  {
621  if ( ( mcThisByte == '/' ) && ( mcLastByte == '*' ) )
622  mnStatus &=~XPMREMARK;
623  continue;
624  }
625  if ( mnStatus & XPMSTRING ) // characters in string
626  {
627  if ( mcThisByte == '"' )
628  {
629  mnStatus &=~XPMSTRING; // end of parameter by eol
630  break;
631  }
632  if ( mnStringSize >= ( XPMSTRINGBUF - 1 ) )
633  {
634  mbStatus = false;
635  break;
636  }
637  *pString++ = mcThisByte;
638  pString[0] = 0;
639  mnStringSize++;
640  continue;
641  }
642  else
643  { // characters beside string
644  switch ( mcThisByte )
645  {
646  case '*' :
647  if ( mcLastByte == '/' ) mnStatus |= XPMREMARK;
648  break;
649  case '/' :
650  if ( mcLastByte == '/' ) mnStatus |= XPMDOUBLE;
651  break;
652  case '"' : mnStatus |= XPMSTRING;
653  break;
654  case '{' :
655  if ( mnIdentifier == XPMDEFINITION )
656  mnIdentifier++;
657  break;
658  case '}' :
659  if ( mnIdentifier == XPMENDEXT )
660  mnStatus = XPMFINISHED;
661  break;
662  }
663  }
664  }
665  return mbStatus;
666 }
667 
668 
669 VCL_DLLPUBLIC bool ImportXPM( SvStream& rStm, Graphic& rGraphic )
670 {
671  std::shared_ptr<GraphicReader> pContext = rGraphic.GetContext();
672  rGraphic.SetContext(nullptr);
673  XPMReader* pXPMReader = dynamic_cast<XPMReader*>( pContext.get() );
674  if (!pXPMReader)
675  {
676  pContext = std::make_shared<XPMReader>( rStm );
677  pXPMReader = static_cast<XPMReader*>( pContext.get() );
678  }
679 
680  bool bRet = true;
681 
682  ReadState eReadState = pXPMReader->ReadXPM( rGraphic );
683 
684  if( eReadState == XPMREAD_ERROR )
685  {
686  bRet = false;
687  }
688  else if( eReadState == XPMREAD_NEED_MORE )
689  rGraphic.SetContext( pContext );
690 
691  return bRet;
692 }
693 
694 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
double mnHeight
sal_uInt8 const red
Definition: rgbtable.hxx:28
sal_uInt8 const green
Definition: rgbtable.hxx:29
#define XPMIDENTIFIER
Definition: xpmread.cxx:32
void SetContext(const std::shared_ptr< GraphicReader > &pReader)
Definition: graph.cxx:501
#define XPMENDEXT
Definition: xpmread.cxx:38
#define VCL_DLLPUBLIC
Definition: dllapi.h:29
sal_uIntPtr sal_uLong
#define XPMSTRINGBUF
Definition: xpmread.cxx:30
vcl::ScopedBitmapAccess< BitmapWriteAccess, Bitmap,&Bitmap::AcquireWriteAccess > BitmapScopedWriteAccess
std::shared_ptr< GraphicReader > & GetContext()
Definition: graph.cxx:496
#define XPMDEFINITION
Definition: xpmread.cxx:33
ReadState
Definition: gifread.cxx:43
This template handles BitmapAccess the RAII way.
static const XPMRGBTab pRGBTable[]
Definition: rgbtable.hxx:33
int nCount
VCL_DLLPUBLIC bool ImportXPM(SvStream &rStm, Graphic &rGraphic)
Definition: xpmread.cxx:669
#define XPMEXTENSIONS
Definition: xpmread.cxx:37
sal_uInt8 * Scanline
Definition: Scanline.hxx:25
#define XPMDOUBLE
Definition: xpmread.cxx:41
#define XPMCOLORS
Definition: xpmread.cxx:35
int i
#define XPMFINISHED
Definition: xpmread.cxx:43
#define XPMSTRING
Definition: xpmread.cxx:42
#define XPMTEMPBUFSIZE
Definition: xpmread.cxx:29
#define XPMREMARK
Definition: xpmread.cxx:40
sal_uInt8 const blue
Definition: rgbtable.hxx:30
unsigned char sal_uInt8
double mnWidth
#define XPMVALUES
Definition: xpmread.cxx:34
#define ERRCODE_IO_PENDING
Definition: errcode.hxx:227
#define XPMPIXELS
Definition: xpmread.cxx:36