bump product version to 4.1.6.2
[LibreOffice.git] / l10ntools / source / merge.cxx
blobfab9e6ed5246aba41753c22d92457bc3f4a4851b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "sal/config.h"
22 #include <algorithm>
23 #include <fstream>
24 #include <string>
25 #include <vector>
27 #include "export.hxx"
28 #include "po.hxx"
30 namespace
32 static OString lcl_NormalizeFilename(const OString& rFilename)
34 return rFilename.copy(
35 std::max(
36 rFilename.lastIndexOf( '\\' ),
37 rFilename.lastIndexOf( '/' ))+1);
40 static bool lcl_ReadPoChecked(
41 PoEntry& o_rPoEntry, PoIfstream& rPoFile,
42 const OString& rFileName)
44 try
46 rPoFile.readEntry( o_rPoEntry );
48 catch( PoIfstream::Exception& aException )
50 if( aException == PoIfstream::INVALIDENTRY )
52 printf(
53 "Warning : %s contains invalid entry\n",
54 rFileName.getStr() );
55 return false;
58 return true;
63 // class ResData
66 ResData::ResData( const OString &rGId )
68 nIdLevel( ID_LEVEL_NULL ),
69 bChild( sal_False ),
70 bChildWithText( sal_False ),
71 bText( sal_False ),
72 bHelpText( sal_False ),
73 bQuickHelpText( sal_False ),
74 bTitle( sal_False ),
75 bList( sal_False ),
76 sGId( rGId ),
77 sTextTyp( "Text" ),
78 pStringList( NULL ),
79 pUIEntries( NULL ),
80 pItemList( NULL ),
81 pFilterList( NULL ),
82 pPairedList( NULL )
84 sGId = sGId.replaceAll("\r", OString());
87 ResData::ResData( const OString &rGId, const OString &rFilename)
89 nIdLevel( ID_LEVEL_NULL ),
90 bChild( sal_False ),
91 bChildWithText( sal_False ),
92 bText( sal_False ),
93 bHelpText( sal_False ),
94 bQuickHelpText( sal_False ),
95 bTitle( sal_False ),
96 bList( sal_False ),
97 sGId( rGId ),
98 sFilename( rFilename ),
99 sTextTyp( "Text" ),
100 pStringList( NULL ),
101 pUIEntries( NULL ),
102 pItemList( NULL ),
103 pFilterList( NULL ),
104 pPairedList( NULL )
106 sGId = sGId.replaceAll("\r", OString());
110 ResData::~ResData()
112 if ( pStringList ) {
113 // delete existing res. of type StringList
114 for ( size_t i = 0; i < pStringList->size(); i++ ) {
115 ExportListEntry* test = (*pStringList)[ i ];
116 if( test != NULL ) delete test;
118 delete pStringList;
120 if ( pFilterList ) {
121 // delete existing res. of type FilterList
122 for ( size_t i = 0; i < pFilterList->size(); i++ ) {
123 ExportListEntry* test = (*pFilterList)[ i ];
124 delete test;
126 delete pFilterList;
128 if ( pItemList ) {
129 // delete existing res. of type ItemList
130 for ( size_t i = 0; i < pItemList->size(); i++ ) {
131 ExportListEntry* test = (*pItemList)[ i ];
132 delete test;
134 delete pItemList;
136 if ( pUIEntries ) {
137 // delete existing res. of type UIEntries
138 for ( size_t i = 0; i < pUIEntries->size(); i++ ) {
139 ExportListEntry* test = (*pUIEntries)[ i ];
140 delete test;
142 delete pUIEntries;
147 // class MergeEntrys
150 sal_Bool MergeEntrys::GetText( OString &rReturn,
151 sal_uInt16 nTyp, const OString &nLangIndex, sal_Bool bDel )
154 sal_Bool bReturn=sal_True;
155 switch ( nTyp ) {
156 case STRING_TYP_TEXT :
157 rReturn = sText[ nLangIndex ];
158 if ( bDel )
159 sText[ nLangIndex ] = "";
160 bReturn = bTextFirst[ nLangIndex ];
161 bTextFirst[ nLangIndex ] = sal_False;
162 break;
163 case STRING_TYP_QUICKHELPTEXT :
164 rReturn = sQuickHelpText[ nLangIndex ];
165 if ( bDel )
166 sQuickHelpText[ nLangIndex ] = "";
167 bReturn = bQuickHelpTextFirst[ nLangIndex ];
168 bQuickHelpTextFirst[ nLangIndex ] = sal_False;
169 break;
170 case STRING_TYP_TITLE :
171 rReturn = sTitle[ nLangIndex ];
172 if ( bDel )
173 sTitle[ nLangIndex ] = "";
174 bReturn = bTitleFirst[ nLangIndex ];
175 bTitleFirst[ nLangIndex ] = sal_False;
176 break;
178 return bReturn;
182 OString MergeEntrys::GetQTZText(const ResData& rResData, const OString& rOrigText)
184 const OString sFilename = rResData.sFilename.copy(rResData.sFilename.lastIndexOf("/")+1);
185 const OString sKey =
186 PoEntry::genKeyId(sFilename + rResData.sGId + rResData.sId + rResData.sResTyp + rOrigText);
187 return sKey + "||" + rOrigText;
191 // class MergeDataHashMap
194 std::pair<MergeDataHashMap::iterator,bool> MergeDataHashMap::insert(const OString& rKey, MergeData* pMergeData)
196 std::pair<iterator,bool> aTemp = m_aHashMap.insert(HashMap_t::value_type( rKey, pMergeData ));
197 if( m_aHashMap.size() == 1 )
199 // When first insert, set an iterator to the first element
200 aFirstInOrder = aTemp.first;
202 else
204 // Define insertion order by setting an iterator to the next element.
205 aLastInsertion->second->m_aNextData = aTemp.first;
207 aLastInsertion = aTemp.first;
208 return aTemp;
211 MergeDataHashMap::iterator MergeDataHashMap::find(const OString& rKey)
213 iterator aHint = m_aHashMap.end();
215 // Add a hint
216 if( bFirstSearch && !m_aHashMap.empty() )
218 aHint = aFirstInOrder;
220 else if( aLastFound == aLastInsertion )
222 // Next to the last element is the first element
223 aHint = aFirstInOrder;
225 else if( aLastFound != m_aHashMap.end() && aLastFound != aLastInsertion )
227 aHint = aLastFound->second->m_aNextData;
230 // If hint works than no need for search
231 if( aHint != m_aHashMap.end() && aHint->first == rKey )
233 aLastFound = aHint;
235 else
237 aLastFound = m_aHashMap.find(rKey);
240 bFirstSearch = false;
241 return aLastFound;
245 // class MergeData
248 MergeData::MergeData(
249 const OString &rTyp, const OString &rGID,
250 const OString &rLID , const OString &rFilename )
251 : sTyp( rTyp ),
252 sGID( rGID ),
253 sLID( rLID ) ,
254 sFilename( rFilename ),
255 pMergeEntrys( new MergeEntrys() )
259 MergeData::~MergeData()
261 delete pMergeEntrys;
264 MergeEntrys* MergeData::GetMergeEntries()
266 return pMergeEntrys;
269 sal_Bool MergeData::operator==( ResData *pData )
271 return pData->sId == sLID && pData->sGId == sGID
272 && pData->sResTyp.equalsIgnoreAsciiCase(sTyp);
276 // class MergeDataFile
279 MergeDataFile::MergeDataFile(
280 const OString &rFileName, const OString &rFile,
281 bool bCaseSensitive, bool bWithQtz )
283 std::ifstream aInputStream( rFileName.getStr() );
284 if ( !aInputStream.is_open() )
286 printf("Warning : Can't open po path container file\n");
287 return;
289 std::string sPoFile;
290 aInputStream >> sPoFile;
291 bool bFirstLang = true;
292 while( !aInputStream.eof() )
294 bool bSkipCurrentPOFile = false;
295 const OString sFileName( lcl_NormalizeFilename(rFile) );
296 const bool bReadAll = sFileName.isEmpty();
297 const OString sPoFileName(sPoFile.data(), sPoFile.length());
298 PoIfstream aPoInput;
299 aPoInput.open( sPoFileName );
300 if ( !aPoInput.isOpen() )
302 printf( "Warning : Can't open %s\n", sPoFileName.getStr() );
303 return;
306 OString sLang;
307 //Get language id from path
309 const OString sTransSource("translations/source/");
310 const sal_Int32 nStart =
311 sPoFileName.indexOf(sTransSource)+sTransSource.getLength();
312 const sal_Int32 nCount =
313 sPoFileName.indexOf("/",nStart) - nStart;
314 sLang = sPoFileName.copy(nStart,nCount);
316 aLanguageSet.insert( sLang );
317 PoEntry aNextPo;
320 if( !lcl_ReadPoChecked(aNextPo, aPoInput, sPoFileName) )
322 bSkipCurrentPOFile = true;
323 break;
325 } while( !aPoInput.eof() && aNextPo.getSourceFile() != sFileName && !bReadAll );
326 while( !aPoInput.eof() && (aNextPo.getSourceFile() == sFileName || bReadAll ) && !bSkipCurrentPOFile )
328 PoEntry aActPo( aNextPo );
330 bool bInSameComp = false;
331 OString sText;
332 OString sQHText;
333 OString sTitle;
334 OString sExText;
335 OString sExQHText;
336 OString sExTitle;
339 if( bInSameComp )
340 aActPo = aNextPo;
341 OString sTemp = aActPo.getMsgStr();
342 if( aActPo.isFuzzy() || sTemp.isEmpty() )
343 sTemp = aActPo.getMsgId();
344 switch( aActPo.getType() )
346 case PoEntry::TTEXT:
347 sText = sTemp;
348 sExText = aActPo.getMsgId();
349 break;
350 case PoEntry::TQUICKHELPTEXT:
351 sQHText = sTemp;
352 sExQHText = aActPo.getMsgId();
353 break;
354 case PoEntry::TTITLE:
355 sTitle = sTemp;
356 sExTitle = aActPo.getMsgId();
357 break;
359 if( !lcl_ReadPoChecked(aNextPo, aPoInput, sPoFileName) )
361 bSkipCurrentPOFile = true;
362 break;
364 } while( !aPoInput.eof() &&
365 ( bInSameComp = PoEntry::IsInSameComp(aActPo, aNextPo) ) );
367 InsertEntry(
368 aActPo.getResourceType(), aActPo.getGroupId(),
369 aActPo.getLocalId(), sLang, sText,
370 sQHText, sTitle, aActPo.getSourceFile(),
371 bFirstLang, bCaseSensitive );
373 if( bFirstLang && bWithQtz &&
374 ( strcmp(getenv("ENABLE_RELEASE_BUILD"),"TRUE") ) )
376 aLanguageSet.insert("qtz");
377 InsertEntry(
378 aActPo.getResourceType(), aActPo.getGroupId(),
379 aActPo.getLocalId(), "qtz",
380 sExText, sExQHText,
381 sExTitle, aActPo.getSourceFile(),
382 false, bCaseSensitive );
385 aPoInput.close();
386 aInputStream >> sPoFile;
387 bFirstLang = false;
389 aInputStream.close();
392 MergeDataFile::~MergeDataFile()
394 for (MergeDataHashMap::iterator aI = aMap.begin(), aEnd = aMap.end(); aI != aEnd; ++aI)
395 delete aI->second;
398 std::vector<OString> MergeDataFile::GetLanguages() const
400 return std::vector<OString>(aLanguageSet.begin(),aLanguageSet.end());
403 MergeData *MergeDataFile::GetMergeData( ResData *pResData , bool bCaseSensitive )
405 OString sOldG = pResData->sGId;
406 OString sOldL = pResData->sId;
407 OString sGID = pResData->sGId;
408 OString sLID;
409 if (sGID.isEmpty())
410 sGID = pResData->sId;
411 else
412 sLID = pResData->sId;
413 pResData->sGId = sGID;
414 pResData->sId = sLID;
416 OString sKey = CreateKey( pResData->sResTyp , pResData->sGId , pResData->sId , pResData->sFilename , bCaseSensitive );
418 MergeDataHashMap::const_iterator mit = aMap.find( sKey );
419 if(mit != aMap.end())
421 pResData->sGId = sOldG;
422 pResData->sId = sOldL;
423 return mit->second;
425 pResData->sGId = sOldG;
426 pResData->sId = sOldL;
427 return NULL;
430 MergeEntrys *MergeDataFile::GetMergeEntrys( ResData *pResData )
432 // search for requested MergeEntrys
433 MergeData *pData = GetMergeData( pResData );
434 if ( pData )
435 return pData->GetMergeEntries();
436 return NULL;
439 MergeEntrys *MergeDataFile::GetMergeEntrysCaseSensitive( ResData *pResData )
441 // search for requested MergeEntrys
442 MergeData *pData = GetMergeData( pResData , true );
443 if ( pData )
444 return pData->GetMergeEntries();
445 return NULL;
448 void MergeDataFile::InsertEntry(
449 const OString &rTYP, const OString &rGID,
450 const OString &rLID, const OString &nLANG,
451 const OString &rTEXT, const OString &rQHTEXT,
452 const OString &rTITLE, const OString &rInFilename,
453 bool bFirstLang, bool bCaseSensitive )
455 MergeData *pData = 0;
457 // search for MergeData
458 OString sKey = CreateKey(rTYP , rGID , rLID , rInFilename , bCaseSensitive);
460 if( !bFirstLang )
462 MergeDataHashMap::const_iterator mit = aMap.find( sKey );
463 if(mit != aMap.end())
464 pData = mit->second;
468 if( !pData )
470 pData = new MergeData( rTYP, rGID, rLID, rInFilename );
471 aMap.insert( sKey, pData );
475 // insert the cur string
476 MergeEntrys *pMergeEntrys = pData->GetMergeEntries();
477 if( nLANG =="qtz" )
479 const OString sTemp = rInFilename + rGID + rLID + rTYP;
480 pMergeEntrys->InsertEntry(
481 nLANG,
482 rTEXT.isEmpty()? rTEXT : PoEntry::genKeyId(sTemp + rTEXT) + "||" + rTEXT,
483 rQHTEXT.isEmpty()? rQHTEXT : PoEntry::genKeyId(sTemp + rQHTEXT) + "||" + rQHTEXT,
484 rTITLE.isEmpty()? rTITLE : PoEntry::genKeyId(sTemp + rTITLE) + "||" + rTITLE );
486 else
488 pMergeEntrys->InsertEntry( nLANG , rTEXT, rQHTEXT, rTITLE );
492 OString MergeDataFile::CreateKey(const OString& rTYP, const OString& rGID,
493 const OString& rLID, const OString& rFilename, bool bCaseSensitive)
495 static const OString sStroke('-');
496 OString sKey( rTYP );
497 sKey += sStroke;
498 sKey += rGID;
499 sKey += sStroke;
500 sKey += rLID;
501 sKey += sStroke;
502 sKey += lcl_NormalizeFilename(rFilename);
503 OSL_TRACE("created key: %s", sKey.getStr());
504 if(bCaseSensitive)
505 return sKey; // officecfg case sensitive identifier
506 return sKey.toAsciiUpperCase();
509 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */