merge the formfield patch from ooo-build
[ooovba.git] / svtools / source / filter.vcl / ixpm / xpmread.cxx
blob2e837129da29b2c56b56c738ff4c6f2182d9c072
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: xpmread.cxx,v $
10 * $Revision: 1.11 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svtools.hxx"
34 #ifndef _BMPACC_HXX
35 #include <vcl/bmpacc.hxx>
36 #endif
37 #ifndef _GRAPH_HXX
38 #include <vcl/graph.hxx>
39 #endif
40 #include "rgbtable.hxx"
41 #define _XPMPRIVATE
42 #include "xpmread.hxx"
44 // -------------
45 // - XPMReader -
46 // -------------
48 XPMReader::XPMReader( SvStream& rStm ) :
49 mrIStm ( rStm ),
50 mpAcc ( NULL ),
51 mpMaskAcc ( NULL ),
52 mnLastPos ( rStm.Tell() ),
53 mnWidth ( 0 ),
54 mnHeight ( 0 ),
55 mnColors ( 0 ),
56 mnCpp ( 0 ),
57 mbTransparent ( FALSE ),
58 mbStatus ( TRUE ),
59 mnStatus ( 0 ),
60 mnIdentifier ( XPMIDENTIFIER ),
61 mcThisByte ( 0 ),
62 mnTempAvail ( 0 ),
63 mpFastColorTable( NULL ),
64 mpColMap ( NULL )
69 // ------------------------------------------------------------------------
71 XPMReader::~XPMReader()
73 if( mpAcc )
74 maBmp.ReleaseAccess( mpAcc );
77 // ------------------------------------------------------------------------
79 #ifdef _MSC_VER
80 #pragma optimize ("",off)
81 #endif
83 ReadState XPMReader::ReadXPM( Graphic& rGraphic )
85 ReadState eReadState;
86 BYTE cDummy;
88 // sehen, ob wir _alles_ lesen koennen
89 mrIStm.Seek( STREAM_SEEK_TO_END );
90 mrIStm >> cDummy;
92 // falls wir nicht alles lesen koennen
93 // kehren wir zurueck und warten auf neue Daten
94 if ( mrIStm.GetError() != ERRCODE_IO_PENDING )
96 mrIStm.Seek( mnLastPos );
97 mbStatus = TRUE;
99 if ( mbStatus )
101 mpStringBuf = new BYTE [ XPMSTRINGBUF ];
102 mpTempBuf = new BYTE [ XPMTEMPBUFSIZE ];
104 if ( ( mbStatus = ImplGetString() ) == TRUE )
106 mnIdentifier = XPMVALUES; // Bitmap informationen einholen
107 mnWidth = ImplGetULONG( 0 );
108 mnHeight = ImplGetULONG( 1 );
109 mnColors = ImplGetULONG( 2 );
110 mnCpp = ImplGetULONG( 3 );
112 if ( mbStatus && mnWidth && mnHeight && mnColors && mnCpp )
114 mnIdentifier = XPMCOLORS;
116 // mpColMap beinhaltet fuer jede vorhandene
117 // Farbe: ( mnCpp )Byte(s)-> ASCII Eintrag der der Farbe zugeordnet ist
118 // 1 Byte -> 0xff wenn Farbe transparent ist
119 // 3 Bytes -> RGB Wert der Farbe
120 mpColMap = new BYTE[ mnColors * ( 4 + mnCpp ) ];
122 for ( ULONG i = 0; i < mnColors; i++ )
124 if ( ImplGetColor( i ) == FALSE )
126 mbStatus = FALSE;
127 break;
130 if ( mbStatus )
132 // bei mehr als 256 Farben wird eine 24 Bit Grafik erstellt
133 sal_uInt16 nBits = 1;
134 if ( mnColors > 256 )
135 nBits = 24;
136 else if ( mnColors > 16 )
137 nBits = 8;
138 else if ( mnColors > 2 )
139 nBits = 4;
140 else
141 nBits = 1;
143 maBmp = Bitmap( Size( mnWidth, mnHeight ), nBits );
144 mpAcc = maBmp.AcquireWriteAccess();
146 // mbTransparent ist TRUE wenn mindestens eine Farbe Transparent ist
147 if ( mbTransparent )
149 maMaskBmp = Bitmap( Size( mnWidth, mnHeight ), 1 );
150 if ( ( mpMaskAcc = maMaskBmp.AcquireWriteAccess() ) == NULL )
151 mbStatus = FALSE;
153 if( mpAcc && mbStatus )
155 ULONG i;
156 if ( mnColors <=256 ) // palette is only needed by using less than 257
157 { // colors
159 BYTE* pPtr = &mpColMap[mnCpp];
161 for ( i = 0; i < mnColors; i++ )
163 mpAcc->SetPaletteColor( (BYTE)i, Color( pPtr[1], pPtr[2], pPtr[3] ) );
164 pPtr += ( mnCpp + 4 );
166 // using 2 charakters per pixel and less than 257 Colors we speed up
167 if ( mnCpp == 2 ) // by using a 64kb indexing table
169 mpFastColorTable = new BYTE[ 256 * 256 ];
170 for ( pPtr = mpColMap, i = 0; i < mnColors; i++, pPtr += mnCpp + 4 )
172 ULONG j = pPtr[ 0 ] << 8;
173 j += pPtr[ 1 ];
174 mpFastColorTable[ j ] = (BYTE)i;
178 // now we get the bitmap data
179 mnIdentifier = XPMPIXELS;
180 for ( i = 0; i < mnHeight; i++ )
182 if ( ImplGetScanLine( i ) == FALSE )
184 mbStatus = FALSE;
185 break;
188 mnIdentifier = XPMEXTENSIONS;
193 delete[] mpFastColorTable;
194 delete[] mpColMap;
195 delete[] mpStringBuf;
196 delete[] mpTempBuf;
199 if( mbStatus )
201 if ( mpMaskAcc )
203 maMaskBmp.ReleaseAccess ( mpMaskAcc), mpMaskAcc = NULL;
204 maBmp.ReleaseAccess( mpAcc ), mpAcc = NULL;
205 rGraphic = Graphic( BitmapEx( maBmp, maMaskBmp ) );
207 else
209 maBmp.ReleaseAccess( mpAcc ), mpAcc = NULL;
210 rGraphic = maBmp;
212 eReadState = XPMREAD_OK;
214 else
216 if ( mpMaskAcc ) maMaskBmp.ReleaseAccess ( mpMaskAcc), mpMaskAcc = NULL;
217 if ( mpAcc ) maBmp.ReleaseAccess( mpAcc ), mpAcc = NULL;
218 eReadState = XPMREAD_ERROR;
221 else
223 mrIStm.ResetError();
224 eReadState = XPMREAD_NEED_MORE;
226 return eReadState;
229 #ifdef _MSC_VER
230 #pragma optimize ("",on)
231 #endif
233 // ------------------------------------------------------------------------
234 // ImplGetColor ermittelt saemtliche Farbwerte,
235 // die Rueckgabe ist TRUE wenn saemtliche Farben zugeordnet werden konnten
237 BOOL XPMReader::ImplGetColor( ULONG nNumb )
239 BYTE* pString = mpStringBuf;
240 BYTE* pPtr = ( mpColMap + nNumb * ( 4 + mnCpp ) );
241 BOOL bStatus = ImplGetString();
243 if ( bStatus )
245 for ( ULONG i = 0; i < mnCpp; i++ )
246 *pPtr++ = *pString++;
247 bStatus = ImplGetColSub ( pPtr );
249 return bStatus;
252 // ------------------------------------------------------------------------
253 // ImpGetScanLine liest den String mpBufSize aus und schreibt die Pixel in die
254 // Bitmap. Der Parameter nY gibt die horizontale Position an.
256 BOOL XPMReader::ImplGetScanLine( ULONG nY )
258 BOOL bStatus = ImplGetString();
259 BYTE* pString = mpStringBuf;
260 BYTE* pColor;
261 BitmapColor aWhite;
262 BitmapColor aBlack;
264 if ( bStatus )
266 if ( mpMaskAcc )
268 aWhite = mpMaskAcc->GetBestMatchingColor( Color( COL_WHITE ) );
269 aBlack = mpMaskAcc->GetBestMatchingColor( Color( COL_BLACK ) );
271 if ( mnStringSize != ( mnWidth * mnCpp ))
272 bStatus = FALSE;
273 else
275 ULONG i, j;
276 if ( mpFastColorTable )
278 for ( i = 0; i < mnWidth; i++ )
280 j = (*pString++) << 8;
281 j += *pString++;
282 BYTE k = (BYTE)mpFastColorTable[ j ];
283 mpAcc->SetPixel( nY, i, BitmapColor( (BYTE)k ) );
285 if ( mpMaskAcc )
286 mpMaskAcc->SetPixel( nY, i,
287 ( mpColMap[ k * (mnCpp + 4) + mnCpp] ) ? aWhite : aBlack );
290 else for ( i = 0; i < mnWidth; i++ )
292 pColor = mpColMap;
293 for ( j = 0; j < mnColors; j++ )
295 if ( ImplCompare( pString, pColor, mnCpp, XPMCASESENSITIVE ) == TRUE )
297 if ( mnColors > 256 )
298 mpAcc->SetPixel( nY, i, Color ( pColor[3], pColor[4], pColor[5] ) );
299 else
300 mpAcc->SetPixel( nY, i, BitmapColor( (BYTE) j ) );
302 if ( mpMaskAcc )
303 mpMaskAcc->SetPixel( nY, i, (
304 pColor[ mnCpp ] ) ? aWhite : aBlack );
306 break;
308 pColor += ( mnCpp + 4 );
310 pString += mnCpp;
315 return bStatus;
318 // ------------------------------------------------------------------------
319 // versucht aus mpStringBuf einen Farbwert zu uebermitteln
320 // wurde eine Farbe gefunden wird an pDest[1]..pDest[2] der RGB wert geschrieben
321 // pDest[0] enthaelt 0xff wenn die Farbe transparent ist sonst 0
323 BOOL XPMReader::ImplGetColSub( BYTE* pDest )
325 unsigned char cTransparent[] = "None";
327 BOOL bColStatus = FALSE;
329 if ( ImplGetColKey( 'c' ) || ImplGetColKey( 'm' ) || ImplGetColKey( 'g' ) )
331 // hexentry for RGB or HSV color ?
332 if ( *mpPara == '#' )
334 *pDest++ = 0;
335 bColStatus = TRUE;
336 switch ( mnParaSize )
338 case 25 :
339 ImplGetRGBHex ( pDest, 6 );
340 break;
341 case 13 :
342 ImplGetRGBHex ( pDest, 2 );
343 break;
344 case 7 :
345 ImplGetRGBHex ( pDest, 0 );
346 break;
347 default:
348 bColStatus = FALSE;
349 break;
352 // maybe pixel is transparent
353 else if ( ImplCompare( &cTransparent[0], mpPara, 4 ))
355 *pDest++ = 0xff;
356 bColStatus = TRUE;
357 mbTransparent = TRUE;
359 // last we will try to get the colorname
360 else if ( mnParaSize > 2 ) // name must enlarge the minimum size
362 ULONG i = 0;
363 while ( TRUE )
365 if ( pRGBTable[ i ].name == NULL )
366 break;
367 if ( pRGBTable[ i ].name[ mnParaSize ] == 0 )
369 if ( ImplCompare ( (unsigned char*)pRGBTable[ i ].name,
370 mpPara, mnParaSize, XPMCASENONSENSITIVE ) )
372 bColStatus = TRUE;
373 *pDest++ = 0;
374 *pDest++ = pRGBTable[ i ].red;
375 *pDest++ = pRGBTable[ i ].green;
376 *pDest++ = pRGBTable[ i ].blue;
379 i++;
383 return bColStatus;
386 // ------------------------------------------------------------------------
387 // ImplGetColKey durchsuch den String mpStringBuf nach einem Parameter 'nKey'
388 // und gibt einen BOOL zurueck. ( wenn TRUE werden mpPara und mnParaSize gesetzt )
390 BOOL XPMReader::ImplGetColKey( BYTE nKey )
392 BYTE nTemp, nPrev = ' ';
394 mpPara = mpStringBuf + mnCpp + 1;
395 mnParaSize = 0;
397 while ( *mpPara != 0 )
399 if ( *mpPara == nKey )
401 nTemp = *( mpPara + 1 );
402 if ( nTemp == ' ' || nTemp == 0x09 )
404 if ( nPrev == ' ' || nPrev == 0x09 )
405 break;
408 nPrev = *mpPara;
409 mpPara++;
411 if ( *mpPara )
413 mpPara++;
414 while ( (*mpPara == ' ') || (*mpPara == 0x09) )
416 mpPara++;
418 if ( *mpPara != 0 )
420 while ( *(mpPara+mnParaSize) != ' ' && *(mpPara+mnParaSize) != 0x09 &&
421 *(mpPara+mnParaSize) != 0 )
423 mnParaSize++;
427 return ( mnParaSize ) ? TRUE : FALSE;
430 // ------------------------------------------------------------------------
431 // ImplGetRGBHex uebersetzt den ASCII-Hexadezimalwert der sich bei mpPara befindet
432 // in einen RGB wert und schreibt diesen nach pDest
433 // folgende Formate muessen sich bei mpPara befinden:
434 // wenn nAdd = 0 : '#12ab12' -> RGB = 0x12, 0xab, 0x12
435 // 2 : '#1234abcd1234' " " " "
436 // 6 : '#12345678abcdefab12345678' " " " "
439 void XPMReader::ImplGetRGBHex( BYTE* pDest,ULONG nAdd )
441 BYTE* pPtr = mpPara+1;
442 BYTE nHex, nTemp;
444 for ( ULONG i = 0; i < 3; i++ )
446 nHex = (*pPtr++) - '0';
447 if ( nHex > 9 )
448 nHex = ((nHex - 'A' + '0') & 7) + 10;
450 nTemp = (*pPtr++) - '0';
451 if ( nTemp > 9 )
452 nTemp = ((nTemp - 'A' + '0') & 7) + 10;
453 nHex = ( nHex << 4 ) + nTemp;
455 pPtr += nAdd;
456 *pDest++ = (BYTE)nHex;
460 // ------------------------------------------------------------------------
461 // ImplGetUlong gibt den wert einer bis zu 6stelligen ASCII-Dezimalzahl zurueck.
463 ULONG XPMReader::ImplGetULONG( ULONG nPara )
465 if ( ImplGetPara ( nPara ) )
467 ULONG nRetValue = 0;
468 BYTE* pPtr = mpPara;
470 if ( ( mnParaSize > 6 ) || ( mnParaSize == 0 ) ) return 0;
471 for ( ULONG i = 0; i < mnParaSize; i++ )
473 BYTE j = (*pPtr++) - 48;
474 if ( j > 9 ) return 0; // ascii is invalid
475 nRetValue*=10;
476 nRetValue+=j;
478 return nRetValue;
480 else return 0;
483 // ------------------------------------------------------------------------
485 BOOL XPMReader::ImplCompare( BYTE* pSource, BYTE* pDest, ULONG nSize, ULONG nMode )
487 BOOL bRet = TRUE;
489 if ( nMode == XPMCASENONSENSITIVE )
491 for ( ULONG i = 0; i < nSize; i++ )
493 if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
495 bRet = FALSE;
496 break;
500 else
502 for ( ULONG i = 0; i < nSize; i++ )
504 if ( pSource[i] != pDest[i] )
506 bRet = FALSE;
507 break;
511 return bRet;
514 // ------------------------------------------------------------------------
515 // ImplGetPara versucht den nNumb ( 0...x ) Parameter aus mpStringBuf zu ermitteln.
516 // Ein Parameter ist durch Spaces oder Tabs von den anderen getrennt.
517 // Konnte der Parameter gefunden werden ist der Rueckgabewert TRUE und mpPara + mnParaSize
518 // werden gesetzt.
520 BOOL XPMReader::ImplGetPara ( ULONG nNumb )
522 BYTE nByte;
523 ULONG pSize = 0;
524 BYTE* pPtr = mpStringBuf;
525 ULONG nCount = 0;
527 if ( ( *pPtr != ' ' ) && ( *pPtr != 0x09 ) )
529 mpPara = pPtr;
530 mnParaSize = 0;
531 nCount = 0;
533 else
535 mpPara = NULL;
536 nCount = 0xffffffff;
539 while ( pSize < mnStringSize )
541 nByte = *pPtr;
543 if ( mpPara )
545 if ( ( nByte == ' ' ) || ( nByte == 0x09 ) )
547 if ( nCount == nNumb )
548 break;
549 else
550 mpPara = NULL;
552 else
553 mnParaSize++;
555 else
557 if ( ( nByte != ' ' ) && ( nByte != 0x09 ) )
559 mpPara = pPtr;
560 mnParaSize = 1;
561 nCount++;
564 pSize++;
565 pPtr++;
567 return ( ( nCount == nNumb ) && ( mpPara ) ) ? TRUE : FALSE;
570 // ------------------------------------------------------------------------
571 // Der naechste String wird ausgelesen und in mpStringBuf (mit 0 abgeschlossen) abgelegt;
572 // mnStringSize enthaelt die Groesse des gelesenen Strings.
573 // Bemerkungen wie '//' und '/*.....*/' werden uebersprungen.
575 BOOL XPMReader::ImplGetString( void )
577 BYTE sID[] = "/* XPM */";
578 BYTE* pString = mpStringBuf;
580 mnStringSize = 0;
581 mpStringBuf[0] = 0;
583 while( mbStatus && ( mnStatus != XPMFINISHED ) )
585 if ( mnTempAvail == 0 )
587 mnTempAvail = mrIStm.Read( mpTempBuf, XPMTEMPBUFSIZE );
588 if ( mnTempAvail == 0 )
589 break;
591 mpTempPtr = mpTempBuf;
593 if ( mnIdentifier == XPMIDENTIFIER )
595 if ( mnTempAvail <= 50 )
597 mbStatus = FALSE; // file is too short to be a correct XPM format
598 break;
600 for ( int i = 0; i < 9; i++ ) // searching for "/* XPM */"
601 if ( *mpTempPtr++ != sID[i] )
603 mbStatus = FALSE;
604 break;
606 mnTempAvail-=9;
607 mnIdentifier++;
610 mcLastByte = mcThisByte;
611 mcThisByte = *mpTempPtr++;
612 mnTempAvail--;
614 if ( mnStatus & XPMDOUBLE )
616 if ( mcThisByte == 0x0a )
617 mnStatus &=~XPMDOUBLE;
618 continue;
620 if ( mnStatus & XPMREMARK )
622 if ( ( mcThisByte == '/' ) && ( mcLastByte == '*' ) )
623 mnStatus &=~XPMREMARK;
624 continue;
626 if ( mnStatus & XPMSTRING ) // characters in string
628 if ( mcThisByte == '"' )
630 mnStatus &=~XPMSTRING; // end of parameter by eol
631 break;
633 if ( mnStringSize >= XPMSTRINGBUF )
635 mbStatus = FALSE;
636 break;
638 *pString++ = mcThisByte;
639 pString[0] = 0;
640 mnStringSize++;
641 continue;
643 else
644 { // characters beside string
645 switch ( mcThisByte )
647 case '*' :
648 if ( mcLastByte == '/' ) mnStatus |= XPMREMARK;
649 break;
650 case '/' :
651 if ( mcLastByte == '/' ) mnStatus |= XPMDOUBLE;
652 break;
653 case '"' : mnStatus |= XPMSTRING;
654 break;
655 case '{' :
656 if ( mnIdentifier == XPMDEFINITION )
657 mnIdentifier++;
658 break;
659 case '}' :
660 if ( mnIdentifier == XPMENDEXT )
661 mnStatus = XPMFINISHED;
662 break;
666 return mbStatus;
669 // -------------
670 // - ImportXPM -
671 // -------------
673 BOOL ImportXPM( SvStream& rStm, Graphic& rGraphic )
675 XPMReader* pXPMReader = (XPMReader*) rGraphic.GetContext();
676 ReadState eReadState;
677 BOOL bRet = TRUE;
679 if( !pXPMReader )
680 pXPMReader = new XPMReader( rStm );
682 rGraphic.SetContext( NULL );
683 eReadState = pXPMReader->ReadXPM( rGraphic );
685 if( eReadState == XPMREAD_ERROR )
687 bRet = FALSE;
688 delete pXPMReader;
690 else if( eReadState == XPMREAD_OK )
691 delete pXPMReader;
692 else
693 rGraphic.SetContext( pXPMReader );
695 return bRet;