office-gobmx/rsc/source/parser/rscdb.cxx
Stephan Bergmann 1e2078d451 -Werror=unused-but-set-variable
Change-Id: I7c0f1e37f3a53dfed09c4e13d10826022b3ca777
2016-03-23 09:35:36 +01:00

606 lines
17 KiB
C++

/* -*- 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 <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <tools/rc.h>
#include <i18nlangtag/languagetag.hxx>
#include <rtl/strbuf.hxx>
#include <sal/log.hxx>
#include <sal/macros.h>
#include <rsctree.hxx>
#include <rsctop.hxx>
#include <rscmgr.hxx>
#include <rscdb.hxx>
#include <rscrsc.hxx>
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<ObjNode*>(pObjNode->Left()) );
DestroyNode( pRscTop, static_cast<ObjNode*>(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<RscTop*>(pRscTop->Left()) );
DestroyNode( pRscTop, pRscTop->GetObjNode() );
DestroySubTrees( static_cast<RscTop*>(pRscTop->Right()) );
}
}
void DestroyTree( RscTop * pRscTop )
{
if( pRscTop )
{
DestroyTree( static_cast<RscTop*>(pRscTop->Left()) );
DestroyTree( static_cast<RscTop*>(pRscTop->Right()) );
delete pRscTop;
}
}
void Pre_dtorTree( RscTop * pRscTop )
{
if( pRscTop )
{
Pre_dtorTree( static_cast<RscTop*>(pRscTop->Left()) );
Pre_dtorTree( static_cast<RscTop*>(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<const ObjNode&>(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<const ObjNode&>(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<const RscTop&>(rNode);
aEnumObj.WriteRc( const_cast<RscTop*>(&rRef), rRef.GetObjNode() );
}
IMPL_LINK_TYPED( RscEnumerateRef, CallBackWriteSrc, const NameNode&, rNode, void )
{
const RscTop& rRef = static_cast<const RscTop&>(rNode);
aEnumObj.WriteSrc( const_cast<RscTop*>(&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<RscTop*>(static_cast<const RscTop*>(&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<ObjNode*>(pObjNode->Left()), pRscTop ) )
bRet = false;
aTmpI.pClass = pRscTop;
aTmpI.pData = pObjNode->GetRscObj();
if( ! aTmpI.pClass->IsConsistent( aTmpI ) )
bRet = false;
if( ! IsInstConsistent( static_cast<ObjNode*>(pObjNode->Right()), pRscTop ) )
bRet = false;
}
return bRet;
}
bool MakeConsistent( RscTop * pRscTop )
{
bool bRet = true;
if( pRscTop )
{
if( ! ::MakeConsistent( static_cast<RscTop*>(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<RscTop*>(pRscTop->Right()) ) )
bRet = false;
}
return bRet;
}
void RscTypCont::PutTranslatorKey( sal_uInt64 nKey )
{
aIdTranslator[ nKey ] = nFilePos;
nPMId++;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */