Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include <cstdio>
22 : #include <csignal>
23 : #include <vector>
24 : #include <set>
25 : #include <map>
26 :
27 : #include <comphelper/string.hxx>
28 : #include <rtl/crc.h>
29 : #include <rtl/strbuf.hxx>
30 : #include <tools/stream.hxx>
31 : #include <tools/fsys.hxx>
32 : #include <vcl/svapp.hxx>
33 : #include <vcl/bitmap.hxx>
34 : #include <vcl/bmpacc.hxx>
35 : #include <vcl/pngread.hxx>
36 :
37 : #include "svl/solar.hrc"
38 :
39 : #define EXIT_NOERROR 0x00000000
40 : #define EXIT_INVALIDFILE 0x00000001
41 : #define EXIT_COMMONERROR 0x80000000
42 :
43 : // ----------
44 : // - BmpSum -
45 : // ----------
46 :
47 : class BmpSum
48 : {
49 : private:
50 :
51 : sal_uInt32 cExitCode;
52 :
53 : sal_Bool GetCommandOption( const ::std::vector< String >& rArgs, const String& rSwitch, String& rSwitchParam );
54 :
55 0 : void SetExitCode( sal_uInt8 cExit )
56 : {
57 0 : if( ( EXIT_NOERROR == cExitCode ) || ( cExit != EXIT_NOERROR ) )
58 0 : cExitCode = cExit;
59 0 : }
60 : void ShowUsage();
61 : void Message( const String& rText, sal_uInt8 cExitCode );
62 :
63 : sal_uInt64 GetCRC( const BitmapEx& rBmpEx );
64 :
65 : void ProcessFile( const String& rBmpFileName );
66 : void ProcessFileList( const String& rInFileList, const String& rOutFileList, const String& rOutPath );
67 :
68 : public:
69 : //
70 : BmpSum();
71 : ~BmpSum();
72 :
73 : int Start( const ::std::vector< String >& rArgs );
74 : };
75 :
76 : // -----------------------------------------------------------------------------
77 :
78 0 : BmpSum::BmpSum()
79 : {
80 0 : }
81 :
82 : // -----------------------------------------------------------------------------
83 :
84 0 : BmpSum::~BmpSum()
85 : {
86 0 : }
87 :
88 : // -----------------------------------------------------------------------
89 :
90 0 : sal_Bool BmpSum::GetCommandOption( const ::std::vector< String >& rArgs, const String& rSwitch, String& rParam )
91 : {
92 0 : sal_Bool bRet = sal_False;
93 :
94 0 : for( int i = 0, nCount = rArgs.size(); ( i < nCount ) && !bRet; i++ )
95 : {
96 0 : rtl::OUString aTestStr( '-' );
97 :
98 0 : for( int n = 0; ( n < 2 ) && !bRet; n++ )
99 : {
100 0 : aTestStr += rSwitch;
101 :
102 0 : if( aTestStr.equalsIgnoreAsciiCase( rArgs[ i ] ) )
103 : {
104 0 : bRet = sal_True;
105 :
106 0 : if( i < ( nCount - 1 ) )
107 0 : rParam = rArgs[ i + 1 ];
108 : else
109 0 : rParam = String();
110 : }
111 :
112 0 : if( 0 == n )
113 0 : aTestStr = rtl::OUString('/');
114 : }
115 0 : }
116 :
117 0 : return bRet;
118 : }
119 :
120 : // -----------------------------------------------------------------------
121 :
122 0 : void BmpSum::Message( const String& rText, sal_uInt8 nExitCode )
123 : {
124 0 : if( EXIT_NOERROR != nExitCode )
125 0 : SetExitCode( nExitCode );
126 :
127 0 : rtl::OStringBuffer aText(rtl::OUStringToOString(rText, RTL_TEXTENCODING_UTF8));
128 0 : aText.append(RTL_CONSTASCII_STRINGPARAM("\r\n"));
129 0 : fprintf(stderr, "%s", aText.getStr());
130 0 : }
131 :
132 : // -----------------------------------------------------------------------------
133 :
134 0 : void BmpSum::ShowUsage()
135 : {
136 0 : Message( String( RTL_CONSTASCII_USTRINGPARAM( "Usage:" ) ), EXIT_NOERROR );
137 0 : Message( String( RTL_CONSTASCII_USTRINGPARAM( " bmpsum bmp_inputfile" ) ), EXIT_NOERROR );
138 0 : Message( String( RTL_CONSTASCII_USTRINGPARAM( " bmpsum -i input_filelist -o output_filelist [-p path_for_copied_bitmaps]" ) ), EXIT_NOERROR );
139 0 : Message( String( RTL_CONSTASCII_USTRINGPARAM( "Options:" ) ), EXIT_NOERROR );
140 0 : Message( String( RTL_CONSTASCII_USTRINGPARAM( "Examples:" ) ), EXIT_NOERROR );
141 0 : Message( String( RTL_CONSTASCII_USTRINGPARAM( " bmpsum /home/test.bmp" ) ), EXIT_NOERROR );
142 0 : Message( String( RTL_CONSTASCII_USTRINGPARAM( " bmpsum -i /home/inlist.txt -o /home/outlist.txt" ) ), EXIT_NOERROR );
143 0 : Message( String( RTL_CONSTASCII_USTRINGPARAM( " bmpsum -i /home/inlist.txt -o /home/outlist.txt -p /home/outpath" ) ), EXIT_NOERROR );
144 0 : }
145 :
146 : // -----------------------------------------------------------------------------
147 :
148 0 : int BmpSum::Start( const ::std::vector< String >& rArgs )
149 : {
150 0 : cExitCode = EXIT_NOERROR;
151 :
152 0 : if( rArgs.size() >= 1 )
153 : {
154 0 : String aInFileList, aOutFileList, aOutPath;
155 :
156 0 : if( GetCommandOption( rArgs, rtl::OUString('i'), aInFileList ) &&
157 0 : GetCommandOption( rArgs, rtl::OUString('o'), aOutFileList ) )
158 : {
159 0 : GetCommandOption( rArgs, rtl::OUString('p'), aOutPath );
160 0 : ProcessFileList( aInFileList, aOutFileList, aOutPath );
161 : }
162 : else
163 : {
164 0 : ProcessFile( rArgs[ 0 ] );
165 0 : }
166 : }
167 : else
168 : {
169 0 : ShowUsage();
170 0 : cExitCode = EXIT_COMMONERROR;
171 : }
172 :
173 0 : return cExitCode;
174 : }
175 :
176 : // -----------------------------------------------------------------------------
177 :
178 0 : sal_uInt64 BmpSum::GetCRC( const BitmapEx& rBmpEx )
179 : {
180 0 : Bitmap aBmp( rBmpEx.GetBitmap() );
181 0 : BitmapReadAccess* pRAcc = aBmp.AcquireReadAccess();
182 0 : AlphaMask aAlpha;
183 0 : BitmapReadAccess* pAAcc = NULL;
184 0 : sal_uInt64 nRet = 0;
185 :
186 0 : if( rBmpEx.IsTransparent() )
187 : {
188 0 : aAlpha = rBmpEx.GetAlpha();
189 0 : pAAcc = aAlpha.AcquireReadAccess();
190 : }
191 :
192 0 : if( pRAcc && pRAcc->Width() && pRAcc->Height() )
193 : {
194 : SVBT32 aBT32;
195 0 : sal_uInt32 nCrc = 0;
196 :
197 0 : for( long nY = 0; nY < pRAcc->Height(); ++nY )
198 : {
199 0 : for( long nX = 0; nX < pRAcc->Width(); ++nX )
200 : {
201 0 : const BitmapColor aCol( pRAcc->GetColor( nY, nX ) );
202 :
203 0 : UInt32ToSVBT32( aCol.GetRed(), aBT32 );
204 0 : nCrc = rtl_crc32( nCrc, aBT32, 4 );
205 :
206 0 : UInt32ToSVBT32( aCol.GetGreen(), aBT32 );
207 0 : nCrc = rtl_crc32( nCrc, aBT32, 4 );
208 :
209 0 : UInt32ToSVBT32( aCol.GetBlue(), aBT32 );
210 0 : nCrc = rtl_crc32( nCrc, aBT32, 4 );
211 :
212 0 : if( pAAcc )
213 : {
214 0 : const BitmapColor aMaskCol( pAAcc->GetColor( nY, nX ) );
215 :
216 0 : UInt32ToSVBT32( aMaskCol.GetRed(), aBT32 );
217 0 : nCrc = rtl_crc32( nCrc, aBT32, 4 );
218 :
219 0 : UInt32ToSVBT32( aMaskCol.GetGreen(), aBT32 );
220 0 : nCrc = rtl_crc32( nCrc, aBT32, 4 );
221 :
222 0 : UInt32ToSVBT32( aMaskCol.GetBlue(), aBT32 );
223 0 : nCrc = rtl_crc32( nCrc, aBT32, 4 );
224 : }
225 0 : }
226 : }
227 :
228 0 : nRet = ( ( (sal_uInt64) pRAcc->Width() ) << 48 ) |
229 0 : ( ( (sal_uInt64) pRAcc->Height() ) << 32 ) |
230 0 : ( (sal_uInt64) nCrc );
231 : }
232 :
233 0 : if( pAAcc )
234 0 : aAlpha.ReleaseAccess( pAAcc);
235 :
236 0 : aBmp.ReleaseAccess( pRAcc );
237 :
238 0 : return nRet;
239 : }
240 :
241 : // -----------------------------------------------------------------------------
242 :
243 0 : void BmpSum::ProcessFile( const String& rBmpFileName )
244 : {
245 0 : SvFileStream aIStm( rBmpFileName, STREAM_READ );
246 :
247 0 : if( aIStm.IsOpen() )
248 : {
249 0 : BitmapEx aBmpEx;
250 :
251 0 : aIStm >> aBmpEx;
252 :
253 0 : if( !aBmpEx.IsEmpty() )
254 : {
255 0 : fprintf( stdout, "%" SAL_PRIuUINT64 "\r\n", GetCRC( aBmpEx ) );
256 : }
257 : else
258 : {
259 0 : aIStm.ResetError();
260 0 : aIStm.Seek( 0 );
261 :
262 0 : ::vcl::PNGReader aPngReader( aIStm );
263 :
264 0 : aBmpEx = aPngReader.Read();
265 :
266 0 : if( !aBmpEx.IsEmpty() )
267 : {
268 0 : fprintf( stdout, "%" SAL_PRIuUINT64 "\r\n", GetCRC( aBmpEx ) );
269 : }
270 : else
271 0 : Message( String( RTL_CONSTASCII_USTRINGPARAM( "file not valid" ) ), EXIT_INVALIDFILE );
272 0 : }
273 0 : }
274 0 : }
275 :
276 : // -----------------------------------------------------------------------------
277 :
278 0 : void BmpSum::ProcessFileList( const String& rInFileList,
279 : const String& rOutFileList,
280 : const String& rOutPath )
281 : {
282 0 : SvFileStream aIStm( rInFileList, STREAM_READ );
283 0 : SvFileStream aOStm( rOutFileList, STREAM_WRITE | STREAM_TRUNC );
284 0 : const DirEntry aBaseDir( rOutPath );
285 :
286 0 : if( rOutPath.Len() )
287 0 : aBaseDir.MakeDir();
288 :
289 0 : if( aIStm.IsOpen() && aOStm.IsOpen() )
290 : {
291 0 : rtl::OString aReadLine;
292 0 : ::std::set<rtl::OString> aFileNameSet;
293 :
294 0 : while( aIStm.ReadLine( aReadLine ) )
295 : {
296 0 : if( !aReadLine.isEmpty() )
297 0 : aFileNameSet.insert( aReadLine );
298 :
299 0 : if( aReadLine.indexOfL(RTL_CONSTASCII_STRINGPARAM("enus") ) != -1 )
300 : {
301 : static const char* aLanguages[] =
302 : {
303 : "chinsim",
304 : "chintrad",
305 : "dtch",
306 : "enus",
307 : "fren",
308 : "hebrew"
309 : "ital",
310 : "japn",
311 : "korean",
312 : "pol",
313 : "poln",
314 : "port",
315 : "russ",
316 : "span",
317 : "turk"
318 : };
319 :
320 0 : for( sal_uInt32 n = 0; n < 14; ++n )
321 : {
322 : rtl::OString aLangPath(
323 : aReadLine.replaceAll(
324 : rtl::OString(RTL_CONSTASCII_STRINGPARAM("enus")),
325 0 : rtl::OString(aLanguages[n])));
326 :
327 0 : DirEntry aTestFile( aLangPath );
328 :
329 0 : if( aTestFile.Exists() )
330 0 : aFileNameSet.insert( aLangPath );
331 0 : }
332 : }
333 :
334 0 : aReadLine = rtl::OString();
335 : }
336 :
337 0 : aIStm.Close();
338 :
339 0 : ::std::set< rtl::OString >::iterator aIter( aFileNameSet.begin() );
340 0 : ::std::map< sal_uInt64, ::std::vector< rtl::OString > > aFileNameMap;
341 :
342 0 : while( aIter != aFileNameSet.end() )
343 : {
344 0 : rtl::OString aStr( *aIter++ );
345 0 : SvFileStream aBmpStm(rtl::OStringToOUString(aStr, RTL_TEXTENCODING_ASCII_US), STREAM_READ);
346 0 : sal_uInt64 nCRC = 0;
347 :
348 0 : if( aBmpStm.IsOpen() )
349 : {
350 0 : BitmapEx aBmpEx;
351 :
352 0 : aBmpStm >> aBmpEx;
353 :
354 0 : if( !aBmpEx.IsEmpty() )
355 0 : nCRC = GetCRC( aBmpEx );
356 : else
357 : {
358 0 : aBmpStm.ResetError();
359 0 : aBmpStm.Seek( 0 );
360 :
361 0 : ::vcl::PNGReader aPngReader( aBmpStm );
362 :
363 0 : aBmpEx = aPngReader.Read();
364 :
365 0 : if( !aBmpEx.IsEmpty() )
366 0 : nCRC = GetCRC( aBmpEx );
367 :
368 : else
369 0 : fprintf( stderr, "%s could not be opened\n", aStr.getStr() );
370 : }
371 :
372 0 : aBmpStm.Close();
373 : }
374 :
375 0 : if( nCRC )
376 : {
377 0 : ::std::map< sal_uInt64, ::std::vector< rtl::OString > >::iterator aFound( aFileNameMap.find( nCRC ) );
378 :
379 0 : if( aFound != aFileNameMap.end() )
380 0 : (*aFound).second.push_back( aStr );
381 : else
382 : {
383 0 : ::std::vector< rtl::OString > aVector( 1, aStr );
384 0 : aFileNameMap[ nCRC ] = aVector;
385 : }
386 :
387 : }
388 : else
389 : {
390 0 : ::std::vector< rtl::OString > aVector( 1, aStr );
391 0 : aFileNameMap[ nCRC ] = aVector;
392 : }
393 0 : }
394 :
395 0 : ::std::map< sal_uInt64, ::std::vector< rtl::OString > >::iterator aMapIter( aFileNameMap.begin() );
396 0 : sal_uInt32 nFileCount = 0;
397 :
398 0 : while( aMapIter != aFileNameMap.end() )
399 : {
400 0 : ::std::pair< const sal_uInt64, ::std::vector< rtl::OString > > aPair( *aMapIter++ );
401 0 : ::std::vector< rtl::OString > aFileNameVector( aPair.second );
402 :
403 : // write new entries
404 0 : for( sal_uInt32 i = 0; i < aFileNameVector.size(); ++i )
405 : {
406 0 : rtl::OString aFileName( aFileNameVector[ i ] );
407 0 : DirEntry aSrcFile( aFileName );
408 :
409 0 : rtl::OStringBuffer aStr;
410 0 : aStr.append(static_cast<sal_Int64>(aPair.first))
411 0 : .append('\t').append(aFileName);
412 0 : aOStm.WriteLine( aStr.makeStringAndClear() );
413 :
414 : // copy bitmap
415 0 : if( rOutPath.Len() )
416 : {
417 0 : sal_Int32 nIndex = aFileName.indexOf(":\\");
418 0 : if (nIndex != -1)
419 0 : aFileName = aFileName.copy(nIndex + 2);
420 :
421 0 : aFileName = aFileName.replace('\\', '/');
422 :
423 0 : sal_Int32 nTokenCount = comphelper::string::getTokenCount(aFileName, '/');
424 0 : DirEntry aNewDir( aBaseDir );
425 :
426 0 : for (sal_Int32 n = 0; ( n < nTokenCount - 1 ); ++n)
427 : {
428 0 : aNewDir += DirEntry( comphelper::string::getToken(aFileName, n, '/') );
429 0 : aNewDir.MakeDir();
430 : }
431 :
432 0 : aNewDir += DirEntry( comphelper::string::getToken(aFileName, nTokenCount - 1, '/') );
433 0 : aSrcFile.CopyTo( aNewDir, FSYS_ACTION_COPYFILE );
434 : }
435 0 : }
436 :
437 0 : ++nFileCount;
438 0 : }
439 :
440 : fprintf(
441 : stdout, "unique file count: %lu",
442 0 : sal::static_int_cast< unsigned long >(nFileCount) );
443 0 : }
444 0 : }
445 :
446 : // --------
447 : // - Main -
448 : // --------
449 :
450 0 : int main( int nArgCount, char* ppArgs[] )
451 : {
452 : #ifdef UNX
453 : static char aDisplayVar[ 1024 ];
454 :
455 0 : strcpy( aDisplayVar, "DISPLAY=" );
456 0 : putenv( aDisplayVar );
457 : #endif
458 :
459 0 : ::std::vector< String > aArgs;
460 0 : BmpSum aBmpSum;
461 :
462 0 : InitVCL();
463 :
464 0 : for( int i = 1; i < nArgCount; i++ )
465 0 : aArgs.push_back( String( ppArgs[ i ], RTL_TEXTENCODING_ASCII_US ) );
466 :
467 0 : return aBmpSum.Start( aArgs );
468 : }
469 :
470 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|