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