blob: 09d899539924b8b8357192c8656b6620d010f4a8 [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"
#include <cstdio>
#include <csignal>
#include <vector>
#include <set>
#include <map>
#include <rtl/crc.h>
#include <tools/stream.hxx>
#include <tools/fsys.hxx>
#include <vcl/svapp.hxx>
#include <vcl/bitmap.hxx>
#include <vcl/bmpacc.hxx>
#include <vcl/pngread.hxx>
#include <vcl/dibtools.hxx>
#include "svl/solar.hrc"
#define EXIT_NOERROR 0x00000000
#define EXIT_INVALIDFILE 0x00000001
#define EXIT_COMMONERROR 0x80000000
// ----------
// - BmpSum -
// ----------
class BmpSum
{
private:
sal_uInt32 cExitCode;
sal_Bool GetCommandOption( const ::std::vector< String >& rArgs, const String& rSwitch, String& rSwitchParam );
sal_Bool GetCommandOptions( const ::std::vector< String >& rArgs, const String& rSwitch, ::std::vector< String >& rSwitchParams );
void SetExitCode( sal_uInt8 cExit )
{
if( ( EXIT_NOERROR == cExitCode ) || ( cExit != EXIT_NOERROR ) )
cExitCode = cExit;
}
void ShowUsage();
void Message( const String& rText, sal_uInt8 cExitCode );
sal_uInt64 GetCRC( const BitmapEx& rBmpEx );
void ProcessFile( const String& rBmpFileName );
void ProcessFileList( const String& rInFileList, const String& rOutFileList, const String& rOutPath );
public:
//
BmpSum();
~BmpSum();
int Start( const ::std::vector< String >& rArgs );
};
// -----------------------------------------------------------------------------
BmpSum::BmpSum()
{
}
// -----------------------------------------------------------------------------
BmpSum::~BmpSum()
{
}
// -----------------------------------------------------------------------
sal_Bool BmpSum::GetCommandOption( const ::std::vector< String >& rArgs, const String& rSwitch, String& rParam )
{
sal_Bool bRet = sal_False;
for( int i = 0, nCount = rArgs.size(); ( i < nCount ) && !bRet; i++ )
{
String aTestStr( '-' );
for( int n = 0; ( n < 2 ) && !bRet; n++ )
{
aTestStr += rSwitch;
if( aTestStr.CompareIgnoreCaseToAscii( rArgs[ i ] ) == COMPARE_EQUAL )
{
bRet = sal_True;
if( i < ( nCount - 1 ) )
rParam = rArgs[ i + 1 ];
else
rParam = String();
}
if( 0 == n )
aTestStr = '/';
}
}
return bRet;
}
// -----------------------------------------------------------------------
sal_Bool BmpSum::GetCommandOptions( const ::std::vector< String >& rArgs, const String& rSwitch, ::std::vector< String >& rParams )
{
sal_Bool bRet = sal_False;
for( int i = 0, nCount = rArgs.size(); ( i < nCount ); i++ )
{
String aTestStr( '-' );
for( int n = 0; ( n < 2 ) && !bRet; n++ )
{
aTestStr += rSwitch;
if( aTestStr.CompareIgnoreCaseToAscii( rArgs[ i ] ) == COMPARE_EQUAL )
{
if( i < ( nCount - 1 ) )
rParams.push_back( rArgs[ i + 1 ] );
else
rParams.push_back( String() );
break;
}
if( 0 == n )
aTestStr = '/';
}
}
return( rParams.size() > 0 );
}
// -----------------------------------------------------------------------
void BmpSum::Message( const String& rText, sal_uInt8 nExitCode )
{
if( EXIT_NOERROR != nExitCode )
SetExitCode( nExitCode );
ByteString aText( rText, RTL_TEXTENCODING_UTF8 );
aText.Append( "\r\n" );
fprintf( stderr, aText.GetBuffer() );
}
// -----------------------------------------------------------------------------
void BmpSum::ShowUsage()
{
Message( String( RTL_CONSTASCII_USTRINGPARAM( "Usage:" ) ), EXIT_NOERROR );
Message( String( RTL_CONSTASCII_USTRINGPARAM( " bmpsum bmp_inputfile" ) ), EXIT_NOERROR );
Message( String( RTL_CONSTASCII_USTRINGPARAM( " bmpsum -i input_filelist -o output_filelist [-p path_for_copied_bitmaps]" ) ), EXIT_NOERROR );
Message( String( RTL_CONSTASCII_USTRINGPARAM( "Options:" ) ), EXIT_NOERROR );
Message( String( RTL_CONSTASCII_USTRINGPARAM( "Examples:" ) ), EXIT_NOERROR );
Message( String( RTL_CONSTASCII_USTRINGPARAM( " bmpsum /home/test.bmp" ) ), EXIT_NOERROR );
Message( String( RTL_CONSTASCII_USTRINGPARAM( " bmpsum -i /home/inlist.txt -o /home/outlist.txt" ) ), EXIT_NOERROR );
Message( String( RTL_CONSTASCII_USTRINGPARAM( " bmpsum -i /home/inlist.txt -o /home/outlist.txt -p /home/outpath" ) ), EXIT_NOERROR );
}
// -----------------------------------------------------------------------------
int BmpSum::Start( const ::std::vector< String >& rArgs )
{
cExitCode = EXIT_NOERROR;
if( rArgs.size() >= 1 )
{
String aInFileList, aOutFileList, aOutPath;
if( GetCommandOption( rArgs, 'i', aInFileList ) &&
GetCommandOption( rArgs, 'o', aOutFileList ) )
{
GetCommandOption( rArgs, 'p', aOutPath );
ProcessFileList( aInFileList, aOutFileList, aOutPath );
}
else
{
ProcessFile( rArgs[ 0 ] );
}
}
else
{
ShowUsage();
cExitCode = EXIT_COMMONERROR;
}
return cExitCode;
}
// -----------------------------------------------------------------------------
sal_uInt64 BmpSum::GetCRC( const BitmapEx& rBmpEx )
{
Bitmap aBmp( rBmpEx.GetBitmap() );
BitmapReadAccess* pRAcc = aBmp.AcquireReadAccess();
AlphaMask aAlpha;
BitmapReadAccess* pAAcc = NULL;
sal_uInt64 nRet = 0;
sal_uInt32 nCrc = 0;
if( rBmpEx.IsTransparent() )
{
aAlpha = rBmpEx.GetAlpha();
pAAcc = aAlpha.AcquireReadAccess();
}
if( pRAcc && pRAcc->Width() && pRAcc->Height() )
{
SVBT32 aBT32;
for( long nY = 0; nY < pRAcc->Height(); ++nY )
{
for( long nX = 0; nX < pRAcc->Width(); ++nX )
{
const BitmapColor aCol( pRAcc->GetColor( nY, nX ) );
UInt32ToSVBT32( aCol.GetRed(), aBT32 );
nCrc = rtl_crc32( nCrc, aBT32, 4 );
UInt32ToSVBT32( aCol.GetGreen(), aBT32 );
nCrc = rtl_crc32( nCrc, aBT32, 4 );
UInt32ToSVBT32( aCol.GetBlue(), aBT32 );
nCrc = rtl_crc32( nCrc, aBT32, 4 );
if( pAAcc )
{
const BitmapColor aMaskCol( pAAcc->GetColor( nY, nX ) );
UInt32ToSVBT32( aMaskCol.GetRed(), aBT32 );
nCrc = rtl_crc32( nCrc, aBT32, 4 );
UInt32ToSVBT32( aMaskCol.GetGreen(), aBT32 );
nCrc = rtl_crc32( nCrc, aBT32, 4 );
UInt32ToSVBT32( aMaskCol.GetBlue(), aBT32 );
nCrc = rtl_crc32( nCrc, aBT32, 4 );
}
}
}
nRet = ( ( (sal_uInt64) pRAcc->Width() ) << 48 ) |
( ( (sal_uInt64) pRAcc->Height() ) << 32 ) |
( (sal_uInt64) nCrc );
}
if( pAAcc )
aAlpha.ReleaseAccess( pAAcc);
aBmp.ReleaseAccess( pRAcc );
return nRet;
}
// -----------------------------------------------------------------------------
void BmpSum::ProcessFile( const String& rBmpFileName )
{
SvFileStream aIStm( rBmpFileName, STREAM_READ );
if( aIStm.IsOpen() )
{
BitmapEx aBmpEx;
ReadDIBBitmapEx(aBmpEx, aIStm);
if( !aBmpEx.IsEmpty() )
{
fprintf( stdout, "%" SAL_PRIuUINT64 "\r\n", GetCRC( aBmpEx ) );
}
else
{
aIStm.ResetError();
aIStm.Seek( 0 );
::vcl::PNGReader aPngReader( aIStm );
aBmpEx = aPngReader.Read();
if( !aBmpEx.IsEmpty() )
{
fprintf( stdout, "%" SAL_PRIuUINT64 "\r\n", GetCRC( aBmpEx ) );
}
else
Message( String( RTL_CONSTASCII_USTRINGPARAM( "file not valid" ) ), EXIT_INVALIDFILE );
}
}
}
// -----------------------------------------------------------------------------
void BmpSum::ProcessFileList( const String& rInFileList,
const String& rOutFileList,
const String& rOutPath )
{
SvFileStream aIStm( rInFileList, STREAM_READ );
SvFileStream aOStm( rOutFileList, STREAM_WRITE | STREAM_TRUNC );
const DirEntry aBaseDir( rOutPath );
if( rOutPath.Len() )
aBaseDir.MakeDir();
if( aIStm.IsOpen() && aOStm.IsOpen() )
{
ByteString aReadLine;
::std::set< ByteString > aFileNameSet;
while( aIStm.ReadLine( aReadLine ) )
{
if( aReadLine.Len() )
aFileNameSet.insert( aReadLine );
if( aReadLine.Search( "enus" ) != STRING_NOTFOUND )
{
static const char* aLanguages[] =
{
"chinsim",
"chintrad",
"dtch",
"enus",
"fren",
"hebrew"
"ital",
"japn",
"korean",
"pol",
"poln",
"port",
"russ",
"span",
"turk"
};
for( sal_uInt32 n = 0; n < 14; ++n )
{
ByteString aLangPath( aReadLine );
aLangPath.SearchAndReplace( "enus", aLanguages[ n ] );
DirEntry aTestFile( aLangPath );
if( aTestFile.Exists() )
aFileNameSet.insert( aLangPath );
}
}
aReadLine.Erase();
}
aIStm.Close();
::std::set< ByteString >::iterator aIter( aFileNameSet.begin() );
::std::map< sal_uInt64, ::std::vector< ByteString > > aFileNameMap;
while( aIter != aFileNameSet.end() )
{
ByteString aStr( *aIter++ );
SvFileStream aBmpStm( String( aStr.GetBuffer(), RTL_TEXTENCODING_ASCII_US ), STREAM_READ );
sal_uInt64 nCRC = 0;
if( aBmpStm.IsOpen() )
{
BitmapEx aBmpEx;
ReadDIBBitmapEx(aBmpEx, aBmpStm);
if( !aBmpEx.IsEmpty() )
nCRC = GetCRC( aBmpEx );
else
{
aBmpStm.ResetError();
aBmpStm.Seek( 0 );
::vcl::PNGReader aPngReader( aBmpStm );
aBmpEx = aPngReader.Read();
if( !aBmpEx.IsEmpty() )
nCRC = GetCRC( aBmpEx );
else
fprintf( stderr, "%s could not be opened\n", aStr.GetBuffer() );
}
aBmpStm.Close();
}
if( nCRC )
{
::std::map< sal_uInt64, ::std::vector< ByteString > >::iterator aFound( aFileNameMap.find( nCRC ) );
if( aFound != aFileNameMap.end() )
(*aFound).second.push_back( aStr );
else
{
::std::vector< ByteString > aVector( 1, aStr );
aFileNameMap[ nCRC ] = aVector;
}
}
else
{
::std::vector< ByteString > aVector( 1, aStr );
aFileNameMap[ nCRC ] = aVector;
}
}
::std::map< sal_uInt64, ::std::vector< ByteString > >::iterator aMapIter( aFileNameMap.begin() );
sal_uInt32 nFileCount = 0;
while( aMapIter != aFileNameMap.end() )
{
::std::pair< const sal_uInt64, ::std::vector< ByteString > > aPair( *aMapIter++ );
::std::vector< ByteString > aFileNameVector( aPair.second );
// write new entries
for( sal_uInt32 i = 0; i < aFileNameVector.size(); ++i )
{
ByteString aStr( ByteString::CreateFromInt64( aPair.first ) );
ByteString aFileName( aFileNameVector[ i ] );
DirEntry aSrcFile( aFileName );
aStr += '\t';
aStr += aFileName;
aOStm.WriteLine( aStr );
// copy bitmap
if( rOutPath.Len() )
{
if( aFileName.Search( ":\\" ) != STRING_NOTFOUND )
aFileName.Erase( 0, aFileName.Search( ":\\" ) + 2 );
aFileName.SearchAndReplaceAll( '\\', '/' );
sal_uInt16 nTokenCount = aFileName.GetTokenCount( '/' );
DirEntry aNewDir( aBaseDir );
for( sal_uInt16 n = 0; ( n < nTokenCount - 1 ); n++ )
{
aNewDir += DirEntry( aFileName.GetToken( n, '/' ) );
aNewDir.MakeDir();
}
aNewDir += DirEntry( aFileName.GetToken( nTokenCount - 1, '/' ) );
aSrcFile.CopyTo( aNewDir, FSYS_ACTION_COPYFILE );
}
}
++nFileCount;
}
fprintf(
stdout, "unique file count: %lu",
sal::static_int_cast< unsigned long >(nFileCount) );
}
}
// --------
// - Main -
// --------
int main( int nArgCount, char* ppArgs[] )
{
#ifdef UNX
static char aDisplayVar[ 1024 ];
strcpy( aDisplayVar, "DISPLAY=" );
putenv( aDisplayVar );
#endif
::std::vector< String > aArgs;
BmpSum aBmpSum;
InitVCL( com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory >() );
for( int i = 1; i < nArgCount; i++ )
aArgs.push_back( String( ppArgs[ i ], RTL_TEXTENCODING_ASCII_US ) );
return aBmpSum.Start( aArgs );
}