bump product version to 5.0.4.1
[LibreOffice.git] / rsc / source / parser / rscdb.cxx
blobde6844f0fc712548d2f58b13ffdc1e5cc4c49f72
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 <ctype.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
25 #include <tools/rc.h>
26 #include <i18nlangtag/languagetag.hxx>
27 #include <rtl/strbuf.hxx>
28 #include <sal/log.hxx>
29 #include <sal/macros.h>
31 #include <rsctree.hxx>
32 #include <rsctop.hxx>
33 #include <rscmgr.hxx>
34 #include <rscdb.hxx>
35 #include <rscrsc.hxx>
38 RscTypCont :: RscTypCont( RscError * pErrHdl,
39 RSCBYTEORDER_TYPE nOrder,
40 const OString& rSearchPath,
41 sal_uInt32 nFlagsP )
42 : nSourceCharSet( RTL_TEXTENCODING_UTF8 )
43 , nByteOrder( nOrder )
44 , aSearchPath( rSearchPath )
45 , aBool( pHS->getID( "sal_Bool" ), RSC_NOTYPE )
46 , aShort( pHS->getID( "short" ), RSC_NOTYPE )
47 , aUShort( pHS->getID( "sal_uInt16" ), RSC_NOTYPE )
48 , aLong( pHS->getID( "long" ), RSC_NOTYPE )
49 , aEnumLong( pHS->getID( "enum_long" ), RSC_NOTYPE )
50 , aIdUShort( pHS->getID( "IDUSHORT" ), RSC_NOTYPE )
51 , aIdNoZeroUShort( pHS->getID( "IDUSHORT" ), RSC_NOTYPE )
52 , aNoZeroShort( pHS->getID( "NoZeroShort" ), RSC_NOTYPE )
53 , aIdLong( pHS->getID( "IDLONG" ), RSC_NOTYPE )
54 , aString( pHS->getID( "Chars" ), RSC_NOTYPE )
55 , aStringLiteral( pHS->getID( "Chars" ), RSC_NOTYPE )
56 , aWinBits( pHS->getID( "WinBits" ), RSC_NOTYPE )
57 , aLangType()
58 , aLangString( pHS->getID( "Lang_Chars" ), RSC_NOTYPE, &aString, &aLangType )
59 , aLangShort( pHS->getID( "Lang_short" ), RSC_NOTYPE, &aShort, &aLangType )
60 , nAcceleratorType( 0 )
61 , nFlags( nFlagsP )
63 nUniqueId = 256;
64 nPMId = RSC_VERSIONCONTROL +1; //mindestens einen groesser
65 pEH = pErrHdl;
66 Init();
69 OString RscTypCont::ChangeLanguage(const OString& rNewLang)
71 OString aRet = aLanguage;
72 aLanguage = rNewLang;
74 ::std::vector< OUString > aFallbacks;
76 if (rNewLang.isEmpty())
77 aFallbacks.push_back( "" ); // do not resolve to SYSTEM (en-US)
78 else
79 aFallbacks = LanguageTag( OStringToOUString( rNewLang, RTL_TEXTENCODING_ASCII_US)).getFallbackStrings( true);
81 bool bAppendEnUsFallback = ! (rNewLang.equalsIgnoreAsciiCase( "en-US" ) ||
82 rNewLang.equalsIgnoreAsciiCase( "x-no-translate" ) );
83 if (bAppendEnUsFallback)
84 aFallbacks.push_back( "en-US");
86 #if OSL_DEBUG_LEVEL > 1
87 fprintf( stderr, "RscTypCont::ChangeLanguage: " );
88 #endif
90 aLangFallbacks.clear();
92 for (::std::vector< OUString >::const_iterator it( aFallbacks.begin()); it != aFallbacks.end(); ++it)
94 OString aLang( OUStringToOString( *it, RTL_TEXTENCODING_ASCII_US));
95 sal_uInt32 nID = GetLangId( aLang );
96 bool bAdd = (nID == 0);
97 if ( bAdd )
99 AddLanguage( aLang.getStr() );
100 nID = GetLangId( aLang );
102 #if OSL_DEBUG_LEVEL > 1
103 fprintf( stderr, " '%s' (0x%hx) (%s)", aLang.getStr(), (int)nID, (bAdd ? "added" : "exists") );
104 #endif
105 aLangFallbacks.push_back( nID);
108 #if OSL_DEBUG_LEVEL > 1
109 fprintf( stderr, "\n" );
110 #endif
112 return aRet;
115 Atom RscTypCont::AddLanguage( const char* pLang )
117 return aLangType.AddLanguage( pLang, aNmTb );
121 void DestroyNode( RscTop * pRscTop, ObjNode * pObjNode )
123 if( pObjNode )
125 DestroyNode( pRscTop, static_cast<ObjNode*>(pObjNode->Left()) );
126 DestroyNode( pRscTop, static_cast<ObjNode*>(pObjNode->Right()) );
128 if( pObjNode->GetRscObj() )
130 pRscTop->Destroy( RSCINST( pRscTop, pObjNode->GetRscObj() ) );
131 rtl_freeMemory( pObjNode->GetRscObj() );
133 delete pObjNode;
137 void DestroySubTrees( RscTop * pRscTop )
139 if( pRscTop )
141 DestroySubTrees( static_cast<RscTop*>(pRscTop->Left()) );
142 DestroyNode( pRscTop, pRscTop->GetObjNode() );
143 DestroySubTrees( static_cast<RscTop*>(pRscTop->Right()) );
147 void DestroyTree( RscTop * pRscTop )
149 if( pRscTop )
151 DestroyTree( static_cast<RscTop*>(pRscTop->Left()) );
152 DestroyTree( static_cast<RscTop*>(pRscTop->Right()) );
154 delete pRscTop;
158 void Pre_dtorTree( RscTop * pRscTop )
160 if( pRscTop )
162 Pre_dtorTree( static_cast<RscTop*>(pRscTop->Left()) );
163 Pre_dtorTree( static_cast<RscTop*>(pRscTop->Right()) );
165 pRscTop->Pre_dtor();
169 RscTypCont :: ~RscTypCont()
171 // Alle Unterbaeume loeschen
172 aVersion.pClass->Destroy( aVersion );
173 rtl_freeMemory( aVersion.pData );
174 DestroySubTrees( pRoot );
176 // Alle Klassen noch gueltig, jeweilige Instanzen freigeben
177 // BasisTypen
178 for ( size_t i = 0, n = aBaseLst.size(); i < n; ++i )
179 aBaseLst[ i ]->Pre_dtor();
181 aBool.Pre_dtor();
182 aShort.Pre_dtor();
183 aUShort.Pre_dtor();
184 aIdUShort.Pre_dtor();
185 aIdNoZeroUShort.Pre_dtor();
186 aNoZeroShort.Pre_dtor();
187 aIdLong.Pre_dtor();
188 aString.Pre_dtor();
189 aWinBits.Pre_dtor();
190 aVersion.pClass->Pre_dtor();
191 // Zusammengesetzte Typen
192 Pre_dtorTree( pRoot );
194 // Klassen zerstoeren
195 delete aVersion.pClass;
196 DestroyTree( pRoot );
198 for ( size_t i = 0, n = aBaseLst.size(); i < n; ++i )
199 delete aBaseLst[ i ];
201 aBaseLst.clear();
203 for ( size_t i = 0, n = aSysLst.size(); i < n; ++i )
204 delete aSysLst[ i ];
206 aSysLst.clear();
209 void RscTypCont::ClearSysNames()
211 for ( size_t i = 0, n = aSysLst.size(); i < n; ++i )
212 delete aSysLst[ i ];
214 aSysLst.clear();
217 RscTop * RscTypCont::SearchType( Atom nId )
219 /* [Beschreibung]
221 Sucht eine Basistyp nId;
223 if( nId == InvalidAtom )
224 return NULL;
226 #define ELSE_IF( a ) \
227 else if( a.GetId() == nId ) \
228 return &a; \
230 if( aBool.GetId() == nId )
231 return &aBool;
232 ELSE_IF( aShort )
233 ELSE_IF( aUShort )
234 ELSE_IF( aLong )
235 ELSE_IF( aEnumLong )
236 ELSE_IF( aIdUShort )
237 ELSE_IF( aIdNoZeroUShort )
238 ELSE_IF( aNoZeroShort )
239 ELSE_IF( aIdLong )
240 ELSE_IF( aString )
241 ELSE_IF( aWinBits )
242 ELSE_IF( aLangType )
243 ELSE_IF( aLangString )
244 ELSE_IF( aLangShort )
245 // al least to not pollute
246 #undef ELSE_IF
248 for ( size_t i = 0, n = aBaseLst.size(); i < n; ++i )
250 RscTop* pEle = aBaseLst[ i ];
251 if( pEle->GetId() == nId )
252 return pEle;
254 return NULL;
257 sal_uInt32 RscTypCont :: PutSysName( sal_uInt32 nRscTyp, char * pFileName,
258 sal_uInt32 nConst, sal_uInt32 nId, bool bFirst )
260 RscSysEntry *pSysEntry;
261 RscSysEntry *pFoundEntry = NULL;
262 bool bId1 = false;
264 for ( size_t i = 0, n = aSysLst.size(); i < n; ++i )
266 pSysEntry = aSysLst[ i ];
267 if( pSysEntry->nKey == 1 )
268 bId1 = true;
269 if( !strcmp( pSysEntry->aFileName.getStr(), pFileName ) )
270 if( pSysEntry->nRscTyp == nRscTyp &&
271 pSysEntry->nTyp == nConst &&
272 pSysEntry->nRefId == nId)
274 pFoundEntry = pSysEntry;
275 break;
278 pSysEntry = pFoundEntry;
280 if ( !pSysEntry || (bFirst && !bId1) )
282 pSysEntry = new RscSysEntry;
283 pSysEntry->nKey = nUniqueId++;
284 pSysEntry->nRscTyp = nRscTyp;
285 pSysEntry->nTyp = nConst;
286 pSysEntry->nRefId = nId;
287 pSysEntry->aFileName = (const char*)pFileName;
288 if( bFirst && !bId1 )
290 pSysEntry->nKey = 1;
291 aSysLst.insert( aSysLst.begin(), pSysEntry );
293 else
294 aSysLst.push_back( pSysEntry );
297 return pSysEntry->nKey;
300 void RscTypCont :: WriteInc( FILE * fOutput, sal_uLong lFileKey )
303 if( NOFILE_INDEX == lFileKey )
305 sal_uIntPtr aIndex = aFileTab.FirstIndex();
306 while( aIndex != UNIQUEINDEX_ENTRY_NOTFOUND )
308 RscFile * pFName = aFileTab.Get( aIndex );
309 if( pFName->IsIncFile() )
311 fprintf( fOutput, "#include " );
312 fprintf( fOutput, "\"%s\"\n",
313 pFName->aFileName.getStr() );
315 aIndex = aFileTab.NextIndex( aIndex );
318 else
320 RscFile * pFName = aFileTab.Get( lFileKey );
321 if( pFName )
323 for ( size_t i = 0, n = pFName->aDepLst.size(); i < n; ++i )
325 RscDepend* pDep = pFName->aDepLst[ i ];
326 if( pDep->GetFileKey() != lFileKey )
328 RscFile* pFile = aFileTab.GetFile( pDep->GetFileKey() );
329 if( pFile )
331 fprintf( fOutput, "#include " );
332 fprintf( fOutput, "\"%s\"\n",
333 pFile->aFileName.getStr() );
342 class RscEnumerateObj
344 friend class RscEnumerateRef;
345 private:
346 ERRTYPE aError; // Enthaelt den ersten Fehler
347 RscTypCont* pTypCont;
348 FILE * fOutput; // AusgabeDatei
349 sal_uLong lFileKey; // Welche src-Datei
350 RscTop * pClass;
352 DECL_LINK( CallBackWriteRc, ObjNode * );
353 DECL_LINK( CallBackWriteSrc, ObjNode * );
355 ERRTYPE WriteRc( RscTop * pCl, ObjNode * pRoot )
357 pClass = pCl;
358 if( pRoot )
359 pRoot->EnumNodes( LINK( this, RscEnumerateObj, CallBackWriteRc ) );
360 return aError;
362 ERRTYPE WriteSrc( RscTop * pCl, ObjNode * pRoot ){
363 pClass = pCl;
364 if( pRoot )
365 pRoot->EnumNodes( LINK( this, RscEnumerateObj, CallBackWriteSrc ) );
366 return aError;
368 public:
369 void WriteRcFile( RscWriteRc & rMem, FILE * fOutput );
372 IMPL_LINK( RscEnumerateObj, CallBackWriteRc, ObjNode *, pObjNode )
374 RscWriteRc aMem( pTypCont->GetByteOrder() );
376 aError = pClass->WriteRcHeader( RSCINST( pClass, pObjNode->GetRscObj() ),
377 aMem, pTypCont,
378 pObjNode->GetRscId(), 0, true );
379 if( aError.IsError() || aError.IsWarning() )
380 pTypCont->pEH->Error( aError, pClass, pObjNode->GetRscId() );
382 WriteRcFile( aMem, fOutput );
383 return 0;
386 IMPL_LINK( RscEnumerateObj, CallBackWriteSrc, ObjNode *, pObjNode )
388 if( pObjNode->GetFileKey() == lFileKey )
390 pClass->WriteSrcHeader( RSCINST( pClass, pObjNode->GetRscObj() ),
391 fOutput, pTypCont, 0,
392 pObjNode->GetRscId(), "" );
393 fprintf( fOutput, ";\n" );
395 return 0;
398 void RscEnumerateObj :: WriteRcFile( RscWriteRc & rMem, FILE * fOut )
400 // Definition der Struktur, aus denen die Resource aufgebaut ist
402 struct RSHEADER_TYPE{
403 sal_uInt32 nId; // Identifier der Resource
404 sal_uInt32 nRT; // Resource Typ
405 sal_uInt32 nGlobOff; // Globaler Offset
406 sal_uInt32 nLocalOff; // Lokaler Offset
407 } aHeader;
410 sal_uInt32 nId = rMem.GetLong( 0 );
411 sal_uInt32 nRT = rMem.GetLong( 4 );
413 // Tabelle wird entsprechend gefuellt
414 pTypCont->PutTranslatorKey( (sal_uInt64(nRT) << 32) + sal_uInt64(nId) );
416 if( nRT == RSC_VERSIONCONTROL )
417 { // kommt immmer als letztes
418 sal_Int32 nCount = pTypCont->aIdTranslator.size();
419 // groesse der Tabelle
420 sal_uInt32 nSize = (nCount * (sizeof(sal_uInt64)+sizeof(sal_Int32))) + sizeof(sal_Int32);
422 rMem.Put( nCount ); //Anzahl speichern
423 for( std::map< sal_uInt64, sal_uLong >::const_iterator it =
424 pTypCont->aIdTranslator.begin(); it != pTypCont->aIdTranslator.end(); ++it )
426 // Schluessel schreiben
427 rMem.Put( it->first );
428 // Objekt Id oder Position schreiben
429 rMem.Put( (sal_Int32)it->second );
431 rMem.Put( nSize ); // Groesse hinten Speichern
434 //Dateioffset neu setzen
435 pTypCont->IncFilePos( rMem.Size() );
438 //Position wurde vorher in Tabelle geschrieben
439 bool bSuccess = (1 == fwrite( rMem.GetBuffer(), rMem.Size(), 1, fOut ));
440 SAL_WARN_IF(!bSuccess, "rsc", "short write");
443 class RscEnumerateRef
445 private:
446 RscTop * pRoot;
448 DECL_LINK( CallBackWriteRc, RscTop * );
449 DECL_LINK( CallBackWriteSrc, RscTop * );
450 public:
451 RscEnumerateObj aEnumObj;
453 RscEnumerateRef( RscTypCont * pTC, RscTop * pR,
454 FILE * fOutput )
456 aEnumObj.pTypCont = pTC;
457 aEnumObj.fOutput = fOutput;
458 pRoot = pR;
460 ERRTYPE WriteRc()
462 aEnumObj.aError.Clear();
463 pRoot->EnumNodes( LINK( this, RscEnumerateRef, CallBackWriteRc ) );
464 return aEnumObj.aError;
466 ERRTYPE WriteSrc( sal_uLong lFileKey )
468 aEnumObj.lFileKey = lFileKey;
470 aEnumObj.aError.Clear();
471 pRoot->EnumNodes( LINK( this, RscEnumerateRef, CallBackWriteSrc ) );
472 return aEnumObj.aError;
476 IMPL_LINK( RscEnumerateRef, CallBackWriteRc, RscTop *, pRef )
478 aEnumObj.WriteRc( pRef, pRef->GetObjNode() );
479 return 0;
482 IMPL_LINK( RscEnumerateRef, CallBackWriteSrc, RscTop *, pRef )
484 aEnumObj.WriteSrc( pRef, pRef->GetObjNode() );
485 return 0;
488 ERRTYPE RscTypCont::WriteRc( WriteRcContext& rContext )
490 ERRTYPE aError;
491 RscEnumerateRef aEnumRef( this, pRoot, rContext.fOutput );
493 aIdTranslator.clear();
494 nFilePos = 0;
495 nPMId = RSCVERSION_ID +1; //mindestens einen groesser
497 aError = aEnumRef.WriteRc();
499 // version control
500 RscWriteRc aMem( nByteOrder );
501 aVersion.pClass->WriteRcHeader( aVersion, aMem, this, RscId( RSCVERSION_ID ), 0, true );
502 aEnumRef.aEnumObj.WriteRcFile( aMem, rContext.fOutput );
504 return aError;
507 void RscTypCont :: WriteSrc( FILE * fOutput, sal_uLong nFileKey,
508 bool bName )
510 RscEnumerateRef aEnumRef( this, pRoot, fOutput );
512 unsigned char aUTF8BOM[3] = { 0xef, 0xbb, 0xbf };
513 size_t nItems = SAL_N_ELEMENTS(aUTF8BOM);
514 bool bSuccess = (nItems == fwrite(aUTF8BOM, 1, nItems, fOutput));
515 SAL_WARN_IF(!bSuccess, "rsc", "short write");
516 if( bName )
518 RscFile* pFName;
519 WriteInc( fOutput, nFileKey );
521 if( NOFILE_INDEX == nFileKey )
523 sal_uIntPtr aIndex = aFileTab.FirstIndex();
524 while( aIndex != UNIQUEINDEX_ENTRY_NOTFOUND )
526 pFName = aFileTab.Get( aIndex );
527 if( !pFName->IsIncFile() )
528 pFName->aDefLst.WriteAll( fOutput );
529 aEnumRef.WriteSrc( aIndex );
530 aIndex = aFileTab.NextIndex( aIndex );
533 else
535 pFName = aFileTab.Get( nFileKey );
536 if( pFName )
538 pFName->aDefLst.WriteAll( fOutput );
539 aEnumRef.WriteSrc( nFileKey );
543 else
545 RscId::SetNames( false );
546 if( NOFILE_INDEX == nFileKey )
548 sal_uIntPtr aIndex = aFileTab.FirstIndex();
549 while( aIndex != UNIQUEINDEX_ENTRY_NOTFOUND )
551 aEnumRef.WriteSrc( aIndex );
552 aIndex = aFileTab.NextIndex( aIndex );
555 else
556 aEnumRef.WriteSrc( nFileKey );
557 RscId::SetNames();
561 class RscDel
563 sal_uLong lFileKey;
564 DECL_LINK( Delete, RscTop * );
565 public:
566 RscDel( RscTop * pRoot, sal_uLong lKey );
570 inline RscDel::RscDel( RscTop * pRoot, sal_uLong lKey )
572 lFileKey = lKey;
573 pRoot->EnumNodes( LINK( this, RscDel, Delete ) );
576 IMPL_LINK( RscDel, Delete, RscTop *, pNode )
578 if( pNode->GetObjNode() )
579 pNode->pObjBiTree = pNode->GetObjNode()->DelObjNode( pNode, lFileKey );
580 return 0;
583 void RscTypCont :: Delete( sal_uLong lFileKey )
585 // Resourceinstanzen loeschen
586 RscDel aDel( pRoot, lFileKey );
587 // Defines loeschen
588 aFileTab.DeleteFileContext( lFileKey );
591 bool IsInstConsistent( ObjNode * pObjNode, RscTop * pRscTop )
593 bool bRet = true;
595 if( pObjNode )
597 RSCINST aTmpI;
599 if( ! IsInstConsistent( static_cast<ObjNode*>(pObjNode->Left()), pRscTop ) )
600 bRet = false;
602 aTmpI.pClass = pRscTop;
603 aTmpI.pData = pObjNode->GetRscObj();
604 if( ! aTmpI.pClass->IsConsistent( aTmpI ) )
605 bRet = false;
607 if( ! IsInstConsistent( static_cast<ObjNode*>(pObjNode->Right()), pRscTop ) )
608 bRet = false;
611 return bRet;
614 bool MakeConsistent( RscTop * pRscTop )
616 bool bRet = true;
618 if( pRscTop )
620 if( ! ::MakeConsistent( static_cast<RscTop*>(pRscTop->Left()) ) )
621 bRet = false;
623 if( pRscTop->GetObjNode() )
625 if( ! pRscTop->GetObjNode()->IsConsistent() )
627 pRscTop->GetObjNode()->OrderTree();
628 if( ! pRscTop->GetObjNode()->IsConsistent() )
629 bRet = false;
631 if( ! IsInstConsistent( pRscTop->GetObjNode(), pRscTop ) )
632 bRet = false;
635 if( ! ::MakeConsistent( static_cast<RscTop*>(pRscTop->Right()) ) )
636 bRet = false;
639 return bRet;
642 sal_uInt32 RscTypCont::PutTranslatorKey( sal_uInt64 nKey )
644 aIdTranslator[ nKey ] = nFilePos;
645 return nPMId++;
648 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */