bump product version to 4.1.6.2
[LibreOffice.git] / rsc / source / parser / rscdb.cxx
blob7c975e09e28113e66754344fe5bb3d264573b3af
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> // isdigit(), isalpha()
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 )
43 nSourceCharSet( RTL_TEXTENCODING_UTF8 ),
44 nByteOrder( nOrder ),
45 aSearchPath( rSearchPath ),
46 aBool( pHS->getID( "sal_Bool" ), RSC_NOTYPE ),
47 aShort( pHS->getID( "short" ), RSC_NOTYPE ),
48 aUShort( pHS->getID( "sal_uInt16" ), RSC_NOTYPE ),
49 aLong( pHS->getID( "long" ), RSC_NOTYPE ),
50 aEnumLong( pHS->getID( "enum_long" ), RSC_NOTYPE ),
51 aIdUShort( pHS->getID( "IDUSHORT" ), RSC_NOTYPE ),
52 aIdNoZeroUShort( pHS->getID( "IDUSHORT" ), RSC_NOTYPE ),
53 aNoZeroShort( pHS->getID( "NoZeroShort" ), RSC_NOTYPE ),
54 a1to12Short( pHS->getID( "MonthShort" ), RSC_NOTYPE ),
55 a0to23Short( pHS->getID( "HourShort" ), RSC_NOTYPE ),
56 a1to31Short( pHS->getID( "DayShort" ), RSC_NOTYPE ),
57 a0to59Short( pHS->getID( "MinuteShort" ), RSC_NOTYPE ),
58 a0to99Short( pHS->getID( "_0to59Short" ), RSC_NOTYPE ),
59 a0to9999Short( pHS->getID( "YearShort" ), RSC_NOTYPE ),
60 aIdLong( pHS->getID( "IDLONG" ), RSC_NOTYPE ),
61 aString( pHS->getID( "Chars" ), RSC_NOTYPE ),
62 aStringLiteral( pHS->getID( "Chars" ), RSC_NOTYPE ),
63 aWinBits( pHS->getID( "WinBits" ), RSC_NOTYPE ),
64 aLangType(),
65 aLangString( pHS->getID( "Lang_Chars" ), RSC_NOTYPE, &aString, &aLangType ),
66 aLangShort( pHS->getID( "Lang_short" ), RSC_NOTYPE, &aShort, &aLangType ),
67 nAcceleratorType( 0 ),
68 nFlags( nFlagsP )
70 nUniqueId = 256;
71 nPMId = RSC_VERSIONCONTROL +1; //mindestens einen groesser
72 pEH = pErrHdl;
73 Init();
76 OString RscTypCont::ChangeLanguage(const OString& rNewLang)
78 OString aRet = aLanguage;
79 aLanguage = rNewLang;
81 ::std::vector< OUString > aFallbacks;
82 if (rNewLang.isEmpty())
83 aFallbacks.push_back( "" ); // do not resolve to SYSTEM (en-US)
84 else
85 aFallbacks = LanguageTag( OStringToOUString( rNewLang, RTL_TEXTENCODING_ASCII_US)).getFallbackStrings();
86 bool bAppendEnUsFallback =
87 ! (rNewLang.equalsIgnoreAsciiCase( "en-US" ) ||
88 rNewLang.equalsIgnoreAsciiCase( "x-no-translate" ) );
89 if (bAppendEnUsFallback)
90 aFallbacks.push_back( "en-US");
92 #if OSL_DEBUG_LEVEL > 1
93 fprintf( stderr, "RscTypCont::ChangeLanguage: " );
94 #endif
96 aLangFallbacks.clear();
98 for (::std::vector< OUString >::const_iterator it( aFallbacks.begin()); it != aFallbacks.end(); ++it)
100 OString aLang( OUStringToOString( *it, RTL_TEXTENCODING_ASCII_US));
101 sal_uInt32 nID = GetLangId( aLang );
102 bool bAdd = (nID == 0);
103 if ( bAdd )
105 AddLanguage( aLang.getStr() );
106 nID = GetLangId( aLang );
108 #if OSL_DEBUG_LEVEL > 1
109 fprintf( stderr, " '%s' (0x%hx) (%s)", aLang.getStr(), (int)nID, (bAdd ? "added" : "exists") );
110 #endif
111 aLangFallbacks.push_back( nID);
114 #if OSL_DEBUG_LEVEL > 1
115 fprintf( stderr, "\n" );
116 #endif
118 return aRet;
121 Atom RscTypCont::AddLanguage( const char* pLang )
123 return aLangType.AddLanguage( pLang, aNmTb );
127 void DestroyNode( RscTop * pRscTop, ObjNode * pObjNode ){
128 if( pObjNode ){
129 DestroyNode( pRscTop, (ObjNode*)pObjNode->Left() );
130 DestroyNode( pRscTop, (ObjNode*)pObjNode->Right() );
132 if( pObjNode->GetRscObj() ){
133 pRscTop->Destroy( RSCINST( pRscTop, pObjNode->GetRscObj() ) );
134 rtl_freeMemory( pObjNode->GetRscObj() );
136 delete pObjNode;
140 void DestroySubTrees( RscTop * pRscTop ){
141 if( pRscTop ){
142 DestroySubTrees( (RscTop*)pRscTop->Left() );
144 DestroyNode( pRscTop, pRscTop->GetObjNode() );
146 DestroySubTrees( (RscTop*)pRscTop->Right() );
150 void DestroyTree( RscTop * pRscTop ){
151 if( pRscTop ){
152 DestroyTree( (RscTop*)pRscTop->Left() );
153 DestroyTree( (RscTop*)pRscTop->Right() );
155 delete pRscTop;
159 void Pre_dtorTree( RscTop * pRscTop ){
160 if( pRscTop ){
161 Pre_dtorTree( (RscTop*)pRscTop->Left() );
162 Pre_dtorTree( (RscTop*)pRscTop->Right() );
164 pRscTop->Pre_dtor();
168 RscTypCont :: ~RscTypCont(){
169 // Alle Unterbaeume loeschen
170 aVersion.pClass->Destroy( aVersion );
171 rtl_freeMemory( aVersion.pData );
172 DestroySubTrees( pRoot );
174 // Alle Klassen noch gueltig, jeweilige Instanzen freigeben
175 // BasisTypen
176 for ( size_t i = 0, n = aBaseLst.size(); i < n; ++i )
177 aBaseLst[ i ]->Pre_dtor();
178 aBool.Pre_dtor();
179 aShort.Pre_dtor();
180 aUShort.Pre_dtor();
181 aIdUShort.Pre_dtor();
182 aIdNoZeroUShort.Pre_dtor();
183 aNoZeroShort.Pre_dtor();
184 aIdLong.Pre_dtor();
185 aString.Pre_dtor();
186 aWinBits.Pre_dtor();
187 aVersion.pClass->Pre_dtor();
188 // Zusammengesetzte Typen
189 Pre_dtorTree( pRoot );
191 // Klassen zerstoeren
192 delete aVersion.pClass;
193 DestroyTree( pRoot );
195 for ( size_t i = 0, n = aBaseLst.size(); i < n; ++i )
196 delete aBaseLst[ i ];
197 aBaseLst.clear();
199 for ( size_t i = 0, n = aSysLst.size(); i < n; ++i )
200 delete aSysLst[ i ];
201 aSysLst.clear();
204 void RscTypCont::ClearSysNames()
206 for ( size_t i = 0, n = aSysLst.size(); i < n; ++i )
207 delete aSysLst[ i ];
208 aSysLst.clear();
211 RscTop * RscTypCont::SearchType( Atom nId )
212 /* [Beschreibung]
214 Sucht eine Basistyp nId;
217 if( nId == InvalidAtom )
218 return NULL;
220 #define ELSE_IF( a ) \
221 else if( a.GetId() == nId ) \
222 return &a; \
224 if( aBool.GetId() == nId )
225 return &aBool;
226 ELSE_IF( aShort )
227 ELSE_IF( aUShort )
228 ELSE_IF( aLong )
229 ELSE_IF( aEnumLong )
230 ELSE_IF( aIdUShort )
231 ELSE_IF( aIdNoZeroUShort )
232 ELSE_IF( aNoZeroShort )
233 ELSE_IF( a1to12Short )
234 ELSE_IF( a0to23Short )
235 ELSE_IF( a1to31Short )
236 ELSE_IF( a0to59Short )
237 ELSE_IF( a0to99Short )
238 ELSE_IF( a0to9999Short )
239 ELSE_IF( aIdLong )
240 ELSE_IF( aString )
241 ELSE_IF( aWinBits )
242 ELSE_IF( aLangType )
243 ELSE_IF( aLangString )
244 ELSE_IF( aLangShort )
246 for ( size_t i = 0, n = aBaseLst.size(); i < n; ++i )
248 RscTop* pEle = aBaseLst[ i ];
249 if( pEle->GetId() == nId )
250 return pEle;
252 return NULL;
255 sal_uInt32 RscTypCont :: PutSysName( sal_uInt32 nRscTyp, char * pFileName,
256 sal_uInt32 nConst, sal_uInt32 nId, sal_Bool bFirst )
258 RscSysEntry *pSysEntry;
259 RscSysEntry *pFoundEntry = NULL;
260 sal_Bool bId1 = sal_False;
262 for ( size_t i = 0, n = aSysLst.size(); i < n; ++i )
264 pSysEntry = aSysLst[ i ];
265 if( pSysEntry->nKey == 1 )
266 bId1 = sal_True;
267 if( !strcmp( pSysEntry->aFileName.getStr(), pFileName ) )
268 if( pSysEntry->nRscTyp == nRscTyp
269 && pSysEntry->nTyp == nConst
270 && pSysEntry->nRefId == nId
272 pFoundEntry = pSysEntry;
273 break;
276 pSysEntry = pFoundEntry;
278 if ( !pSysEntry || (bFirst && !bId1) )
280 pSysEntry = new RscSysEntry;
281 pSysEntry->nKey = nUniqueId++;
282 pSysEntry->nRscTyp = nRscTyp;
283 pSysEntry->nTyp = nConst;
284 pSysEntry->nRefId = nId;
285 pSysEntry->aFileName = (const char*)pFileName;
286 if( bFirst && !bId1 )
288 pSysEntry->nKey = 1;
289 aSysLst.insert( aSysLst.begin(), pSysEntry );
291 else
292 aSysLst.push_back( pSysEntry );
295 return pSysEntry->nKey;
298 void RscTypCont :: WriteInc( FILE * fOutput, sal_uLong lFileKey )
301 if( NOFILE_INDEX == lFileKey )
303 sal_uIntPtr aIndex = aFileTab.FirstIndex();
304 while( aIndex != UNIQUEINDEX_ENTRY_NOTFOUND )
306 RscFile * pFName = aFileTab.Get( aIndex );
307 if( pFName->IsIncFile() )
309 fprintf( fOutput, "#include " );
310 fprintf( fOutput, "\"%s\"\n",
311 pFName->aFileName.getStr() );
313 aIndex = aFileTab.NextIndex( aIndex );
316 else
318 RscDepend * pDep;
319 RscFile * pFile;
321 RscFile * pFName = aFileTab.Get( lFileKey );
322 if( pFName )
324 for ( size_t i = 0, n = pFName->aDepLst.size(); i < n; ++i )
326 pDep = pFName->aDepLst[ i ];
327 if( pDep->GetFileKey() != lFileKey )
329 pFile = aFileTab.GetFile( pDep->GetFileKey() );
330 if( pFile )
332 fprintf( fOutput, "#include " );
333 fprintf( fOutput, "\"%s\"\n",
334 pFile->aFileName.getStr() );
343 class RscEnumerateObj
345 friend class RscEnumerateRef;
346 private:
347 ERRTYPE aError; // Enthaelt den ersten Fehler
348 RscTypCont* pTypCont;
349 FILE * fOutput; // AusgabeDatei
350 sal_uLong lFileKey; // Welche src-Datei
351 RscTop * pClass;
353 DECL_LINK( CallBackWriteRc, ObjNode * );
354 DECL_LINK( CallBackWriteSrc, ObjNode * );
356 ERRTYPE WriteRc( RscTop * pCl, ObjNode * pRoot )
358 pClass = pCl;
359 if( pRoot )
360 pRoot->EnumNodes( LINK( this, RscEnumerateObj, CallBackWriteRc ) );
361 return aError;
363 ERRTYPE WriteSrc( RscTop * pCl, ObjNode * pRoot ){
364 pClass = pCl;
365 if( pRoot )
366 pRoot->EnumNodes( LINK( this, RscEnumerateObj, CallBackWriteSrc ) );
367 return aError;
369 public:
370 void WriteRcFile( RscWriteRc & rMem, FILE * fOutput );
373 IMPL_LINK( RscEnumerateObj, CallBackWriteRc, ObjNode *, pObjNode )
375 RscWriteRc aMem( pTypCont->GetByteOrder() );
377 aError = pClass->WriteRcHeader( RSCINST( pClass, pObjNode->GetRscObj() ),
378 aMem, pTypCont,
379 pObjNode->GetRscId(), 0, sal_True );
380 if( aError.IsError() || aError.IsWarning() )
381 pTypCont->pEH->Error( aError, pClass, pObjNode->GetRscId() );
383 WriteRcFile( aMem, fOutput );
384 return 0;
387 IMPL_LINK_INLINE_START( RscEnumerateObj, CallBackWriteSrc, ObjNode *, pObjNode )
389 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;
397 IMPL_LINK_INLINE_END( RscEnumerateObj, CallBackWriteSrc, ObjNode *, pObjNode )
399 void RscEnumerateObj :: WriteRcFile( RscWriteRc & rMem, FILE * fOut )
401 // Definition der Struktur, aus denen die Resource aufgebaut ist
403 struct RSHEADER_TYPE{
404 sal_uInt32 nId; // Identifier der Resource
405 sal_uInt32 nRT; // Resource Typ
406 sal_uInt32 nGlobOff; // Globaler Offset
407 sal_uInt32 nLocalOff; // Lokaler Offset
408 } aHeader;
411 sal_uInt32 nId = rMem.GetLong( 0 );
412 sal_uInt32 nRT = rMem.GetLong( 4 );
414 // Tabelle wird entsprechend gefuellt
415 pTypCont->PutTranslatorKey( (sal_uInt64(nRT) << 32) + sal_uInt64(nId) );
417 if( nRT == RSC_VERSIONCONTROL )
418 { // kommt immmer als letztes
419 sal_Int32 nCount = pTypCont->aIdTranslator.size();
420 // groesse der Tabelle
421 sal_uInt32 nSize = (nCount * (sizeof(sal_uInt64)+sizeof(sal_Int32))) + sizeof(sal_Int32);
423 rMem.Put( nCount ); //Anzahl speichern
424 for( std::map< sal_uInt64, sal_uLong >::const_iterator it =
425 pTypCont->aIdTranslator.begin(); it != pTypCont->aIdTranslator.end(); ++it )
427 // Schluessel schreiben
428 rMem.Put( it->first );
429 // Objekt Id oder Position schreiben
430 rMem.Put( (sal_Int32)it->second );
432 rMem.Put( nSize ); // Groesse hinten Speichern
435 //Dateioffset neu setzen
436 pTypCont->IncFilePos( rMem.Size() );
439 //Position wurde vorher in Tabelle geschrieben
440 bool bSuccess = (1 == fwrite( rMem.GetBuffer(), rMem.Size(), 1, fOut ));
441 SAL_WARN_IF(!bSuccess, "rsc", "short write");
444 class RscEnumerateRef
446 private:
447 RscTop * pRoot;
449 DECL_LINK( CallBackWriteRc, RscTop * );
450 DECL_LINK( CallBackWriteSrc, RscTop * );
451 public:
452 RscEnumerateObj aEnumObj;
454 RscEnumerateRef( RscTypCont * pTC, RscTop * pR,
455 FILE * fOutput )
457 aEnumObj.pTypCont = pTC;
458 aEnumObj.fOutput = fOutput;
459 pRoot = pR;
461 ERRTYPE WriteRc()
463 aEnumObj.aError.Clear();
464 pRoot->EnumNodes( LINK( this, RscEnumerateRef, CallBackWriteRc ) );
465 return aEnumObj.aError;
468 ERRTYPE WriteSrc( sal_uLong lFileKey )
470 aEnumObj.lFileKey = lFileKey;
472 aEnumObj.aError.Clear();
473 pRoot->EnumNodes( LINK( this, RscEnumerateRef, CallBackWriteSrc ) );
474 return aEnumObj.aError;
478 IMPL_LINK_INLINE_START( RscEnumerateRef, CallBackWriteRc, RscTop *, pRef )
480 aEnumObj.WriteRc( pRef, pRef->GetObjNode() );
481 return 0;
483 IMPL_LINK_INLINE_END( RscEnumerateRef, CallBackWriteRc, RscTop *, pRef )
484 IMPL_LINK_INLINE_START( RscEnumerateRef, CallBackWriteSrc, RscTop *, pRef )
486 aEnumObj.WriteSrc( pRef, pRef->GetObjNode() );
487 return 0;
489 IMPL_LINK_INLINE_END( RscEnumerateRef, CallBackWriteSrc, RscTop *, pRef )
492 ERRTYPE RscTypCont::WriteRc( WriteRcContext& rContext )
494 ERRTYPE aError;
495 RscEnumerateRef aEnumRef( this, pRoot, rContext.fOutput );
497 aIdTranslator.clear();
498 nFilePos = 0;
499 nPMId = RSCVERSION_ID +1; //mindestens einen groesser
501 aError = aEnumRef.WriteRc();
503 // version control
504 RscWriteRc aMem( nByteOrder );
505 aVersion.pClass->WriteRcHeader( aVersion, aMem, this, RscId( RSCVERSION_ID ), 0, sal_True );
506 aEnumRef.aEnumObj.WriteRcFile( aMem, rContext.fOutput );
508 return aError;
511 void RscTypCont :: WriteSrc( FILE * fOutput, sal_uLong nFileKey,
512 sal_Bool bName )
514 RscFile * pFName;
515 RscEnumerateRef aEnumRef( this, pRoot, fOutput );
517 unsigned char aUTF8BOM[3] = { 0xef, 0xbb, 0xbf };
518 size_t nItems = SAL_N_ELEMENTS(aUTF8BOM);
519 bool bSuccess = (nItems == fwrite(aUTF8BOM, 1, nItems, fOutput));
520 SAL_WARN_IF(!bSuccess, "rsc", "short write");
521 if( bName )
523 WriteInc( fOutput, nFileKey );
525 if( NOFILE_INDEX == nFileKey )
527 sal_uIntPtr aIndex = aFileTab.FirstIndex();
528 while( aIndex != UNIQUEINDEX_ENTRY_NOTFOUND ) {
529 pFName = aFileTab.Get( aIndex );
530 if( !pFName->IsIncFile() )
531 pFName->aDefLst.WriteAll( fOutput );
532 aEnumRef.WriteSrc( aIndex );
533 aIndex = aFileTab.NextIndex( aIndex );
536 else
538 pFName = aFileTab.Get( nFileKey );
539 if( pFName ){
540 pFName->aDefLst.WriteAll( fOutput );
541 aEnumRef.WriteSrc( nFileKey );
545 else
547 RscId::SetNames( sal_False );
548 if( NOFILE_INDEX == nFileKey )
550 sal_uIntPtr aIndex = aFileTab.FirstIndex();
551 while( aIndex != UNIQUEINDEX_ENTRY_NOTFOUND )
553 aEnumRef.WriteSrc( aIndex );
554 aIndex = aFileTab.NextIndex( aIndex );
557 else
558 aEnumRef.WriteSrc( nFileKey );
559 RscId::SetNames();
563 class RscDel
565 sal_uLong lFileKey;
566 DECL_LINK( Delete, RscTop * );
567 public:
568 RscDel( RscTop * pRoot, sal_uLong lKey );
572 inline RscDel::RscDel( RscTop * pRoot, sal_uLong lKey )
574 lFileKey = lKey;
575 pRoot->EnumNodes( LINK( this, RscDel, Delete ) );
578 IMPL_LINK_INLINE_START( RscDel, Delete, RscTop *, pNode )
580 if( pNode->GetObjNode() )
581 pNode->pObjBiTree = pNode->GetObjNode()->DelObjNode( pNode, lFileKey );
582 return 0;
584 IMPL_LINK_INLINE_END( RscDel, Delete, RscTop *, pNode )
586 void RscTypCont :: Delete( sal_uLong lFileKey ){
587 // Resourceinstanzen loeschen
588 RscDel aDel( pRoot, lFileKey );
589 // Defines loeschen
590 aFileTab.DeleteFileContext( lFileKey );
593 sal_Bool IsInstConsistent( ObjNode * pObjNode, RscTop * pRscTop )
595 sal_Bool bRet = sal_True;
597 if( pObjNode ){
598 RSCINST aTmpI;
600 if( ! IsInstConsistent( (ObjNode*)pObjNode->Left(), pRscTop ) )
601 bRet = sal_False;
603 aTmpI.pClass = pRscTop;
604 aTmpI.pData = pObjNode->GetRscObj();
605 if( ! aTmpI.pClass->IsConsistent( aTmpI ) )
606 bRet = sal_False;
608 if( ! IsInstConsistent( (ObjNode*)pObjNode->Right(), pRscTop ) )
609 bRet = sal_False;
612 return( bRet );
615 sal_Bool MakeConsistent( RscTop * pRscTop )
617 sal_Bool bRet = sal_True;
619 if( pRscTop ){
620 if( ! ::MakeConsistent( (RscTop*)pRscTop->Left() ) )
621 bRet = sal_False;
623 if( pRscTop->GetObjNode() ){
624 if( ! pRscTop->GetObjNode()->IsConsistent() ){
625 pRscTop->GetObjNode()->OrderTree();
626 if( ! pRscTop->GetObjNode()->IsConsistent() )
627 bRet = sal_False;
629 if( ! IsInstConsistent( pRscTop->GetObjNode(), pRscTop ) )
630 bRet = sal_False;
633 if( ! ::MakeConsistent( (RscTop*)pRscTop->Right() ) )
634 bRet = sal_False;
637 return bRet;
640 sal_uInt32 RscTypCont::PutTranslatorKey( sal_uInt64 nKey )
642 aIdTranslator[ nKey ] = nFilePos;
643 return nPMId++;
646 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */