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 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_svtools.hxx"
24
25 #include <cstdio>
26 #include <csignal>
27 #include <vector>
28 #include <set>
29 #include <map>
30 #include <rtl/crc.h>
31 #include <tools/stream.hxx>
32 #include <tools/fsys.hxx>
33 #include <vcl/svapp.hxx>
34 #include <vcl/bitmap.hxx>
35 #include <vcl/bmpacc.hxx>
36 #include <vcl/pngread.hxx>
37 #include <vcl/dibtools.hxx>
38 #include "svl/solar.hrc"
39
40 #define EXIT_NOERROR 0x00000000
41 #define EXIT_INVALIDFILE 0x00000001
42 #define EXIT_COMMONERROR 0x80000000
43
44 // ----------
45 // - BmpSum -
46 // ----------
47
48 class BmpSum
49 {
50 private:
51
52 sal_uInt32 cExitCode;
53
54 sal_Bool GetCommandOption( const ::std::vector< String >& rArgs, const String& rSwitch, String& rSwitchParam );
55 sal_Bool GetCommandOptions( const ::std::vector< String >& rArgs, const String& rSwitch, ::std::vector< String >& rSwitchParams );
56
SetExitCode(sal_uInt8 cExit)57 void SetExitCode( sal_uInt8 cExit )
58 {
59 if( ( EXIT_NOERROR == cExitCode ) || ( cExit != EXIT_NOERROR ) )
60 cExitCode = cExit;
61 }
62 void ShowUsage();
63 void Message( const String& rText, sal_uInt8 cExitCode );
64
65 sal_uInt64 GetCRC( const BitmapEx& rBmpEx );
66
67 void ProcessFile( const String& rBmpFileName );
68 void ProcessFileList( const String& rInFileList, const String& rOutFileList, const String& rOutPath );
69
70 public:
71 //
72 BmpSum();
73 ~BmpSum();
74
75 int Start( const ::std::vector< String >& rArgs );
76 };
77
78 // -----------------------------------------------------------------------------
79
BmpSum()80 BmpSum::BmpSum()
81 {
82 }
83
84 // -----------------------------------------------------------------------------
85
~BmpSum()86 BmpSum::~BmpSum()
87 {
88 }
89
90 // -----------------------------------------------------------------------
91
GetCommandOption(const::std::vector<String> & rArgs,const String & rSwitch,String & rParam)92 sal_Bool BmpSum::GetCommandOption( const ::std::vector< String >& rArgs, const String& rSwitch, String& rParam )
93 {
94 sal_Bool bRet = sal_False;
95
96 for( int i = 0, nCount = rArgs.size(); ( i < nCount ) && !bRet; i++ )
97 {
98 String aTestStr( '-' );
99
100 for( int n = 0; ( n < 2 ) && !bRet; n++ )
101 {
102 aTestStr += rSwitch;
103
104 if( aTestStr.CompareIgnoreCaseToAscii( rArgs[ i ] ) == COMPARE_EQUAL )
105 {
106 bRet = sal_True;
107
108 if( i < ( nCount - 1 ) )
109 rParam = rArgs[ i + 1 ];
110 else
111 rParam = String();
112 }
113
114 if( 0 == n )
115 aTestStr = '/';
116 }
117 }
118
119 return bRet;
120 }
121
122 // -----------------------------------------------------------------------
123
GetCommandOptions(const::std::vector<String> & rArgs,const String & rSwitch,::std::vector<String> & rParams)124 sal_Bool BmpSum::GetCommandOptions( const ::std::vector< String >& rArgs, const String& rSwitch, ::std::vector< String >& rParams )
125 {
126 sal_Bool bRet = sal_False;
127
128 for( int i = 0, nCount = rArgs.size(); ( i < nCount ); i++ )
129 {
130 String aTestStr( '-' );
131
132 for( int n = 0; ( n < 2 ) && !bRet; n++ )
133 {
134 aTestStr += rSwitch;
135
136 if( aTestStr.CompareIgnoreCaseToAscii( rArgs[ i ] ) == COMPARE_EQUAL )
137 {
138 if( i < ( nCount - 1 ) )
139 rParams.push_back( rArgs[ i + 1 ] );
140 else
141 rParams.push_back( String() );
142
143 break;
144 }
145
146 if( 0 == n )
147 aTestStr = '/';
148 }
149 }
150
151 return( rParams.size() > 0 );
152 }
153
154 // -----------------------------------------------------------------------
155
Message(const String & rText,sal_uInt8 nExitCode)156 void BmpSum::Message( const String& rText, sal_uInt8 nExitCode )
157 {
158 if( EXIT_NOERROR != nExitCode )
159 SetExitCode( nExitCode );
160
161 ByteString aText( rText, RTL_TEXTENCODING_UTF8 );
162 aText.Append( "\r\n" );
163 fprintf( stderr, aText.GetBuffer() );
164 }
165
166 // -----------------------------------------------------------------------------
167
ShowUsage()168 void BmpSum::ShowUsage()
169 {
170 Message( String( RTL_CONSTASCII_USTRINGPARAM( "Usage:" ) ), EXIT_NOERROR );
171 Message( String( RTL_CONSTASCII_USTRINGPARAM( " bmpsum bmp_inputfile" ) ), EXIT_NOERROR );
172 Message( String( RTL_CONSTASCII_USTRINGPARAM( " bmpsum -i input_filelist -o output_filelist [-p path_for_copied_bitmaps]" ) ), EXIT_NOERROR );
173 Message( String( RTL_CONSTASCII_USTRINGPARAM( "Options:" ) ), EXIT_NOERROR );
174 Message( String( RTL_CONSTASCII_USTRINGPARAM( "Examples:" ) ), EXIT_NOERROR );
175 Message( String( RTL_CONSTASCII_USTRINGPARAM( " bmpsum /home/test.bmp" ) ), EXIT_NOERROR );
176 Message( String( RTL_CONSTASCII_USTRINGPARAM( " bmpsum -i /home/inlist.txt -o /home/outlist.txt" ) ), EXIT_NOERROR );
177 Message( String( RTL_CONSTASCII_USTRINGPARAM( " bmpsum -i /home/inlist.txt -o /home/outlist.txt -p /home/outpath" ) ), EXIT_NOERROR );
178 }
179
180 // -----------------------------------------------------------------------------
181
Start(const::std::vector<String> & rArgs)182 int BmpSum::Start( const ::std::vector< String >& rArgs )
183 {
184 cExitCode = EXIT_NOERROR;
185
186 if( rArgs.size() >= 1 )
187 {
188 String aInFileList, aOutFileList, aOutPath;
189
190 if( GetCommandOption( rArgs, 'i', aInFileList ) &&
191 GetCommandOption( rArgs, 'o', aOutFileList ) )
192 {
193 GetCommandOption( rArgs, 'p', aOutPath );
194 ProcessFileList( aInFileList, aOutFileList, aOutPath );
195 }
196 else
197 {
198 ProcessFile( rArgs[ 0 ] );
199 }
200 }
201 else
202 {
203 ShowUsage();
204 cExitCode = EXIT_COMMONERROR;
205 }
206
207 return cExitCode;
208 }
209
210 // -----------------------------------------------------------------------------
211
GetCRC(const BitmapEx & rBmpEx)212 sal_uInt64 BmpSum::GetCRC( const BitmapEx& rBmpEx )
213 {
214 Bitmap aBmp( rBmpEx.GetBitmap() );
215 BitmapReadAccess* pRAcc = aBmp.AcquireReadAccess();
216 AlphaMask aAlpha;
217 BitmapReadAccess* pAAcc = NULL;
218 sal_uInt64 nRet = 0;
219 sal_uInt32 nCrc = 0;
220
221 if( rBmpEx.IsTransparent() )
222 {
223 aAlpha = rBmpEx.GetAlpha();
224 pAAcc = aAlpha.AcquireReadAccess();
225 }
226
227 if( pRAcc && pRAcc->Width() && pRAcc->Height() )
228 {
229 SVBT32 aBT32;
230
231 for( long nY = 0; nY < pRAcc->Height(); ++nY )
232 {
233 for( long nX = 0; nX < pRAcc->Width(); ++nX )
234 {
235 const BitmapColor aCol( pRAcc->GetColor( nY, nX ) );
236
237 UInt32ToSVBT32( aCol.GetRed(), aBT32 );
238 nCrc = rtl_crc32( nCrc, aBT32, 4 );
239
240 UInt32ToSVBT32( aCol.GetGreen(), aBT32 );
241 nCrc = rtl_crc32( nCrc, aBT32, 4 );
242
243 UInt32ToSVBT32( aCol.GetBlue(), aBT32 );
244 nCrc = rtl_crc32( nCrc, aBT32, 4 );
245
246 if( pAAcc )
247 {
248 const BitmapColor aMaskCol( pAAcc->GetColor( nY, nX ) );
249
250 UInt32ToSVBT32( aMaskCol.GetRed(), aBT32 );
251 nCrc = rtl_crc32( nCrc, aBT32, 4 );
252
253 UInt32ToSVBT32( aMaskCol.GetGreen(), aBT32 );
254 nCrc = rtl_crc32( nCrc, aBT32, 4 );
255
256 UInt32ToSVBT32( aMaskCol.GetBlue(), aBT32 );
257 nCrc = rtl_crc32( nCrc, aBT32, 4 );
258 }
259 }
260 }
261
262 nRet = ( ( (sal_uInt64) pRAcc->Width() ) << 48 ) |
263 ( ( (sal_uInt64) pRAcc->Height() ) << 32 ) |
264 ( (sal_uInt64) nCrc );
265 }
266
267 if( pAAcc )
268 aAlpha.ReleaseAccess( pAAcc);
269
270 aBmp.ReleaseAccess( pRAcc );
271
272 return nRet;
273 }
274
275 // -----------------------------------------------------------------------------
276
ProcessFile(const String & rBmpFileName)277 void BmpSum::ProcessFile( const String& rBmpFileName )
278 {
279 SvFileStream aIStm( rBmpFileName, STREAM_READ );
280
281 if( aIStm.IsOpen() )
282 {
283 BitmapEx aBmpEx;
284
285 ReadDIBBitmapEx(aBmpEx, aIStm);
286
287 if( !aBmpEx.IsEmpty() )
288 {
289 fprintf( stdout, "%" SAL_PRIuUINT64 "\r\n", GetCRC( aBmpEx ) );
290 }
291 else
292 {
293 aIStm.ResetError();
294 aIStm.Seek( 0 );
295
296 ::vcl::PNGReader aPngReader( aIStm );
297
298 aBmpEx = aPngReader.Read();
299
300 if( !aBmpEx.IsEmpty() )
301 {
302 fprintf( stdout, "%" SAL_PRIuUINT64 "\r\n", GetCRC( aBmpEx ) );
303 }
304 else
305 Message( String( RTL_CONSTASCII_USTRINGPARAM( "file not valid" ) ), EXIT_INVALIDFILE );
306 }
307 }
308 }
309
310 // -----------------------------------------------------------------------------
311
ProcessFileList(const String & rInFileList,const String & rOutFileList,const String & rOutPath)312 void BmpSum::ProcessFileList( const String& rInFileList,
313 const String& rOutFileList,
314 const String& rOutPath )
315 {
316 SvFileStream aIStm( rInFileList, STREAM_READ );
317 SvFileStream aOStm( rOutFileList, STREAM_WRITE | STREAM_TRUNC );
318 const DirEntry aBaseDir( rOutPath );
319
320 if( rOutPath.Len() )
321 aBaseDir.MakeDir();
322
323 if( aIStm.IsOpen() && aOStm.IsOpen() )
324 {
325 ByteString aReadLine;
326 ::std::set< ByteString > aFileNameSet;
327
328 while( aIStm.ReadLine( aReadLine ) )
329 {
330 if( aReadLine.Len() )
331 aFileNameSet.insert( aReadLine );
332
333 if( aReadLine.Search( "enus" ) != STRING_NOTFOUND )
334 {
335 static const char* aLanguages[] =
336 {
337 "chinsim",
338 "chintrad",
339 "dtch",
340 "enus",
341 "fren",
342 "hebrew"
343 "ital",
344 "japn",
345 "korean",
346 "pol",
347 "poln",
348 "port",
349 "russ",
350 "span",
351 "turk"
352 };
353
354 for( sal_uInt32 n = 0; n < 14; ++n )
355 {
356 ByteString aLangPath( aReadLine );
357
358 aLangPath.SearchAndReplace( "enus", aLanguages[ n ] );
359
360 DirEntry aTestFile( aLangPath );
361
362 if( aTestFile.Exists() )
363 aFileNameSet.insert( aLangPath );
364 }
365 }
366
367 aReadLine.Erase();
368 }
369
370 aIStm.Close();
371
372 ::std::set< ByteString >::iterator aIter( aFileNameSet.begin() );
373 ::std::map< sal_uInt64, ::std::vector< ByteString > > aFileNameMap;
374
375 while( aIter != aFileNameSet.end() )
376 {
377 ByteString aStr( *aIter++ );
378 SvFileStream aBmpStm( String( aStr.GetBuffer(), RTL_TEXTENCODING_ASCII_US ), STREAM_READ );
379 sal_uInt64 nCRC = 0;
380
381 if( aBmpStm.IsOpen() )
382 {
383 BitmapEx aBmpEx;
384
385 ReadDIBBitmapEx(aBmpEx, aBmpStm);
386
387 if( !aBmpEx.IsEmpty() )
388 nCRC = GetCRC( aBmpEx );
389 else
390 {
391 aBmpStm.ResetError();
392 aBmpStm.Seek( 0 );
393
394 ::vcl::PNGReader aPngReader( aBmpStm );
395
396 aBmpEx = aPngReader.Read();
397
398 if( !aBmpEx.IsEmpty() )
399 nCRC = GetCRC( aBmpEx );
400
401 else
402 fprintf( stderr, "%s could not be opened\n", aStr.GetBuffer() );
403 }
404
405 aBmpStm.Close();
406 }
407
408 if( nCRC )
409 {
410 ::std::map< sal_uInt64, ::std::vector< ByteString > >::iterator aFound( aFileNameMap.find( nCRC ) );
411
412 if( aFound != aFileNameMap.end() )
413 (*aFound).second.push_back( aStr );
414 else
415 {
416 ::std::vector< ByteString > aVector( 1, aStr );
417 aFileNameMap[ nCRC ] = aVector;
418 }
419
420 }
421 else
422 {
423 ::std::vector< ByteString > aVector( 1, aStr );
424 aFileNameMap[ nCRC ] = aVector;
425 }
426 }
427
428 ::std::map< sal_uInt64, ::std::vector< ByteString > >::iterator aMapIter( aFileNameMap.begin() );
429 sal_uInt32 nFileCount = 0;
430
431 while( aMapIter != aFileNameMap.end() )
432 {
433 ::std::pair< const sal_uInt64, ::std::vector< ByteString > > aPair( *aMapIter++ );
434 ::std::vector< ByteString > aFileNameVector( aPair.second );
435
436 // write new entries
437 for( sal_uInt32 i = 0; i < aFileNameVector.size(); ++i )
438 {
439 ByteString aStr( ByteString::CreateFromInt64( aPair.first ) );
440 ByteString aFileName( aFileNameVector[ i ] );
441 DirEntry aSrcFile( aFileName );
442
443 aStr += '\t';
444 aStr += aFileName;
445
446 aOStm.WriteLine( aStr );
447
448 // copy bitmap
449 if( rOutPath.Len() )
450 {
451 if( aFileName.Search( ":\\" ) != STRING_NOTFOUND )
452 aFileName.Erase( 0, aFileName.Search( ":\\" ) + 2 );
453
454 aFileName.SearchAndReplaceAll( '\\', '/' );
455
456 sal_uInt16 nTokenCount = aFileName.GetTokenCount( '/' );
457 DirEntry aNewDir( aBaseDir );
458
459 for( sal_uInt16 n = 0; ( n < nTokenCount - 1 ); n++ )
460 {
461 aNewDir += DirEntry( aFileName.GetToken( n, '/' ) );
462 aNewDir.MakeDir();
463 }
464
465 aNewDir += DirEntry( aFileName.GetToken( nTokenCount - 1, '/' ) );
466 aSrcFile.CopyTo( aNewDir, FSYS_ACTION_COPYFILE );
467 }
468 }
469
470 ++nFileCount;
471 }
472
473 fprintf(
474 stdout, "unique file count: %lu",
475 sal::static_int_cast< unsigned long >(nFileCount) );
476 }
477 }
478
479 // --------
480 // - Main -
481 // --------
482
main(int nArgCount,char * ppArgs[])483 int main( int nArgCount, char* ppArgs[] )
484 {
485 #ifdef UNX
486 static char aDisplayVar[ 1024 ];
487
488 strcpy( aDisplayVar, "DISPLAY=" );
489 putenv( aDisplayVar );
490 #endif
491
492 ::std::vector< String > aArgs;
493 BmpSum aBmpSum;
494
495 InitVCL( com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory >() );
496
497 for( int i = 1; i < nArgCount; i++ )
498 aArgs.push_back( String( ppArgs[ i ], RTL_TEXTENCODING_ASCII_US ) );
499
500 return aBmpSum.Start( aArgs );
501 }
502