1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
26 #include <i18nlangtag/languagetag.hxx>
27 #include <rtl/strbuf.hxx>
28 #include <sal/log.hxx>
29 #include <sal/macros.h>
31 #include <rsctree.hxx>
38 RscTypCont :: RscTypCont( RscError
* pErrHdl
,
39 RSCBYTEORDER_TYPE nOrder
,
40 const OString
& rSearchPath
,
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
)
58 , aLangString( pHS
->getID( "Lang_Chars" ), RSC_NOTYPE
, &aString
, &aLangType
)
59 , aLangShort( pHS
->getID( "Lang_short" ), RSC_NOTYPE
, &aShort
, &aLangType
)
60 , nAcceleratorType( 0 )
64 nPMId
= RSC_VERSIONCONTROL
+1; //mindestens einen groesser
69 OString
RscTypCont::ChangeLanguage(const OString
& rNewLang
)
71 OString aRet
= aLanguage
;
74 ::std::vector
< OUString
> aFallbacks
;
76 if (rNewLang
.isEmpty())
77 aFallbacks
.push_back( "" ); // do not resolve to SYSTEM (en-US)
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: " );
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);
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") );
105 aLangFallbacks
.push_back( nID
);
108 #if OSL_DEBUG_LEVEL > 1
109 fprintf( stderr
, "\n" );
115 Atom
RscTypCont::AddLanguage( const char* pLang
)
117 return aLangType
.AddLanguage( pLang
, aNmTb
);
121 void DestroyNode( RscTop
* pRscTop
, ObjNode
* 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() );
137 void DestroySubTrees( RscTop
* 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
)
151 DestroyTree( static_cast<RscTop
*>(pRscTop
->Left()) );
152 DestroyTree( static_cast<RscTop
*>(pRscTop
->Right()) );
158 void Pre_dtorTree( RscTop
* pRscTop
)
162 Pre_dtorTree( static_cast<RscTop
*>(pRscTop
->Left()) );
163 Pre_dtorTree( static_cast<RscTop
*>(pRscTop
->Right()) );
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
178 for ( size_t i
= 0, n
= aBaseLst
.size(); i
< n
; ++i
)
179 aBaseLst
[ i
]->Pre_dtor();
184 aIdUShort
.Pre_dtor();
185 aIdNoZeroUShort
.Pre_dtor();
186 aNoZeroShort
.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
];
203 for ( size_t i
= 0, n
= aSysLst
.size(); i
< n
; ++i
)
209 void RscTypCont::ClearSysNames()
211 for ( size_t i
= 0, n
= aSysLst
.size(); i
< n
; ++i
)
217 RscTop
* RscTypCont::SearchType( Atom nId
)
221 Sucht eine Basistyp nId;
223 if( nId
== InvalidAtom
)
226 #define ELSE_IF( a ) \
227 else if( a.GetId() == nId ) \
230 if( aBool.GetId() == nId )
237 ELSE_IF( aIdNoZeroUShort
)
238 ELSE_IF( aNoZeroShort
)
243 ELSE_IF( aLangString
)
244 ELSE_IF( aLangShort
)
245 // al least to not pollute
248 for ( size_t i
= 0, n
= aBaseLst
.size(); i
< n
; ++i
)
250 RscTop
* pEle
= aBaseLst
[ i
];
251 if( pEle
->GetId() == nId
)
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
;
264 for ( size_t i
= 0, n
= aSysLst
.size(); i
< n
; ++i
)
266 pSysEntry
= aSysLst
[ i
];
267 if( pSysEntry
->nKey
== 1 )
269 if( !strcmp( pSysEntry
->aFileName
.getStr(), pFileName
) )
270 if( pSysEntry
->nRscTyp
== nRscTyp
&&
271 pSysEntry
->nTyp
== nConst
&&
272 pSysEntry
->nRefId
== nId
)
274 pFoundEntry
= pSysEntry
;
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
)
291 aSysLst
.insert( aSysLst
.begin(), pSysEntry
);
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
);
320 RscFile
* pFName
= aFileTab
.Get( lFileKey
);
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() );
331 fprintf( fOutput
, "#include " );
332 fprintf( fOutput
, "\"%s\"\n",
333 pFile
->aFileName
.getStr() );
342 class RscEnumerateObj
344 friend class RscEnumerateRef
;
346 ERRTYPE aError
; // Enthaelt den ersten Fehler
347 RscTypCont
* pTypCont
;
348 FILE * fOutput
; // AusgabeDatei
349 sal_uLong lFileKey
; // Welche src-Datei
352 DECL_LINK( CallBackWriteRc
, ObjNode
* );
353 DECL_LINK( CallBackWriteSrc
, ObjNode
* );
355 ERRTYPE
WriteRc( RscTop
* pCl
, ObjNode
* pRoot
)
359 pRoot
->EnumNodes( LINK( this, RscEnumerateObj
, CallBackWriteRc
) );
362 ERRTYPE
WriteSrc( RscTop
* pCl
, ObjNode
* pRoot
){
365 pRoot
->EnumNodes( LINK( this, RscEnumerateObj
, CallBackWriteSrc
) );
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() ),
378 pObjNode
->GetRscId(), 0, true );
379 if( aError
.IsError() || aError
.IsWarning() )
380 pTypCont
->pEH
->Error( aError
, pClass
, pObjNode
->GetRscId() );
382 WriteRcFile( aMem
, fOutput
);
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" );
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
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
448 DECL_LINK( CallBackWriteRc
, RscTop
* );
449 DECL_LINK( CallBackWriteSrc
, RscTop
* );
451 RscEnumerateObj aEnumObj
;
453 RscEnumerateRef( RscTypCont
* pTC
, RscTop
* pR
,
456 aEnumObj
.pTypCont
= pTC
;
457 aEnumObj
.fOutput
= fOutput
;
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() );
482 IMPL_LINK( RscEnumerateRef
, CallBackWriteSrc
, RscTop
*, pRef
)
484 aEnumObj
.WriteSrc( pRef
, pRef
->GetObjNode() );
488 ERRTYPE
RscTypCont::WriteRc( WriteRcContext
& rContext
)
491 RscEnumerateRef
aEnumRef( this, pRoot
, rContext
.fOutput
);
493 aIdTranslator
.clear();
495 nPMId
= RSCVERSION_ID
+1; //mindestens einen groesser
497 aError
= aEnumRef
.WriteRc();
500 RscWriteRc
aMem( nByteOrder
);
501 aVersion
.pClass
->WriteRcHeader( aVersion
, aMem
, this, RscId( RSCVERSION_ID
), 0, true );
502 aEnumRef
.aEnumObj
.WriteRcFile( aMem
, rContext
.fOutput
);
507 void RscTypCont :: WriteSrc( FILE * fOutput
, sal_uLong nFileKey
,
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");
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
);
535 pFName
= aFileTab
.Get( nFileKey
);
538 pFName
->aDefLst
.WriteAll( fOutput
);
539 aEnumRef
.WriteSrc( nFileKey
);
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
);
556 aEnumRef
.WriteSrc( nFileKey
);
564 DECL_LINK( Delete
, RscTop
* );
566 RscDel( RscTop
* pRoot
, sal_uLong lKey
);
570 inline RscDel::RscDel( RscTop
* pRoot
, sal_uLong 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
);
583 void RscTypCont :: Delete( sal_uLong lFileKey
)
585 // Resourceinstanzen loeschen
586 RscDel
aDel( pRoot
, lFileKey
);
588 aFileTab
.DeleteFileContext( lFileKey
);
591 bool IsInstConsistent( ObjNode
* pObjNode
, RscTop
* pRscTop
)
599 if( ! IsInstConsistent( static_cast<ObjNode
*>(pObjNode
->Left()), pRscTop
) )
602 aTmpI
.pClass
= pRscTop
;
603 aTmpI
.pData
= pObjNode
->GetRscObj();
604 if( ! aTmpI
.pClass
->IsConsistent( aTmpI
) )
607 if( ! IsInstConsistent( static_cast<ObjNode
*>(pObjNode
->Right()), pRscTop
) )
614 bool MakeConsistent( RscTop
* pRscTop
)
620 if( ! ::MakeConsistent( static_cast<RscTop
*>(pRscTop
->Left()) ) )
623 if( pRscTop
->GetObjNode() )
625 if( ! pRscTop
->GetObjNode()->IsConsistent() )
627 pRscTop
->GetObjNode()->OrderTree();
628 if( ! pRscTop
->GetObjNode()->IsConsistent() )
631 if( ! IsInstConsistent( pRscTop
->GetObjNode(), pRscTop
) )
635 if( ! ::MakeConsistent( static_cast<RscTop
*>(pRscTop
->Right()) ) )
642 sal_uInt32
RscTypCont::PutTranslatorKey( sal_uInt64 nKey
)
644 aIdTranslator
[ nKey
] = nFilePos
;
648 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */