xref: /AOO41X/main/svtools/source/filter/ixpm/xpmread.cxx (revision c82f28778d59b20a7e6c0f9982d1bc73807a432a)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svtools.hxx"
26 
27 #ifndef _BMPACC_HXX
28 #include <vcl/bmpacc.hxx>
29 #endif
30 #ifndef _GRAPH_HXX
31 #include <vcl/graph.hxx>
32 #endif
33 #include "rgbtable.hxx"
34 #define _XPMPRIVATE
35 #include "xpmread.hxx"
36 
37 // -------------
38 // - XPMReader -
39 // -------------
40 
XPMReader(SvStream & rStm)41 XPMReader::XPMReader( SvStream& rStm ) :
42             mrIStm          ( rStm ),
43             mpAcc           ( NULL ),
44             mpMaskAcc       ( NULL ),
45             mnLastPos       ( rStm.Tell() ),
46             mnWidth         ( 0 ),
47             mnHeight        ( 0 ),
48             mnColors        ( 0 ),
49             mnCpp           ( 0 ),
50             mbTransparent   ( sal_False ),
51             mbStatus        ( sal_True ),
52             mnStatus        ( 0 ),
53             mnIdentifier    ( XPMIDENTIFIER ),
54             mcThisByte      ( 0 ),
55             mnTempAvail     ( 0 ),
56             mpFastColorTable( NULL ),
57             mpColMap        ( NULL )
58 {
59 
60 }
61 
62 // ------------------------------------------------------------------------
63 
~XPMReader()64 XPMReader::~XPMReader()
65 {
66     if( mpAcc )
67         maBmp.ReleaseAccess( mpAcc );
68 }
69 
70 // ------------------------------------------------------------------------
71 
72 #ifdef _MSC_VER
73 #pragma optimize ("",off)
74 #endif
75 
ReadXPM(Graphic & rGraphic)76 ReadState XPMReader::ReadXPM( Graphic& rGraphic )
77 {
78     ReadState   eReadState;
79     sal_uInt8       cDummy;
80 
81     // sehen, ob wir _alles_ lesen koennen
82     mrIStm.Seek( STREAM_SEEK_TO_END );
83     mrIStm >> cDummy;
84 
85     // falls wir nicht alles lesen koennen
86     // kehren wir zurueck und warten auf neue Daten
87     if ( mrIStm.GetError() != ERRCODE_IO_PENDING )
88     {
89         mrIStm.Seek( mnLastPos );
90         mbStatus = sal_True;
91 
92         if ( mbStatus )
93         {
94             mpStringBuf = new sal_uInt8 [ XPMSTRINGBUF ];
95             mpTempBuf = new sal_uInt8 [ XPMTEMPBUFSIZE ];
96 
97             if ( ( mbStatus = ImplGetString() ) == sal_True )
98             {
99                 mnIdentifier = XPMVALUES;           // Bitmap informationen einholen
100                 mnWidth = ImplGetULONG( 0 );
101                 mnHeight = ImplGetULONG( 1 );
102                 mnColors = ImplGetULONG( 2 );
103                 mnCpp = ImplGetULONG( 3 );
104             }
105             if ( mnColors > ( SAL_MAX_UINT32 / ( 4 + mnCpp ) ) )
106                 mbStatus = sal_False;
107             if ( ( mnWidth * mnCpp ) >= XPMSTRINGBUF )
108                 mbStatus = sal_False;
109             if ( mbStatus && mnWidth && mnHeight && mnColors && mnCpp )
110             {
111                 mnIdentifier = XPMCOLORS;
112 
113                 // mpColMap beinhaltet fuer jede vorhandene
114                 // Farbe:   ( mnCpp )Byte(s)-> ASCII Eintrag der der Farbe zugeordnet ist
115                 //              1    Byte   -> 0xff wenn Farbe transparent ist
116                 //              3    Bytes  -> RGB Wert der Farbe
117                 mpColMap = new sal_uInt8[ mnColors * ( 4 + mnCpp ) ];
118                 if ( mpColMap )
119                 {
120                     for ( sal_uLong i = 0; i < mnColors; i++ )
121                     {
122                         if ( ImplGetColor( i ) == sal_False )
123                         {
124                             mbStatus = sal_False;
125                             break;
126                         }
127                     }
128                 }
129                 else
130                     mbStatus = sal_False;
131 
132                 if ( mbStatus )
133                 {
134                     // bei mehr als 256 Farben wird eine 24 Bit Grafik erstellt
135                     sal_uInt16  nBits = 1;
136                     if ( mnColors > 256 )
137                         nBits = 24;
138                     else if ( mnColors > 16 )
139                         nBits = 8;
140                     else if ( mnColors > 2 )
141                         nBits = 4;
142                     else
143                         nBits = 1;
144 
145                     maBmp = Bitmap( Size( mnWidth, mnHeight ), nBits );
146                     mpAcc = maBmp.AcquireWriteAccess();
147 
148                     // mbTransparent ist sal_True wenn mindestens eine Farbe Transparent ist
149                     if ( mbTransparent )
150                     {
151                         maMaskBmp = Bitmap( Size( mnWidth, mnHeight ), 1 );
152                         if ( ( mpMaskAcc = maMaskBmp.AcquireWriteAccess() ) == NULL )
153                             mbStatus =  sal_False;
154                     }
155                     if( mpAcc && mbStatus )
156                     {
157                         sal_uLong   i;
158                         if ( mnColors <=256 )   // palette is only needed by using less than 257
159                         {                       // colors
160 
161                             sal_uInt8*  pPtr = &mpColMap[mnCpp];
162 
163                             for ( i = 0; i < mnColors; i++ )
164                             {
165                                 mpAcc->SetPaletteColor( (sal_uInt8)i, Color( pPtr[1], pPtr[2], pPtr[3] ) );
166                                 pPtr += ( mnCpp + 4 );
167                             }
168                             // using 2 charakters per pixel and less than 257 Colors we speed up
169                             if ( mnCpp == 2 )   // by using a 64kb indexing table
170                             {
171                                 mpFastColorTable = new sal_uInt8[ 256 * 256 ];
172                                 for ( pPtr = mpColMap, i = 0; i < mnColors; i++, pPtr += mnCpp + 4 )
173                                 {
174                                     sal_uLong   j =  pPtr[ 0 ] << 8;
175                                             j += pPtr[ 1 ];
176                                     mpFastColorTable[ j ] = (sal_uInt8)i;
177                                 }
178                             }
179                         }
180                         // now we get the bitmap data
181                         mnIdentifier = XPMPIXELS;
182                         for ( i = 0; i < mnHeight; i++ )
183                         {
184                             if ( ImplGetScanLine( i ) == sal_False )
185                             {
186                                 mbStatus = sal_False;
187                                 break;
188                             }
189                         }
190                         mnIdentifier = XPMEXTENSIONS;
191                     }
192                 }
193             }
194 
195             delete[] mpFastColorTable;
196             delete[] mpColMap;
197             delete[] mpStringBuf;
198             delete[] mpTempBuf;
199 
200         }
201         if( mbStatus )
202         {
203             if ( mpMaskAcc )
204             {
205                 maMaskBmp.ReleaseAccess ( mpMaskAcc), mpMaskAcc = NULL;
206                 maBmp.ReleaseAccess( mpAcc ), mpAcc = NULL;
207                 rGraphic = Graphic( BitmapEx( maBmp, maMaskBmp ) );
208             }
209             else
210             {
211                 maBmp.ReleaseAccess( mpAcc ), mpAcc = NULL;
212                 rGraphic = maBmp;
213             }
214             eReadState = XPMREAD_OK;
215         }
216         else
217         {
218             if ( mpMaskAcc ) maMaskBmp.ReleaseAccess ( mpMaskAcc), mpMaskAcc = NULL;
219             if ( mpAcc ) maBmp.ReleaseAccess( mpAcc ), mpAcc = NULL;
220             eReadState = XPMREAD_ERROR;
221         }
222     }
223     else
224     {
225         mrIStm.ResetError();
226         eReadState = XPMREAD_NEED_MORE;
227     }
228     return eReadState;
229 }
230 
231 #ifdef _MSC_VER
232 #pragma optimize ("",on)
233 #endif
234 
235 // ------------------------------------------------------------------------
236 // ImplGetColor ermittelt saemtliche Farbwerte,
237 // die Rueckgabe ist sal_True wenn saemtliche Farben zugeordnet werden konnten
238 
ImplGetColor(sal_uLong nNumb)239 sal_Bool XPMReader::ImplGetColor( sal_uLong nNumb )
240 {
241     sal_uInt8*  pString = mpStringBuf;
242     sal_uInt8*  pPtr =  ( mpColMap + nNumb * ( 4 + mnCpp ) );
243     sal_Bool    bStatus = ImplGetString();
244 
245     if ( bStatus )
246     {
247         for ( sal_uLong i = 0; i < mnCpp; i++ )
248             *pPtr++ = *pString++;
249         bStatus = ImplGetColSub ( pPtr );
250     }
251     return bStatus;
252 }
253 
254 // ------------------------------------------------------------------------
255 // ImpGetScanLine liest den String mpBufSize aus und schreibt die Pixel in die
256 // Bitmap. Der Parameter nY gibt die horizontale Position an.
257 
ImplGetScanLine(sal_uLong nY)258 sal_Bool XPMReader::ImplGetScanLine( sal_uLong nY )
259 {
260     sal_Bool    bStatus = ImplGetString();
261     sal_uInt8*  pString = mpStringBuf;
262     sal_uInt8*  pColor;
263     BitmapColor     aWhite;
264     BitmapColor     aBlack;
265 
266     if ( bStatus )
267     {
268         if ( mpMaskAcc )
269         {
270             aWhite = mpMaskAcc->GetBestMatchingColor( Color( COL_WHITE ) );
271             aBlack = mpMaskAcc->GetBestMatchingColor( Color( COL_BLACK ) );
272         }
273         if ( mnStringSize != ( mnWidth * mnCpp ))
274             bStatus = sal_False;
275         else
276         {
277             sal_uLong i, j;
278             if ( mpFastColorTable )
279             {
280                 for ( i = 0; i < mnWidth; i++ )
281                 {
282                     j = (*pString++) << 8;
283                     j += *pString++;
284                     sal_uInt8 k = (sal_uInt8)mpFastColorTable[ j ];
285                     mpAcc->SetPixel( nY, i, BitmapColor( (sal_uInt8)k ) );
286 
287                     if ( mpMaskAcc )
288                         mpMaskAcc->SetPixel( nY, i,
289                             ( mpColMap[ k * (mnCpp + 4) + mnCpp] ) ? aWhite : aBlack );
290                 }
291             }
292             else for ( i = 0; i < mnWidth; i++ )
293             {
294                 pColor = mpColMap;
295                 for ( j = 0; j < mnColors; j++ )
296                 {
297                     if ( ImplCompare( pString, pColor, mnCpp, XPMCASESENSITIVE ) == sal_True )
298                     {
299                         if ( mnColors > 256 )
300                             mpAcc->SetPixel( nY, i, Color ( pColor[3], pColor[4], pColor[5] ) );
301                         else
302                             mpAcc->SetPixel( nY, i, BitmapColor( (sal_uInt8) j ) );
303 
304                         if ( mpMaskAcc )
305                             mpMaskAcc->SetPixel( nY, i, (
306                                 pColor[ mnCpp ] ) ? aWhite : aBlack );
307 
308                         break;
309                     }
310                     pColor += ( mnCpp + 4 );
311                 }
312                 pString += mnCpp;
313             }
314 
315         }
316     }
317     return bStatus;
318 }
319 
320 // ------------------------------------------------------------------------
321 // versucht aus mpStringBuf einen Farbwert zu uebermitteln
322 // wurde eine Farbe gefunden wird an pDest[1]..pDest[2] der RGB wert geschrieben
323 // pDest[0] enthaelt 0xff wenn die Farbe transparent ist sonst 0
324 
ImplGetColSub(sal_uInt8 * pDest)325 sal_Bool XPMReader::ImplGetColSub( sal_uInt8* pDest )
326 {
327     unsigned char cTransparent[] = "None";
328 
329     sal_Bool bColStatus = sal_False;
330 
331     if ( ImplGetColKey( 'c' ) || ImplGetColKey( 'm' ) || ImplGetColKey( 'g' ) )
332     {
333         // hexentry for RGB or HSV color ?
334         if ( *mpPara == '#' )
335         {
336                 *pDest++ = 0;
337                 bColStatus = sal_True;
338                 switch ( mnParaSize )
339                 {
340                     case 25 :
341                         ImplGetRGBHex ( pDest, 6 );
342                         break;
343                     case 13 :
344                         ImplGetRGBHex ( pDest, 2 );
345                         break;
346                     case  7 :
347                         ImplGetRGBHex ( pDest, 0 );
348                         break;
349                     default:
350                         bColStatus = sal_False;
351                         break;
352                 }
353         }
354         // maybe pixel is transparent
355         else if ( ImplCompare( &cTransparent[0], mpPara, 4 ))
356         {
357             *pDest++ = 0xff;
358             bColStatus = sal_True;
359             mbTransparent = sal_True;
360         }
361         // last we will try to get the colorname
362         else if ( mnParaSize > 2 )  // name must enlarge the minimum size
363         {
364             sal_uLong i = 0;
365             while ( sal_True )
366             {
367                 if ( pRGBTable[ i ].name == NULL )
368                     break;
369                 if ( pRGBTable[ i ].name[ mnParaSize ] == 0 )
370                 {
371                     if ( ImplCompare ( (unsigned char*)pRGBTable[ i ].name,
372                             mpPara, mnParaSize, XPMCASENONSENSITIVE ) )
373                     {
374                         bColStatus = sal_True;
375                         *pDest++ = 0;
376                         *pDest++ = pRGBTable[ i ].red;
377                         *pDest++ = pRGBTable[ i ].green;
378                         *pDest++ = pRGBTable[ i ].blue;
379                     }
380                 }
381                 i++;
382             }
383         }
384     }
385     return bColStatus;
386 }
387 
388 // ------------------------------------------------------------------------
389 // ImplGetColKey durchsuch den String mpStringBuf nach einem Parameter 'nKey'
390 // und gibt einen sal_Bool zurueck. ( wenn sal_True werden mpPara und mnParaSize gesetzt )
391 
ImplGetColKey(sal_uInt8 nKey)392 sal_Bool XPMReader::ImplGetColKey( sal_uInt8 nKey )
393 {
394     sal_uInt8 nTemp, nPrev = ' ';
395 
396     mpPara = mpStringBuf + mnCpp + 1;
397     mnParaSize = 0;
398 
399     while ( *mpPara != 0 )
400     {
401         if ( *mpPara == nKey )
402         {
403             nTemp = *( mpPara + 1 );
404             if ( nTemp == ' ' || nTemp == 0x09 )
405             {
406                 if ( nPrev == ' ' || nPrev == 0x09 )
407                     break;
408             }
409         }
410         nPrev = *mpPara;
411         mpPara++;
412     }
413     if ( *mpPara )
414     {
415         mpPara++;
416         while ( (*mpPara == ' ') || (*mpPara == 0x09) )
417         {
418             mpPara++;
419         }
420         if ( *mpPara != 0 )
421         {
422             while ( *(mpPara+mnParaSize) != ' ' && *(mpPara+mnParaSize) != 0x09 &&
423                         *(mpPara+mnParaSize) != 0 )
424             {
425                 mnParaSize++;
426             }
427         }
428     }
429     return ( mnParaSize ) ? sal_True : sal_False;
430 }
431 
432 // ------------------------------------------------------------------------
433 // ImplGetRGBHex uebersetzt den ASCII-Hexadezimalwert der sich bei mpPara befindet
434 // in einen RGB wert und schreibt diesen nach pDest
435 // folgende Formate muessen sich bei mpPara befinden:
436 // wenn nAdd = 0 : '#12ab12'                    -> RGB = 0x12, 0xab, 0x12
437 //             2 : '#1234abcd1234'                  "      "     "     "
438 //             6 : '#12345678abcdefab12345678'      "      "     "     "
439 
440 
ImplGetRGBHex(sal_uInt8 * pDest,sal_uLong nAdd)441 void XPMReader::ImplGetRGBHex( sal_uInt8* pDest,sal_uLong  nAdd )
442 {
443     sal_uInt8*  pPtr = mpPara+1;
444     sal_uInt8   nHex, nTemp;
445 
446     for ( sal_uLong i = 0; i < 3; i++ )
447     {
448         nHex = (*pPtr++) - '0';
449         if ( nHex > 9 )
450             nHex = ((nHex - 'A' + '0') & 7) + 10;
451 
452         nTemp = (*pPtr++) - '0';
453         if ( nTemp > 9 )
454             nTemp = ((nTemp - 'A' + '0') & 7) + 10;
455         nHex = ( nHex << 4 ) + nTemp;
456 
457         pPtr += nAdd;
458         *pDest++ = (sal_uInt8)nHex;
459     }
460 }
461 
462 // ------------------------------------------------------------------------
463 // ImplGetUlong gibt den wert einer bis zu 6stelligen ASCII-Dezimalzahl zurueck.
464 
ImplGetULONG(sal_uLong nPara)465 sal_uLong XPMReader::ImplGetULONG( sal_uLong nPara )
466 {
467     if ( ImplGetPara ( nPara ) )
468     {
469         sal_uLong nRetValue = 0;
470         sal_uInt8* pPtr = mpPara;
471 
472         if ( ( mnParaSize > 6 ) || ( mnParaSize == 0 ) ) return 0;
473         for ( sal_uLong i = 0; i < mnParaSize; i++ )
474         {
475             sal_uInt8 j = (*pPtr++) - 48;
476             if ( j > 9 ) return 0;              // ascii is invalid
477             nRetValue*=10;
478             nRetValue+=j;
479         }
480         return nRetValue;
481     }
482     else return 0;
483 }
484 
485 // ------------------------------------------------------------------------
486 
ImplCompare(sal_uInt8 * pSource,sal_uInt8 * pDest,sal_uLong nSize,sal_uLong nMode)487 sal_Bool XPMReader::ImplCompare( sal_uInt8* pSource, sal_uInt8* pDest, sal_uLong nSize, sal_uLong nMode )
488 {
489     sal_Bool bRet = sal_True;
490 
491     if ( nMode == XPMCASENONSENSITIVE )
492     {
493         for ( sal_uLong i = 0; i < nSize; i++ )
494         {
495             if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
496             {
497                 bRet = sal_False;
498                 break;
499             }
500         }
501     }
502     else
503     {
504         for ( sal_uLong i = 0; i < nSize; i++ )
505         {
506             if ( pSource[i] != pDest[i] )
507             {
508                 bRet = sal_False;
509                 break;
510             }
511         }
512     }
513     return bRet;
514 }
515 
516 // ------------------------------------------------------------------------
517 // ImplGetPara versucht den nNumb  ( 0...x ) Parameter aus mpStringBuf zu ermitteln.
518 // Ein Parameter ist durch Spaces oder Tabs von den anderen getrennt.
519 // Konnte der Parameter gefunden werden ist der Rueckgabewert sal_True und mpPara + mnParaSize
520 // werden gesetzt.
521 
ImplGetPara(sal_uLong nNumb)522 sal_Bool XPMReader::ImplGetPara ( sal_uLong nNumb )
523 {
524     sal_uInt8   nByte;
525     sal_uLong   pSize = 0;
526     sal_uInt8*  pPtr = mpStringBuf;
527     sal_uLong   nCount = 0;
528 
529     if ( ( *pPtr != ' ' ) && ( *pPtr != 0x09 ) )
530     {
531         mpPara = pPtr;
532         mnParaSize = 0;
533         nCount = 0;
534     }
535     else
536     {
537         mpPara = NULL;
538         nCount = 0xffffffff;
539     }
540 
541     while ( pSize < mnStringSize )
542     {
543         nByte = *pPtr;
544 
545         if ( mpPara )
546         {
547             if ( ( nByte == ' ' ) || ( nByte == 0x09 ) )
548             {
549                 if ( nCount == nNumb )
550                     break;
551                 else
552                     mpPara = NULL;
553             }
554             else
555                 mnParaSize++;
556         }
557         else
558         {
559             if ( ( nByte != ' ' ) && ( nByte != 0x09 ) )
560             {
561                 mpPara = pPtr;
562                 mnParaSize = 1;
563                 nCount++;
564             }
565         }
566         pSize++;
567         pPtr++;
568     }
569     return ( ( nCount == nNumb ) && ( mpPara ) ) ? sal_True : sal_False;
570 }
571 
572 // ------------------------------------------------------------------------
573 // Der naechste String wird ausgelesen und in mpStringBuf (mit 0 abgeschlossen) abgelegt;
574 // mnStringSize enthaelt die Groesse des gelesenen Strings.
575 // Bemerkungen wie '//' und '/*.....*/' werden uebersprungen.
576 
ImplGetString(void)577 sal_Bool XPMReader::ImplGetString( void )
578 {
579     sal_uInt8       sID[] = "/* XPM */";
580     sal_uInt8*      pString = mpStringBuf;
581 
582     mnStringSize = 0;
583     mpStringBuf[0] = 0;
584 
585     while( mbStatus && ( mnStatus != XPMFINISHED ) )
586     {
587         if ( mnTempAvail == 0 )
588         {
589             mnTempAvail = mrIStm.Read( mpTempBuf, XPMTEMPBUFSIZE );
590             if ( mnTempAvail == 0 )
591                 break;
592 
593             mpTempPtr = mpTempBuf;
594 
595             if ( mnIdentifier == XPMIDENTIFIER )
596             {
597                 if ( mnTempAvail <= 50 )
598                 {
599                     mbStatus = sal_False;   // file is too short to be a correct XPM format
600                     break;
601                 }
602                 for ( int i = 0; i < 9; i++ )   // searching for "/* XPM */"
603                     if ( *mpTempPtr++ != sID[i] )
604                     {
605                         mbStatus = sal_False;
606                         break;
607                     }
608                 mnTempAvail-=9;
609                 mnIdentifier++;
610             }
611         }
612         mcLastByte = mcThisByte;
613         mcThisByte = *mpTempPtr++;
614         mnTempAvail--;
615 
616         if ( mnStatus & XPMDOUBLE )
617         {
618             if ( mcThisByte == 0x0a )
619                 mnStatus &=~XPMDOUBLE;
620             continue;
621         }
622         if ( mnStatus & XPMREMARK )
623         {
624             if ( ( mcThisByte == '/' )  && ( mcLastByte == '*' ) )
625                 mnStatus &=~XPMREMARK;
626             continue;
627         }
628         if ( mnStatus & XPMSTRING )             // characters in string
629         {
630             if ( mcThisByte == '"' )
631             {
632                 mnStatus &=~XPMSTRING;          // end of parameter by eol
633                 break;
634             }
635             if ( mnStringSize >= ( XPMSTRINGBUF - 1 ) )
636             {
637                 mbStatus = sal_False;
638                 break;
639             }
640             *pString++ = mcThisByte;
641             pString[0] = 0;
642             mnStringSize++;
643             continue;
644         }
645         else
646         {                                           // characters beside string
647             switch ( mcThisByte )
648             {
649                 case '*' :
650                     if ( mcLastByte == '/' ) mnStatus |= XPMREMARK;
651                     break;
652                 case '/' :
653                     if ( mcLastByte == '/' ) mnStatus |= XPMDOUBLE;
654                     break;
655                 case '"' : mnStatus |= XPMSTRING;
656                     break;
657                 case '{' :
658                     if ( mnIdentifier == XPMDEFINITION )
659                         mnIdentifier++;
660                     break;
661                 case '}' :
662                     if ( mnIdentifier == XPMENDEXT )
663                         mnStatus = XPMFINISHED;
664                     break;
665             }
666         }
667     }
668     return mbStatus;
669 }
670 
671 // -------------
672 // - ImportXPM -
673 // -------------
674 
ImportXPM(SvStream & rStm,Graphic & rGraphic)675 sal_Bool ImportXPM( SvStream& rStm, Graphic& rGraphic )
676 {
677     XPMReader*  pXPMReader = (XPMReader*) rGraphic.GetContext();
678     ReadState   eReadState;
679     sal_Bool        bRet = sal_True;
680 
681     if( !pXPMReader )
682         pXPMReader = new XPMReader( rStm );
683 
684     rGraphic.SetContext( NULL );
685     eReadState = pXPMReader->ReadXPM( rGraphic );
686 
687     if( eReadState == XPMREAD_ERROR )
688     {
689         bRet = sal_False;
690         delete pXPMReader;
691     }
692     else if( eReadState == XPMREAD_OK )
693         delete pXPMReader;
694     else
695         rGraphic.SetContext( pXPMReader );
696 
697     return bRet;
698 }
699