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