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 .
20 #include <ctype.h> // isdigit(), isalpha()
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
,
43 nSourceCharSet( RTL_TEXTENCODING_UTF8
),
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
),
65 aLangString( pHS
->getID( "Lang_Chars" ), RSC_NOTYPE
, &aString
, &aLangType
),
66 aLangShort( pHS
->getID( "Lang_short" ), RSC_NOTYPE
, &aShort
, &aLangType
),
67 nAcceleratorType( 0 ),
71 nPMId
= RSC_VERSIONCONTROL
+1; //mindestens einen groesser
76 OString
RscTypCont::ChangeLanguage(const OString
& rNewLang
)
78 OString aRet
= aLanguage
;
81 ::std::vector
< OUString
> aFallbacks
;
82 if (rNewLang
.isEmpty())
83 aFallbacks
.push_back( "" ); // do not resolve to SYSTEM (en-US)
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: " );
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);
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") );
111 aLangFallbacks
.push_back( nID
);
114 #if OSL_DEBUG_LEVEL > 1
115 fprintf( stderr
, "\n" );
121 Atom
RscTypCont::AddLanguage( const char* pLang
)
123 return aLangType
.AddLanguage( pLang
, aNmTb
);
127 void DestroyNode( RscTop
* pRscTop
, ObjNode
* 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() );
140 void DestroySubTrees( RscTop
* pRscTop
){
142 DestroySubTrees( (RscTop
*)pRscTop
->Left() );
144 DestroyNode( pRscTop
, pRscTop
->GetObjNode() );
146 DestroySubTrees( (RscTop
*)pRscTop
->Right() );
150 void DestroyTree( RscTop
* pRscTop
){
152 DestroyTree( (RscTop
*)pRscTop
->Left() );
153 DestroyTree( (RscTop
*)pRscTop
->Right() );
159 void Pre_dtorTree( RscTop
* pRscTop
){
161 Pre_dtorTree( (RscTop
*)pRscTop
->Left() );
162 Pre_dtorTree( (RscTop
*)pRscTop
->Right() );
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
176 for ( size_t i
= 0, n
= aBaseLst
.size(); i
< n
; ++i
)
177 aBaseLst
[ i
]->Pre_dtor();
181 aIdUShort
.Pre_dtor();
182 aIdNoZeroUShort
.Pre_dtor();
183 aNoZeroShort
.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
];
199 for ( size_t i
= 0, n
= aSysLst
.size(); i
< n
; ++i
)
204 void RscTypCont::ClearSysNames()
206 for ( size_t i
= 0, n
= aSysLst
.size(); i
< n
; ++i
)
211 RscTop
* RscTypCont::SearchType( Atom nId
)
214 Sucht eine Basistyp nId;
217 if( nId
== InvalidAtom
)
220 #define ELSE_IF( a ) \
221 else if( a.GetId() == nId ) \
224 if( aBool.GetId() == nId )
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
)
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
)
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 )
267 if( !strcmp( pSysEntry
->aFileName
.getStr(), pFileName
) )
268 if( pSysEntry
->nRscTyp
== nRscTyp
269 && pSysEntry
->nTyp
== nConst
270 && pSysEntry
->nRefId
== nId
272 pFoundEntry
= pSysEntry
;
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
)
289 aSysLst
.insert( aSysLst
.begin(), pSysEntry
);
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
);
321 RscFile
* pFName
= aFileTab
.Get( lFileKey
);
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() );
332 fprintf( fOutput
, "#include " );
333 fprintf( fOutput
, "\"%s\"\n",
334 pFile
->aFileName
.getStr() );
343 class RscEnumerateObj
345 friend class RscEnumerateRef
;
347 ERRTYPE aError
; // Enthaelt den ersten Fehler
348 RscTypCont
* pTypCont
;
349 FILE * fOutput
; // AusgabeDatei
350 sal_uLong lFileKey
; // Welche src-Datei
353 DECL_LINK( CallBackWriteRc
, ObjNode
* );
354 DECL_LINK( CallBackWriteSrc
, ObjNode
* );
356 ERRTYPE
WriteRc( RscTop
* pCl
, ObjNode
* pRoot
)
360 pRoot
->EnumNodes( LINK( this, RscEnumerateObj
, CallBackWriteRc
) );
363 ERRTYPE
WriteSrc( RscTop
* pCl
, ObjNode
* pRoot
){
366 pRoot
->EnumNodes( LINK( this, RscEnumerateObj
, CallBackWriteSrc
) );
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() ),
379 pObjNode
->GetRscId(), 0, sal_True
);
380 if( aError
.IsError() || aError
.IsWarning() )
381 pTypCont
->pEH
->Error( aError
, pClass
, pObjNode
->GetRscId() );
383 WriteRcFile( aMem
, fOutput
);
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" );
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
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
449 DECL_LINK( CallBackWriteRc
, RscTop
* );
450 DECL_LINK( CallBackWriteSrc
, RscTop
* );
452 RscEnumerateObj aEnumObj
;
454 RscEnumerateRef( RscTypCont
* pTC
, RscTop
* pR
,
457 aEnumObj
.pTypCont
= pTC
;
458 aEnumObj
.fOutput
= fOutput
;
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() );
483 IMPL_LINK_INLINE_END( RscEnumerateRef
, CallBackWriteRc
, RscTop
*, pRef
)
484 IMPL_LINK_INLINE_START( RscEnumerateRef
, CallBackWriteSrc
, RscTop
*, pRef
)
486 aEnumObj
.WriteSrc( pRef
, pRef
->GetObjNode() );
489 IMPL_LINK_INLINE_END( RscEnumerateRef
, CallBackWriteSrc
, RscTop
*, pRef
)
492 ERRTYPE
RscTypCont::WriteRc( WriteRcContext
& rContext
)
495 RscEnumerateRef
aEnumRef( this, pRoot
, rContext
.fOutput
);
497 aIdTranslator
.clear();
499 nPMId
= RSCVERSION_ID
+1; //mindestens einen groesser
501 aError
= aEnumRef
.WriteRc();
504 RscWriteRc
aMem( nByteOrder
);
505 aVersion
.pClass
->WriteRcHeader( aVersion
, aMem
, this, RscId( RSCVERSION_ID
), 0, sal_True
);
506 aEnumRef
.aEnumObj
.WriteRcFile( aMem
, rContext
.fOutput
);
511 void RscTypCont :: WriteSrc( FILE * fOutput
, sal_uLong nFileKey
,
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");
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
);
538 pFName
= aFileTab
.Get( nFileKey
);
540 pFName
->aDefLst
.WriteAll( fOutput
);
541 aEnumRef
.WriteSrc( nFileKey
);
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
);
558 aEnumRef
.WriteSrc( nFileKey
);
566 DECL_LINK( Delete
, RscTop
* );
568 RscDel( RscTop
* pRoot
, sal_uLong lKey
);
572 inline RscDel::RscDel( RscTop
* pRoot
, sal_uLong 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
);
584 IMPL_LINK_INLINE_END( RscDel
, Delete
, RscTop
*, pNode
)
586 void RscTypCont :: Delete( sal_uLong lFileKey
){
587 // Resourceinstanzen loeschen
588 RscDel
aDel( pRoot
, lFileKey
);
590 aFileTab
.DeleteFileContext( lFileKey
);
593 sal_Bool
IsInstConsistent( ObjNode
* pObjNode
, RscTop
* pRscTop
)
595 sal_Bool bRet
= sal_True
;
600 if( ! IsInstConsistent( (ObjNode
*)pObjNode
->Left(), pRscTop
) )
603 aTmpI
.pClass
= pRscTop
;
604 aTmpI
.pData
= pObjNode
->GetRscObj();
605 if( ! aTmpI
.pClass
->IsConsistent( aTmpI
) )
608 if( ! IsInstConsistent( (ObjNode
*)pObjNode
->Right(), pRscTop
) )
615 sal_Bool
MakeConsistent( RscTop
* pRscTop
)
617 sal_Bool bRet
= sal_True
;
620 if( ! ::MakeConsistent( (RscTop
*)pRscTop
->Left() ) )
623 if( pRscTop
->GetObjNode() ){
624 if( ! pRscTop
->GetObjNode()->IsConsistent() ){
625 pRscTop
->GetObjNode()->OrderTree();
626 if( ! pRscTop
->GetObjNode()->IsConsistent() )
629 if( ! IsInstConsistent( pRscTop
->GetObjNode(), pRscTop
) )
633 if( ! ::MakeConsistent( (RscTop
*)pRscTop
->Right() ) )
640 sal_uInt32
RscTypCont::PutTranslatorKey( sal_uInt64 nKey
)
642 aIdTranslator
[ nKey
] = nFilePos
;
646 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */