blob: 14313496ec957b631dee41f86d8b44335276540a [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svtools.hxx"
#define XBMMINREAD 512
#define _XBMPRIVATE
#include <ctype.h>
#include "xbmread.hxx"
// -------------
// - XBMReader -
// -------------
XBMReader::XBMReader( SvStream& rStm ) :
rIStm ( rStm ),
pAcc1 ( NULL ),
nLastPos ( rStm.Tell() ),
nWidth ( 0 ),
nHeight ( 0 ),
bStatus ( sal_True )
{
pHexTable = new short[ 256 ];
maUpperName = String::CreateFromAscii( "SVIXBM", 6 );
InitTable();
}
// ------------------------------------------------------------------------
XBMReader::~XBMReader()
{
delete[] pHexTable;
if( pAcc1 )
aBmp1.ReleaseAccess( pAcc1 );
}
// ------------------------------------------------------------------------
void XBMReader::InitTable()
{
memset( pHexTable, 0, sizeof( short ) );
pHexTable['0'] = 0;
pHexTable['1'] = 1;
pHexTable['2'] = 2;
pHexTable['3'] = 3;
pHexTable['4'] = 4;
pHexTable['5'] = 5;
pHexTable['6'] = 6;
pHexTable['7'] = 7;
pHexTable['8'] = 8;
pHexTable['9'] = 9;
pHexTable['A'] = 10;
pHexTable['B'] = 11;
pHexTable['C'] = 12;
pHexTable['D'] = 13;
pHexTable['E'] = 14;
pHexTable['F'] = 15;
pHexTable['X'] = 0;
pHexTable['a'] = 10;
pHexTable['b'] = 11;
pHexTable['c'] = 12;
pHexTable['d'] = 13;
pHexTable['e'] = 14;
pHexTable['f'] = 15;
pHexTable['x'] = 0;
pHexTable[' '] = -1;
pHexTable[','] = -1;
pHexTable['}'] = -1;
pHexTable['\n'] = -1;
pHexTable['\t'] = -1;
pHexTable['\0'] = -1;
}
// ------------------------------------------------------------------------
ByteString XBMReader::FindTokenLine( SvStream* pInStm, const char* pTok1,
const char* pTok2, const char* pTok3 )
{
ByteString aRet;
long nPos1;
long nPos2;
long nPos3;
bStatus = sal_False;
do
{
if( !pInStm->ReadLine( aRet ) )
break;
if( pTok1 )
{
if( ( nPos1 = aRet.Search( pTok1 ) ) != STRING_NOTFOUND )
{
bStatus = sal_True;
if( pTok2 )
{
bStatus = sal_False;
if( ( ( nPos2 = aRet.Search( pTok2 ) ) != STRING_NOTFOUND ) &&
( nPos2 > nPos1 ) )
{
bStatus = sal_True;
if( pTok3 )
{
bStatus = sal_False;
if( ( ( nPos3 = aRet.Search( pTok3 ) ) != STRING_NOTFOUND ) && ( nPos3 > nPos2 ) )
bStatus = sal_True;
}
}
}
}
}
}
while( !bStatus );
return aRet;
}
// ------------------------------------------------------------------------
long XBMReader::ParseDefine( const sal_Char* pDefine )
{
long nRet = 0;
char* pTmp = (char*) pDefine;
unsigned char cTmp;
// bis zum Ende gehen
pTmp += ( strlen( pDefine ) - 1 );
cTmp = *pTmp--;
// letzte Ziffer suchen
while( pHexTable[ cTmp ] == -1 )
cTmp = *pTmp--;
// bis vor die Zahl laufen
while( pHexTable[ cTmp ] != -1 )
cTmp = *pTmp--;
// auf Anfang der Zahl gehen
pTmp += 2;
// Hex lesen
if( ( pTmp[0] == '0' ) && ( ( pTmp[1] == 'X' ) || ( pTmp[1] == 'x' ) ) )
{
pTmp += 2;
cTmp = *pTmp++;
while ( pHexTable[ cTmp ] != -1 )
{
nRet = ( nRet << 4 ) + pHexTable[ cTmp ];
cTmp = *pTmp++;
}
}
// Dezimal lesen
else
{
cTmp = *pTmp++;
while( ( cTmp >= '0' ) && ( cTmp <= '9' ) )
{
nRet = nRet * 10 + ( cTmp - '0' );
cTmp = *pTmp++;
}
}
return nRet;
}
// ------------------------------------------------------------------------
sal_Bool XBMReader::ParseData( SvStream* pInStm, const ByteString& aLastLine, XBMFormat eFormat )
{
ByteString aLine;
long nRow = 0;
long nCol = 0;
long nBits = ( eFormat == XBM10 ) ? 16 : 8;
long nBit;
sal_uInt16 nValue;
sal_uInt16 nDigits;
sal_Bool bFirstLine = sal_True;
while( nRow < nHeight )
{
if( bFirstLine )
{
xub_StrLen nPos;
// einfuehrende geschweifte Klammer loeschen
if( (nPos = ( aLine = aLastLine ).Search( '{' ) ) != STRING_NOTFOUND )
aLine.Erase( 0, nPos + 1 );
bFirstLine = sal_False;
}
else if( !pInStm->ReadLine( aLine ) )
break;
if( aLine.Len() )
{
const sal_uInt16 nCount = aLine.GetTokenCount( ',' );
for( sal_uInt16 i = 0; ( i < nCount ) && ( nRow < nHeight ); i++ )
{
const ByteString aToken( aLine.GetToken( i, ',' ) );
const xub_StrLen nLen = aToken.Len();
sal_Bool bProcessed = sal_False;
nBit = nDigits = nValue = 0;
for( xub_StrLen n = 0UL; n < nLen; n++ )
{
const unsigned char cChar = aToken.GetChar( n );
const short nTable = pHexTable[ cChar ];
if( isxdigit( cChar ) || !nTable )
{
nValue = ( nValue << 4 ) + nTable;
nDigits++;
bProcessed = sal_True;
}
else if( ( nTable < 0 ) && nDigits )
{
bProcessed = sal_True;
break;
}
}
if( bProcessed )
{
while( ( nCol < nWidth ) && ( nBit < nBits ) )
pAcc1->SetPixel( nRow, nCol++, ( nValue & ( 1 << nBit++ ) ) ? aBlack : aWhite );
if( nCol == nWidth )
nCol = 0, nRow++;
}
}
}
}
return sal_True;
}
// ------------------------------------------------------------------------
ReadState XBMReader::ReadXBM( Graphic& rGraphic )
{
ReadState eReadState;
sal_uInt8 cDummy;
// sehen, ob wir _alles_ lesen koennen
rIStm.Seek( STREAM_SEEK_TO_END );
rIStm >> cDummy;
// falls wir nicht alles lesen koennen
// kehren wir zurueck und warten auf neue Daten
if ( rIStm.GetError() != ERRCODE_IO_PENDING )
{
ByteString aLine;
int nValue;
rIStm.Seek( nLastPos );
bStatus = sal_False;
aLine = FindTokenLine( &rIStm, "#define", "_width" );
if ( bStatus )
{
if ( ( nValue = (int) ParseDefine( aLine.GetBuffer() ) ) > 0 )
{
nWidth = nValue;
aLine = FindTokenLine( &rIStm, "#define", "_height" );
// Falls die Hoehe nicht folgt, suchen wir noch
// einmal vom Anfang der Datei an
if ( !bStatus )
{
rIStm.Seek( nLastPos );
aLine = FindTokenLine( &rIStm, "#define", "_height" );
}
}
else
bStatus = sal_False;
if ( bStatus )
{
if ( ( nValue = (int) ParseDefine( aLine.GetBuffer() ) ) > 0 )
{
nHeight = nValue;
aLine = FindTokenLine( &rIStm, "static", "_bits" );
if ( bStatus )
{
XBMFormat eFormat = XBM10;
if ( aLine.Search( "short" ) != STRING_NOTFOUND )
eFormat = XBM10;
else if ( aLine.Search( "char" ) != STRING_NOTFOUND )
eFormat = XBM11;
else
bStatus = sal_False;
if ( bStatus && nWidth && nHeight )
{
aBmp1 = Bitmap( Size( nWidth, nHeight ), 1 );
pAcc1 = aBmp1.AcquireWriteAccess();
if( pAcc1 )
{
aWhite = pAcc1->GetBestMatchingColor( Color( COL_WHITE ) );
aBlack = pAcc1->GetBestMatchingColor( Color( COL_BLACK ) );
bStatus = ParseData( &rIStm, aLine, eFormat );
}
else
bStatus = sal_False;
}
}
}
}
}
if( bStatus )
{
Bitmap aBlackBmp( Size( pAcc1->Width(), pAcc1->Height() ), 1 );
aBmp1.ReleaseAccess( pAcc1 ), pAcc1 = NULL;
aBlackBmp.Erase( Color( COL_BLACK ) );
rGraphic = BitmapEx( aBlackBmp, aBmp1 );
eReadState = XBMREAD_OK;
}
else
eReadState = XBMREAD_ERROR;
}
else
{
rIStm.ResetError();
eReadState = XBMREAD_NEED_MORE;
}
return eReadState;
}
// -------------
// - ImportXBM -
// -------------
sal_Bool ImportXBM( SvStream& rStm, Graphic& rGraphic )
{
XBMReader* pXBMReader = (XBMReader*) rGraphic.GetContext();
ReadState eReadState;
sal_Bool bRet = sal_True;
if( !pXBMReader )
pXBMReader = new XBMReader( rStm );
rGraphic.SetContext( NULL );
eReadState = pXBMReader->ReadXBM( rGraphic );
if( eReadState == XBMREAD_ERROR )
{
bRet = sal_False;
delete pXBMReader;
}
else if( eReadState == XBMREAD_OK )
delete pXBMReader;
else
rGraphic.SetContext( pXBMReader );
return bRet;
}