/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include RscTypCont::RscTypCont( RscError * pErrHdl, RSCBYTEORDER_TYPE nOrder, const OString& rSearchPath, sal_uInt32 nFlagsP ) : nSourceCharSet( RTL_TEXTENCODING_UTF8 ) , nByteOrder( nOrder ) , aSearchPath( rSearchPath ) , aBool( pHS->getID( "sal_Bool" ), RSC_NOTYPE ) , aShort( pHS->getID( "short" ), RSC_NOTYPE ) , aUShort( pHS->getID( "sal_uInt16" ), RSC_NOTYPE ) , aLong( pHS->getID( "long" ), RSC_NOTYPE ) , aEnumLong( pHS->getID( "enum_long" ), RSC_NOTYPE ) , aIdUShort( pHS->getID( "IDUSHORT" ), RSC_NOTYPE ) , aIdNoZeroUShort( pHS->getID( "IDUSHORT" ), RSC_NOTYPE ) , aNoZeroShort( pHS->getID( "NoZeroShort" ), RSC_NOTYPE ) , aIdLong( pHS->getID( "IDLONG" ), RSC_NOTYPE ) , aString( pHS->getID( "Chars" ), RSC_NOTYPE ) , aStringLiteral( pHS->getID( "Chars" ), RSC_NOTYPE ) , aWinBits( pHS->getID( "WinBits" ), RSC_NOTYPE ) , aLangType() , aLangString( pHS->getID( "Lang_Chars" ), RSC_NOTYPE, &aString, &aLangType ) , aLangShort( pHS->getID( "Lang_short" ), RSC_NOTYPE, &aShort, &aLangType ) , nAcceleratorType( 0 ) , nFlags( nFlagsP ) { nUniqueId = 256; nPMId = RSC_VERSIONCONTROL +1; // at least one more pEH = pErrHdl; Init(); } OString RscTypCont::ChangeLanguage(const OString& rNewLang) { OString aRet = aLanguage; aLanguage = rNewLang; ::std::vector< OUString > aFallbacks; if (rNewLang.isEmpty()) aFallbacks.push_back( "" ); // do not resolve to SYSTEM (en-US) else aFallbacks = LanguageTag( OStringToOUString( rNewLang, RTL_TEXTENCODING_ASCII_US)).getFallbackStrings( true); bool bAppendEnUsFallback = ! (rNewLang.equalsIgnoreAsciiCase( "en-US" ) || rNewLang.equalsIgnoreAsciiCase( "x-no-translate" ) ); if (bAppendEnUsFallback) aFallbacks.push_back( "en-US"); #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "RscTypCont::ChangeLanguage: " ); #endif aLangFallbacks.clear(); for (::std::vector< OUString >::const_iterator it( aFallbacks.begin()); it != aFallbacks.end(); ++it) { OString aLang( OUStringToOString( *it, RTL_TEXTENCODING_ASCII_US)); sal_uInt32 nID = GetLangId( aLang ); bool bAdd = (nID == 0); if ( bAdd ) { AddLanguage( aLang.getStr() ); nID = GetLangId( aLang ); } #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, " '%s' (0x%hx) (%s)", aLang.getStr(), (int)nID, (bAdd ? "added" : "exists") ); #endif aLangFallbacks.push_back( nID); } #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "\n" ); #endif return aRet; } Atom RscTypCont::AddLanguage( const char* pLang ) { return aLangType.AddLanguage( pLang, aNmTb ); } void DestroyNode( RscTop * pRscTop, ObjNode * pObjNode ) { if( pObjNode ) { DestroyNode( pRscTop, static_cast(pObjNode->Left()) ); DestroyNode( pRscTop, static_cast(pObjNode->Right()) ); if( pObjNode->GetRscObj() ) { pRscTop->Destroy( RSCINST( pRscTop, pObjNode->GetRscObj() ) ); rtl_freeMemory( pObjNode->GetRscObj() ); } delete pObjNode; } } void DestroySubTrees( RscTop * pRscTop ) { if( pRscTop ) { DestroySubTrees( static_cast(pRscTop->Left()) ); DestroyNode( pRscTop, pRscTop->GetObjNode() ); DestroySubTrees( static_cast(pRscTop->Right()) ); } } void DestroyTree( RscTop * pRscTop ) { if( pRscTop ) { DestroyTree( static_cast(pRscTop->Left()) ); DestroyTree( static_cast(pRscTop->Right()) ); delete pRscTop; } } void Pre_dtorTree( RscTop * pRscTop ) { if( pRscTop ) { Pre_dtorTree( static_cast(pRscTop->Left()) ); Pre_dtorTree( static_cast(pRscTop->Right()) ); pRscTop->Pre_dtor(); } } RscTypCont::~RscTypCont() { // delete all subtrees aVersion.pClass->Destroy( aVersion ); rtl_freeMemory( aVersion.pData ); DestroySubTrees( pRoot ); // all classes are still valid, destroy each instance // of base types for ( size_t i = 0, n = aBaseLst.size(); i < n; ++i ) aBaseLst[ i ]->Pre_dtor(); aBool.Pre_dtor(); aShort.Pre_dtor(); aUShort.Pre_dtor(); aIdUShort.Pre_dtor(); aIdNoZeroUShort.Pre_dtor(); aNoZeroShort.Pre_dtor(); aIdLong.Pre_dtor(); aString.Pre_dtor(); aWinBits.Pre_dtor(); aVersion.pClass->Pre_dtor(); // sub-types Pre_dtorTree( pRoot ); // destroy classes delete aVersion.pClass; DestroyTree( pRoot ); for ( size_t i = 0, n = aBaseLst.size(); i < n; ++i ) delete aBaseLst[ i ]; aBaseLst.clear(); for ( size_t i = 0, n = aSysLst.size(); i < n; ++i ) delete aSysLst[ i ]; aSysLst.clear(); } void RscTypCont::ClearSysNames() { for ( size_t i = 0, n = aSysLst.size(); i < n; ++i ) delete aSysLst[ i ]; aSysLst.clear(); } RscTop * RscTypCont::SearchType( Atom nId ) { /* [Description] Search for base type nId; */ if( nId == InvalidAtom ) return nullptr; #define ELSE_IF( a ) \ else if( a.GetId() == nId ) \ return &a; \ if( aBool.GetId() == nId ) return &aBool; ELSE_IF( aShort ) ELSE_IF( aUShort ) ELSE_IF( aLong ) ELSE_IF( aEnumLong ) ELSE_IF( aIdUShort ) ELSE_IF( aIdNoZeroUShort ) ELSE_IF( aNoZeroShort ) ELSE_IF( aIdLong ) ELSE_IF( aString ) ELSE_IF( aWinBits ) ELSE_IF( aLangType ) ELSE_IF( aLangString ) ELSE_IF( aLangShort ) // al least to not pollute #undef ELSE_IF for ( size_t i = 0, n = aBaseLst.size(); i < n; ++i ) { RscTop* pEle = aBaseLst[ i ]; if( pEle->GetId() == nId ) return pEle; } return nullptr; } sal_uInt32 RscTypCont::PutSysName( sal_uInt32 nRscTyp, char * pFileName ) { RscSysEntry *pSysEntry; RscSysEntry *pFoundEntry = nullptr; for ( size_t i = 0, n = aSysLst.size(); i < n; ++i ) { pSysEntry = aSysLst[ i ]; if( !strcmp( pSysEntry->aFileName.getStr(), pFileName ) ) if( pSysEntry->nRscTyp == nRscTyp && pSysEntry->nTyp == 0 && pSysEntry->nRefId == 0) { pFoundEntry = pSysEntry; break; } } pSysEntry = pFoundEntry; if ( !pSysEntry ) { pSysEntry = new RscSysEntry; pSysEntry->nKey = nUniqueId++; pSysEntry->nRscTyp = nRscTyp; pSysEntry->nTyp = 0; pSysEntry->nRefId = 0; pSysEntry->aFileName = pFileName; aSysLst.push_back( pSysEntry ); } return pSysEntry->nKey; } void RscTypCont::WriteInc( FILE * fOutput, RscFileTab::Index lFileKey ) { if( lFileKey == RscFileTab::IndexNotFound ) { RscFileTab::Index aIndex = aFileTab.FirstIndex(); while( aIndex != RscFileTab::IndexNotFound ) { RscFile * pFName = aFileTab.Get( aIndex ); if( pFName->IsIncFile() ) { fprintf( fOutput, "#include " ); fprintf( fOutput, "\"%s\"\n", pFName->aFileName.getStr() ); } aIndex = aFileTab.NextIndex( aIndex ); } } else { RscFile * pFName = aFileTab.Get( lFileKey ); if( pFName ) { for ( size_t i = 0, n = pFName->aDepLst.size(); i < n; ++i ) { RscDepend* pDep = pFName->aDepLst[ i ]; if( pDep->GetFileKey() != lFileKey ) { RscFile* pFile = aFileTab.GetFile( pDep->GetFileKey() ); if( pFile ) { fprintf( fOutput, "#include " ); fprintf( fOutput, "\"%s\"\n", pFile->aFileName.getStr() ); } } } } } } class RscEnumerateObj { friend class RscEnumerateRef; private: ERRTYPE aError; // contains the first field RscTypCont* pTypCont; FILE * fOutput; // output file sal_uLong lFileKey; // what source file RscTop * pClass; DECL_LINK_TYPED( CallBackWriteRc, const NameNode&, void ); DECL_LINK_TYPED( CallBackWriteSrc, const NameNode&, void ); void WriteRc( RscTop * pCl, ObjNode * pRoot ) { pClass = pCl; if( pRoot ) pRoot->EnumNodes( LINK( this, RscEnumerateObj, CallBackWriteRc ) ); } ERRTYPE WriteSrc( RscTop * pCl, ObjNode * pRoot ){ pClass = pCl; if( pRoot ) pRoot->EnumNodes( LINK( this, RscEnumerateObj, CallBackWriteSrc ) ); return aError; } public: void WriteRcFile( RscWriteRc & rMem, FILE * fOutput ); }; IMPL_LINK_TYPED( RscEnumerateObj, CallBackWriteRc, const NameNode&, rNode, void ) { const ObjNode& rObjNode = static_cast(rNode); RscWriteRc aMem( pTypCont->GetByteOrder() ); aError = pClass->WriteRcHeader( RSCINST( pClass, rObjNode.GetRscObj() ), aMem, pTypCont, rObjNode.GetRscId(), 0, true ); if( aError.IsError() || aError.IsWarning() ) pTypCont->pEH->Error( aError, pClass, rObjNode.GetRscId() ); WriteRcFile( aMem, fOutput ); } IMPL_LINK_TYPED( RscEnumerateObj, CallBackWriteSrc, const NameNode&, rNode, void ) { const ObjNode& rObjNode = static_cast(rNode); if( rObjNode.GetFileKey() == lFileKey ) { pClass->WriteSrcHeader( RSCINST( pClass, rObjNode.GetRscObj() ), fOutput, pTypCont, 0, rObjNode.GetRscId(), "" ); fprintf( fOutput, ";\n" ); } } void RscEnumerateObj::WriteRcFile( RscWriteRc & rMem, FILE * fOut ) { // structure definition from which the resource is built /* struct RSHEADER_TYPE{ sal_uInt32 nId; // resource identifier sal_uInt32 nRT; // resource type sal_uInt32 nGlobOff; // global offset sal_uInt32 nLocalOff; // local offset } aHeader; */ sal_uInt32 nId = rMem.GetLong( 0 ); sal_uInt32 nRT = rMem.GetLong( 4 ); // table is filled with with nId and nRT pTypCont->PutTranslatorKey( (sal_uInt64(nRT) << 32) + sal_uInt64(nId) ); if( nRT == RSC_VERSIONCONTROL ) { // always comes last sal_Int32 nCount = pTypCont->aIdTranslator.size(); // table size sal_uInt32 nSize = (nCount * (sizeof(sal_uInt64)+sizeof(sal_Int32))) + sizeof(sal_Int32); rMem.Put( nCount ); // save the count for( std::map< sal_uInt64, sal_uLong >::const_iterator it = pTypCont->aIdTranslator.begin(); it != pTypCont->aIdTranslator.end(); ++it ) { // save the key rMem.Put( it->first ); // save the object id or position rMem.Put( (sal_Int32)it->second ); } rMem.Put( nSize ); // save the size next } // reset the file offset pTypCont->IncFilePos( rMem.Size() ); // position was written previously in the table bool bSuccess = (1 == fwrite( rMem.GetBuffer(), rMem.Size(), 1, fOut )); SAL_WARN_IF(!bSuccess, "rsc", "short write"); }; class RscEnumerateRef { private: RscTop * pRoot; DECL_LINK_TYPED( CallBackWriteRc, const NameNode&, void ); DECL_LINK_TYPED( CallBackWriteSrc, const NameNode&, void ); public: RscEnumerateObj aEnumObj; RscEnumerateRef( RscTypCont * pTC, RscTop * pR, FILE * fOutput ) { aEnumObj.pTypCont = pTC; aEnumObj.fOutput = fOutput; pRoot = pR; } ERRTYPE WriteRc() { aEnumObj.aError.Clear(); pRoot->EnumNodes( LINK( this, RscEnumerateRef, CallBackWriteRc ) ); return aEnumObj.aError; } ERRTYPE WriteSrc( sal_uLong lFileKey ) { aEnumObj.lFileKey = lFileKey; aEnumObj.aError.Clear(); pRoot->EnumNodes( LINK( this, RscEnumerateRef, CallBackWriteSrc ) ); return aEnumObj.aError; } }; IMPL_LINK_TYPED( RscEnumerateRef, CallBackWriteRc, const NameNode&, rNode, void ) { const RscTop& rRef = static_cast(rNode); aEnumObj.WriteRc( const_cast(&rRef), rRef.GetObjNode() ); } IMPL_LINK_TYPED( RscEnumerateRef, CallBackWriteSrc, const NameNode&, rNode, void ) { const RscTop& rRef = static_cast(rNode); aEnumObj.WriteSrc( const_cast(&rRef), rRef.GetObjNode() ); } ERRTYPE RscTypCont::WriteRc( WriteRcContext& rContext ) { ERRTYPE aError; RscEnumerateRef aEnumRef( this, pRoot, rContext.fOutput ); aIdTranslator.clear(); nFilePos = 0; nPMId = RSCVERSION_ID +1; // at least one more aError = aEnumRef.WriteRc(); // version control RscWriteRc aMem( nByteOrder ); aVersion.pClass->WriteRcHeader( aVersion, aMem, this, RscId( RSCVERSION_ID ), 0, true ); aEnumRef.aEnumObj.WriteRcFile( aMem, rContext.fOutput ); return aError; } void RscTypCont::WriteSrc( FILE * fOutput, RscFileTab::Index nFileKey ) { RscEnumerateRef aEnumRef( this, pRoot, fOutput ); unsigned char aUTF8BOM[3] = { 0xef, 0xbb, 0xbf }; size_t nItems = SAL_N_ELEMENTS(aUTF8BOM); bool bSuccess = (nItems == fwrite(aUTF8BOM, 1, nItems, fOutput)); SAL_WARN_IF(!bSuccess, "rsc", "short write"); RscId::SetNames( false ); if( nFileKey == RscFileTab::IndexNotFound ) { RscFileTab::Index aIndex = aFileTab.FirstIndex(); while( aIndex != RscFileTab::IndexNotFound ) { aEnumRef.WriteSrc( aIndex ); aIndex = aFileTab.NextIndex( aIndex ); }; } else aEnumRef.WriteSrc( nFileKey ); RscId::SetNames(); } class RscDel { sal_uLong lFileKey; DECL_LINK_TYPED( Delete, const NameNode&, void ); public: RscDel( RscTop * pRoot, sal_uLong lKey ); }; inline RscDel::RscDel( RscTop * pRoot, sal_uLong lKey ) { lFileKey = lKey; pRoot->EnumNodes( LINK( this, RscDel, Delete ) ); } IMPL_LINK_TYPED( RscDel, Delete, const NameNode&, r, void ) { RscTop* pNode = const_cast(static_cast(&r)); if( pNode->GetObjNode() ) pNode->pObjBiTree = pNode->GetObjNode()->DelObjNode( pNode, lFileKey ); } void RscTypCont::Delete( RscFileTab::Index lFileKey ) { // delete resource instance RscDel aDel( pRoot, lFileKey ); // delete defines aFileTab.DeleteFileContext( lFileKey ); } bool IsInstConsistent( ObjNode * pObjNode, RscTop * pRscTop ) { bool bRet = true; if( pObjNode ) { RSCINST aTmpI; if( ! IsInstConsistent( static_cast(pObjNode->Left()), pRscTop ) ) bRet = false; aTmpI.pClass = pRscTop; aTmpI.pData = pObjNode->GetRscObj(); if( ! aTmpI.pClass->IsConsistent( aTmpI ) ) bRet = false; if( ! IsInstConsistent( static_cast(pObjNode->Right()), pRscTop ) ) bRet = false; } return bRet; } bool MakeConsistent( RscTop * pRscTop ) { bool bRet = true; if( pRscTop ) { if( ! ::MakeConsistent( static_cast(pRscTop->Left()) ) ) bRet = false; if( pRscTop->GetObjNode() ) { if( ! pRscTop->GetObjNode()->IsConsistent() ) { pRscTop->GetObjNode()->OrderTree(); if( ! pRscTop->GetObjNode()->IsConsistent() ) bRet = false; } if( ! IsInstConsistent( pRscTop->GetObjNode(), pRscTop ) ) bRet = false; } if( ! ::MakeConsistent( static_cast(pRscTop->Right()) ) ) bRet = false; } return bRet; } void RscTypCont::PutTranslatorKey( sal_uInt64 nKey ) { aIdTranslator[ nKey ] = nFilePos; nPMId++; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */