/* -*- 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 "sal/config.h" #include #include #include "helper.hxx" #include "srclex.hxx" #include #include #include "common.hxx" #include "export.hxx" #include "tokens.h" #include #include #include void yyerror( const char * ); void YYWarning( const char * ); namespace { MergeDataFile * pMergeDataFile = nullptr; //TODO namespace global { OString inputPathname; std::unique_ptr< Export > exporter; } OString lcl_GetListTyp( const ExportListType nTyp, const bool bUpperCamelCase ) { OString sType; switch (nTyp) { case ExportListType::String: sType = bUpperCamelCase ? "StringList" : "stringlist"; break; case ExportListType::Filter: sType = bUpperCamelCase ? "FilterList" : "filterlist"; break; case ExportListType::Item: sType = bUpperCamelCase ? "ItemList" : "itemlist"; break; case ExportListType::Paired: sType = bUpperCamelCase ? "PairedList" : "pairedlist"; break; default: break; } return sType; } } extern "C" { FILE * init(int argc, char ** argv) { common::HandledArgs aArgs; if ( !common::handleArguments(argc, argv, aArgs) ) { common::writeUsage("transex3","*.src/*.hrc"); std::exit(EXIT_FAILURE); } global::inputPathname = aArgs.m_sInputFile; FILE * pFile = std::fopen(global::inputPathname.getStr(), "r"); if (pFile == nullptr) { std::fprintf( stderr, "Error: Cannot open file \"%s\"\n", global::inputPathname.getStr()); std::exit(EXIT_FAILURE); } if (aArgs.m_bMergeMode) { global::exporter.reset(new Export(aArgs.m_sMergeSrc, aArgs.m_sOutputFile, aArgs.m_bUTF8BOM)); } else { global::exporter.reset(new Export(aArgs.m_sOutputFile)); } global::exporter->Init(); return pFile; } int Parse( int nTyp, const char *pTokenText ){ global::exporter->Execute( nTyp , pTokenText ); return 1; } void Close() { global::exporter->GetParseQueue()->Close(); global::exporter.reset(); // avoid nontrivial Export dtor being executed during exit } int WorkOnTokenSet( int nTyp, char *pTokenText ) { global::exporter->GetParseQueue()->Push( QueueEntry( nTyp , OString(pTokenText) ) ); return 1; } int SetError() { // set error at global instance of class Export global::exporter->SetError(); return 1; } int GetError() { // get error at global instance of class Export if (global::exporter->GetError()) return 1; return false; } } // extern "C" // class ResData bool ResData::SetId( const OString& rId, IdLevel nLevel ) { if ( nLevel > nIdLevel ) { nIdLevel = nLevel; sId = rId; if ( bChild && bChildWithText ) { yyerror("ResId after child definition"); SetError(); } if ( sId.getLength() > 255 ) { YYWarning( "LocalId > 255 chars, truncating..." ); sId = sId.copy(0, 255).trim(); } return true; } return false; } // class Export namespace { sal_Int32 lcl_countOccurrences(const OString& text, char c) { sal_Int32 n = 0; for (sal_Int32 i = 0;; ++i) { i = text.indexOf(c, i); if (i == -1) { break; } ++n; } return n; } } Export::Export(const OString &rOutput) : bDefine( false ), bNextMustBeDefineEOL( false ), nLevel( 0 ), nList( ExportListType::NONE ), nListLevel( 0 ), bMergeMode( false ), bError( false ), bReadOver( false ), sFilename( global::inputPathname ), pParseQueue( new ParserQueue( *this ) ) { aOutput.mPo = new PoOfstream( rOutput, PoOfstream::APP ); if (!aOutput.mPo->isOpen()) { std::fprintf(stderr, "ERROR : Can't open file %s\n", rOutput.getStr()); std::exit(EXIT_FAILURE); } } Export::Export( const OString &rMergeSource, const OString &rOutput, bool bUTF8BOM) : bDefine( false ), bNextMustBeDefineEOL( false ), nLevel( 0 ), nList( ExportListType::NONE ), nListLevel( 0 ), bMergeMode( true ), sMergeSrc( rMergeSource ), bError( false ), bReadOver( false ), sFilename( global::inputPathname ), pParseQueue( new ParserQueue( *this ) ) { aOutput.mSimple = new std::ofstream(); aOutput.mSimple->open(rOutput.getStr(), std::ios_base::out | std::ios_base::trunc); if (!aOutput.mSimple->is_open()) { std::fprintf(stderr, "ERROR : Can't open file %s\n", rOutput.getStr()); std::exit(EXIT_FAILURE); } if ( bUTF8BOM ) *aOutput.mSimple << '\xEF' << '\xBB' << '\xBF'; } void Export::Init() { // resets the internal status, used before parsing another file bDefine = false; bNextMustBeDefineEOL = false; nLevel = 0; nList = ExportListType::NONE; for ( size_t i = 0, n = aResStack.size(); i < n; ++i ) delete aResStack[ i ]; aResStack.clear(); } Export::~Export() { delete pParseQueue; if ( bMergeMode ) { aOutput.mSimple->close(); delete aOutput.mSimple; } else { aOutput.mPo->close(); delete aOutput.mPo; } for ( size_t i = 0, n = aResStack.size(); i < n; ++i ) delete aResStack[ i ]; aResStack.clear(); if ( bMergeMode ) { if ( !pMergeDataFile ) pMergeDataFile = new MergeDataFile(sMergeSrc, global::inputPathname, true); delete pMergeDataFile; } } void Export::Execute( int nToken, const char * pToken ) { OString sToken( pToken ); OString sOrig( sToken ); if ( nToken == CONDITION ) { OString sTestToken(pToken); sTestToken = sTestToken.replaceAll("\t", OString()). replaceAll(" ", OString()); if (( !bReadOver ) && ( sTestToken.startsWith("#ifndef__RSC_PARSER"))) bReadOver = true; else if (( bReadOver ) && ( sTestToken.startsWith("#endif") )) bReadOver = false; } if ((( nToken < FILTER_LEVEL ) || ( bReadOver )) && (!(( bNextMustBeDefineEOL ) && ( sOrig == "\n" )))) { // this tokens are not mandatory for parsing, so ignore them ... if ( bMergeMode ) WriteToMerged( sOrig , false ); // ... or write them directly to dest. return; } ResData *pResData = nullptr; if ( nLevel ) { // res. exists at cur. level pResData = ( (nLevel-1) < aResStack.size() ) ? aResStack[ nLevel-1 ] : nullptr; } else if (( nToken != RESOURCE ) && ( nToken != RESOURCEEXPR ) && ( nToken != SMALRESOURCE ) && ( nToken != LEVELUP ) && ( nToken != NORMDEFINE ) && ( nToken != RSCDEFINE ) && ( nToken != CONDITION ) && ( nToken != PRAGMA )) { // no res. exists at cur. level so return if ( bMergeMode ) WriteToMerged( sOrig , false ); return; } if ( bDefine ) { if (( nToken != EMPTYLINE ) && ( nToken != LEVELDOWN ) && ( nToken != LEVELUP )) { // cur. res. defined in macro if ( bNextMustBeDefineEOL ) { if ( nToken != RSCDEFINELEND ) { // end of macro found, so destroy res. bDefine = false; Execute( LEVELDOWN, "" ); bNextMustBeDefineEOL = false; } else { // next line also in macro definition bNextMustBeDefineEOL = false; if ( bMergeMode ) WriteToMerged( sOrig , false ); return; } } } } bool bExecuteDown = false; if ( nToken != LEVELDOWN ) { sal_uInt16 nOpen = 0; sal_uInt16 nClose = 0; bool bReadOver1 = false; for ( sal_Int32 i = 0; i < sToken.getLength(); i++ ) { if ( sToken[i] == '"' ) bReadOver1 = !bReadOver1; if ( !bReadOver1 && ( sToken[i] == '{' )) nOpen++; } bReadOver1 = false; for ( sal_Int32 i = 0; i < sToken.getLength(); i++ ) { if ( sToken[i] == '"' ) bReadOver1 = !bReadOver1; if ( !bReadOver1 && ( sToken[i] == '}' )) nClose++; } if ( nOpen < nClose ) bExecuteDown = true; } bool bWriteToMerged = bMergeMode; switch ( nToken ) { case NORMDEFINE: if ( bMergeMode ) WriteToMerged( sOrig , false ); return; case RSCDEFINE: bDefine = true; // res. defined in macro SAL_FALLTHROUGH; case RESOURCE: case RESOURCEEXPR: { if ( nToken != RSCDEFINE ) bNextMustBeDefineEOL = false; // this is the beginning of a new res. nLevel++; if ( nLevel > 1 ) { aResStack[ nLevel - 2 ]->bChild = true; } // create new instance for this res. and fill mandatory fields pResData = new ResData( FullId() , sFilename ); aResStack.push_back( pResData ); sToken = sToken.replaceAll("\n", OString()). replaceAll("\r", OString()). replaceAll("{", OString()).replace('\t', ' '); sToken = sToken.trim(); OString sTLower = sToken.getToken(0, ' ').toAsciiLowerCase(); pResData->sResTyp = sTLower; OString sId( sToken.copy( pResData->sResTyp.getLength() + 1 )); OString sCondition; if ( sId.indexOf( '#' ) != -1 ) { // between ResTyp, Id and parentheses is a precomp. condition sCondition = "#"; sal_Int32 n = 0; sId = sId.getToken(0, '#', n); sCondition += sId.getToken(0, '#', n); } sId = sId.getToken(0, '/'); CleanValue( sId ); sId = sId.replaceAll("\t", OString()); pResData->SetId( sId, IdLevel::Identifier ); if (!sCondition.isEmpty()) { Execute( CONDITION, ""); // execute the precomp. condition } } break; case SMALRESOURCE: { // this is the beginning of a new res. bNextMustBeDefineEOL = false; nLevel++; if ( nLevel > 1 ) { aResStack[ nLevel - 2 ]->bChild = true; } // create new instance for this res. and fill mandatory fields pResData = new ResData( FullId() , sFilename ); aResStack.push_back( pResData ); sToken = sToken.replaceAll("\n", OString()). replaceAll("\r", OString()). replaceAll("{", OString()). replaceAll("\t", OString()). replaceAll(" ", OString()). replaceAll("\\", OString()).toAsciiLowerCase(); pResData->sResTyp = sToken; } break; case LEVELUP: { // push if ( nList != ExportListType::NONE ) { nListLevel++; break; } OString sLowerTyp; if ( pResData ) sLowerTyp = "unknown"; nLevel++; if ( nLevel > 1 ) { aResStack[ nLevel - 2 ]->bChild = true; } ResData *pNewData = new ResData( FullId() , sFilename ); pNewData->sResTyp = sLowerTyp; aResStack.push_back( pNewData ); } break; case LEVELDOWN: { // pop if ( nList == ExportListType::NONE || !nListLevel ) { if ( nLevel ) { if ( bDefine && (nLevel == 1 )) { bDefine = false; bNextMustBeDefineEOL = false; } WriteData( pResData ); ResStack::iterator it = aResStack.begin(); ::std::advance( it, nLevel-1 ); delete *it; aResStack.erase( it ); nLevel--; } if( nList != ExportListType::NONE ) { nList = ExportListType::NONE; nListLevel = 1; } } else { if ( bDefine ) bNextMustBeDefineEOL = true; nListLevel--; } } break; case ASSIGNMENT: { // interpret different types of assignement sal_Int32 n = 0; OString sKey = sToken.getToken(0, '=', n). replaceAll(" ", OString()). replaceAll("\t", OString()); OString sValue = sToken.getToken(0, '=', n); CleanValue( sValue ); sKey = sKey.toAsciiUpperCase(); if (sKey == "IDENTIFIER") { OString sId( sValue.replaceAll("\t", OString()). replaceAll(" ", OString())); pResData->SetId(sId, IdLevel::Identifier); } else if (sKey =="STRINGLIST") { nList = ExportListType::String; nListLevel = 1; } else if (sKey == "FILTERLIST") { nList = ExportListType::Filter; nListLevel = 1; } if (sToken.indexOf( '{' ) != -1 && (lcl_countOccurrences(sToken, '{') > lcl_countOccurrences(sToken, '}'))) { Parse( LEVELUP, "" ); } } break; case LISTASSIGNMENT: { OString sTmpToken( sToken.replaceAll(" ", OString()).toAsciiLowerCase()); sal_Int32 nPos = sTmpToken.indexOf("[en-us]="); if (nPos != -1) { OString sKey( sTmpToken.copy(0 , nPos).replaceAll(" ", OString()). replaceAll("\t", OString())); OString sValue = sToken.getToken(1, '='); CleanValue( sValue ); sKey = sKey.toAsciiUpperCase(); if (sKey == "STRINGLIST") { nList = ExportListType::String; } else if (sKey == "FILTERLIST") { nList = ExportListType::Filter; } else if (sKey == "PAIREDLIST") { nList = ExportListType::Paired; } else if (sKey == "ITEMLIST") { nList = ExportListType::Item; } if( nList != ExportListType::NONE ) { nListLevel = 1; } } } break; case TEXT: case LISTTEXT_: case LISTTEXT: { // this is an entry for a List if ( nList != ExportListType::NONE ) { SetChildWithText(); InsertListEntry( sOrig ); } } break; case LONGTEXTLINE: case TEXTLINE: if ( nLevel ) { CutComment( sToken ); // this is a text line!!! OString t(sToken.getToken(0, '=')); OString sKey( t.getToken(0, '[').replaceAll(" ", OString()). replaceAll("\t", OString())); OString sText( GetText( sToken, nToken )); OString sLang; if ( sToken.getToken(0, '=').indexOf('[') != -1 ) { sLang = sToken.getToken(0, '=').getToken(1, '['). getToken(0, ']'); CleanValue( sLang ); } OString sLangIndex = sLang; OString sOrigKey = sKey; if ( !sText.isEmpty() && !sLang.isEmpty() ) { sKey = sKey.toAsciiUpperCase(); if (sKey == "TEXT" || sKey == "MESSAGE" || sKey == "CUSTOMUNITTEXT") { SetChildWithText(); if ( sLangIndex.equalsIgnoreAsciiCase("en-US") ) pResData->SetId( sText, IdLevel::Text ); pResData->bText = true; pResData->sTextTyp = sOrigKey; if ( !bMergeMode ) { pResData->sText[ sLangIndex ] = sText; } } else if ( sKey == "QUICKHELPTEXT" ) { SetChildWithText(); pResData->bQuickHelpText = true; if ( !bMergeMode ) { pResData->sQuickHelpText[ sLangIndex ] = sText; } } else if ( sKey == "TITLE" ) { SetChildWithText(); pResData->bTitle = true; if ( !bMergeMode ) { pResData->sTitle[ sLangIndex ] = sText; } } } } break; case APPFONTMAPPING: break; case RSCDEFINELEND: break; case CONDITION: { if ( nLevel && pResData ) { WriteData( pResData, true ); } } break; case EMPTYLINE : { if ( bDefine ) { bNextMustBeDefineEOL = false; bDefine = false; while ( nLevel ) Parse( LEVELDOWN, "" ); } } break; case PRAGMA : { std::fprintf(stderr, "ERROR: archaic PRAGMA %s\n", sToken.getStr()); std::exit(EXIT_FAILURE); } break; } if ( bWriteToMerged ) { // the current token must be written to dest. without merging if( bDefine && sOrig.getLength() > 2 ){ for( sal_Int32 n = 0; n < sOrig.getLength(); n++ ){ if( sOrig[n] == '\n' && sOrig[n-1] != '\\'){ sOrig = sOrig.replaceAt(n++, 0, "\\"); } } } WriteToMerged( sOrig , false); } if ( bExecuteDown ) { Parse( LEVELDOWN, "" ); } } void Export::CutComment( OString &rText ) { if (rText.indexOf("//") != -1) { OString sWork(rText.replaceAll("\\\"", "XX")); bool bInner = false; for (sal_Int32 i = 0; i < sWork.getLength() - 1; ++i) { if (sWork[i] == '"') { bInner = !bInner; } else if (sWork[i] == '/' && !bInner && sWork[i + 1] == '/' ) { rText = rText.copy(0, i); break; } } } } void Export::WriteData( ResData *pResData, bool bCreateNew ) { if ( bMergeMode ) { MergeRest( pResData ); return; } // mandatory to export: en-US if (( !pResData->sText[ SOURCE_LANGUAGE ].isEmpty()) || ( !pResData->sQuickHelpText[ SOURCE_LANGUAGE ].isEmpty()) || ( !pResData->sTitle[ SOURCE_LANGUAGE ].isEmpty())) { OString sGID = pResData->sGId; OString sLID; if (sGID.isEmpty()) sGID = pResData->sId; else sLID = pResData->sId; OString sXText = pResData->sText[ SOURCE_LANGUAGE ]; OString sXHText = pResData->sText[ X_COMMENT ]; OString sXQHText = pResData->sQuickHelpText[ SOURCE_LANGUAGE ]; OString sXTitle = pResData->sTitle[ SOURCE_LANGUAGE ]; if( !sXText.isEmpty() ) { ConvertExportContent(sXText); ConvertExportContent(sXHText); common::writePoEntry( "Transex3", *aOutput.mPo, global::inputPathname, pResData->sResTyp, sGID, sLID, sXHText, sXText); } if( !sXQHText.isEmpty() ) { ConvertExportContent(sXQHText); common::writePoEntry( "Transex3", *aOutput.mPo, global::inputPathname, pResData->sResTyp, sGID, sLID, OString(), sXQHText, PoEntry::TQUICKHELPTEXT ); } if( !sXTitle.isEmpty() ) { ConvertExportContent(sXTitle); common::writePoEntry( "Transex3", *aOutput.mPo, global::inputPathname, pResData->sResTyp, sGID, sLID, OString(), sXTitle, PoEntry::TTITLE ); } if ( bCreateNew ) { pResData->sText[ SOURCE_LANGUAGE ] = ""; pResData->sQuickHelpText[ SOURCE_LANGUAGE ]= ""; pResData->sTitle[ SOURCE_LANGUAGE ] = ""; } } if( nList != ExportListType::NONE ) { WriteExportList( pResData, pResData->m_aList, nList ); if ( bCreateNew ) pResData->m_aList.clear(); } } OString Export::GetPairedListID(const OString& rText) { // < "STRING" ; IDENTIFIER ; > ; return rText.getToken(1, ';').toAsciiUpperCase().replace('\t', ' ').trim(); } OString Export::GetPairedListString(const OString& rText) { // < "STRING" ; IDENTIFIER ; > ; OString sString(rText.getToken(0, ';').replace('\t', ' ')); sString = sString.trim(); OString s1(sString.copy(sString.indexOf('"') + 1)); sString = s1.copy(0, s1.lastIndexOf('"')); return sString.trim(); } OString Export::StripList(const OString & rText) { OString s1 = rText.copy( rText.indexOf('\"') + 1); return s1.copy( 0 , s1.lastIndexOf('\"')); } void Export::WriteExportList(ResData *pResData, ExportList& rExportList, const ExportListType nTyp) { OString sGID(pResData->sGId); if (sGID.isEmpty()) sGID = pResData->sId; else { sGID += "."; sGID += pResData->sId; while (sGID.endsWith(".")) { sGID = sGID.copy(0, sGID.getLength() - 1); } } for ( size_t i = 0; i < rExportList.size(); i++ ) { OString sLID; OString sText(rExportList[ i ]); // Strip PairList Line String if (nTyp == ExportListType::Paired) { sLID = GetPairedListID( sText ); sText = GetPairedListString( sText ); } else { sText = StripList( sText ); if( sText == "\\\"" ) sText = "\""; } ConvertExportContent(sText); if (nTyp != ExportListType::Paired) sLID = sText; OString sType = lcl_GetListTyp( nList, false ); common::writePoEntry( "Transex3", *aOutput.mPo, global::inputPathname, sType, sGID, sLID, OString(), sText); } } OString Export::FullId() { OStringBuffer sFull; if ( nLevel > 1 ) { sFull.append(aResStack[ 0 ]->sId); for ( size_t i = 1; i < nLevel - 1; ++i ) { OString sToAdd = aResStack[ i ]->sId; if (!sToAdd.isEmpty()) sFull.append('.').append(sToAdd); } } if (sFull.getLength() > 255) { printf("GroupID = %s\n", sFull.getStr()); yyerror("GroupId > 255 chars"); } return sFull.makeStringAndClear(); } void Export::InsertListEntry(const OString &rLine) { ResData *pResData = ( nLevel-1 < aResStack.size() ) ? aResStack[ nLevel-1 ] : nullptr; if (!pResData) std::exit(EXIT_FAILURE); pResData->m_aList.push_back(rLine); } void Export::CleanValue( OString &rValue ) { while ( !rValue.isEmpty()) { if (( rValue[0] == ' ' ) || ( rValue[0] == '\t' )) rValue = rValue.copy( 1 ); else break; } if ( !rValue.isEmpty()) { for ( sal_Int32 i = rValue.getLength() - 1; i > 0; i-- ) { if (( rValue[i] == ' ' ) || ( rValue[i] == '\t' ) || ( rValue[i] == '\n' ) || ( rValue[i] == ';' ) || ( rValue[i] == '{' ) || ( rValue[i] == '\\' ) || ( rValue[i] == '\r' )) rValue = rValue.copy(0, i); else break; } } } enum class TextState { Text=1, Macro }; OString Export::GetText(const OString &rSource, int nToken) { OString sReturn; switch ( nToken ) { case TEXTLINE: case LONGTEXTLINE: { OString sTmp(rSource.copy(rSource.indexOf('='))); CleanValue( sTmp ); sTmp = sTmp.replaceAll("\n", OString()). replaceAll("\r", OString()). replaceAll("\\\\\"", "-=<[BSlashBSlashHKom]>=-\""). replaceAll("\\\"", "-=<[Hochkomma]>=-"). replaceAll("\\", "-=<[0x7F]>=-"). replaceAll("\\0x7F", "-=<[0x7F]>=-"); TextState nState = TextState::Text; for (sal_Int32 i = 1; i <= lcl_countOccurrences(sTmp, '"'); ++i) { OString sToken(sTmp.getToken(i, '"')); if (!sToken.isEmpty()) { if ( nState == TextState::Text ) { sReturn += sToken; nState = TextState::Macro; } else { sToken = sToken.replace('\t', ' '); for (;;) { sal_Int32 n = 0; sToken = sToken.replaceFirst(" ", " ", &n); if (n == -1) { break; } } sToken = sToken.trim(); if (!sToken.isEmpty()) { sReturn += "\\\" "; sReturn += sToken; sReturn += " \\\""; } nState = TextState::Text; } } } sReturn = sReturn.replaceAll("-=<[0x7F]>=-", ""). replaceAll("-=<[Hochkomma]>=-", "\""). replaceAll("-=<[BSlashBSlashHKom]>=-", "\\\\"). replaceAll("\\\\", "-=<[BSlashBSlash]>=-"). replaceAll("-=<[BSlashBSlash]>=-", "\\"); } break; } return sReturn; } void Export::WriteToMerged(const OString &rText , bool bSDFContent) { OString sText(rText); for (;;) { sal_Int32 n = 0; sText = sText.replaceFirst(" \n", "\n", &n); if (n == -1) { break; } } if (pParseQueue->bNextIsM && bSDFContent && sText.getLength() > 2) { for (sal_Int32 n = 0; n < sText.getLength(); ++n) { if (sText[n] == '\n' && sText[n - 1] != '\\') { sText = sText.replaceAt(n++, 0, "\\"); } } } else if (pParseQueue->bLastWasM && sText.getLength() > 2) { for (sal_Int32 n = 0; n < sText.getLength(); ++n) { if (sText[n] == '\n' && sText[n - 1] != '\\') { sText = sText.replaceAt(n++, 0, "\\"); } if (sText[n] == '\n') { pParseQueue->bMflag = true; } } } else if (pParseQueue->bCurrentIsM && bSDFContent && sText.getLength() > 2) { for (sal_Int32 n = 0; n < sText.getLength(); ++n) { if (sText[n] == '\n' && sText[n - 1] != '\\') { sText = sText.replaceAt(n++, 0, "\\"); pParseQueue->bMflag = true; } } } else if (pParseQueue->bMflag) { for (sal_Int32 n = 1; n < sText.getLength(); ++n) { if (sText[n] == '\n' && sText[n - 1] != '\\') { sText = sText.replaceAt(n++, 0, "\\"); } } } for (sal_Int32 i = 0; i < sText.getLength(); ++i) { if (sText[i] == '\n') { *aOutput.mSimple << '\n'; } else { char cChar = sText[i]; *aOutput.mSimple << cChar; } } } void Export::ConvertMergeContent( OString &rText ) { rText = rText.replaceAll("\\\'","\'"); // Temporary: until PO files contain escaped single quotes // (Maybe next PO update solve this) rText = helper::escapeAll( rText.replaceAll("","\\0x7F"), "\n""\t""\\""\"","\\n""\\t""\\\\""\\\""); rText = "\"" + rText + "\""; } void Export::ConvertExportContent( OString& rText ) { rText = helper::unEscapeAll(rText,"\\n""\\t""\\\\""\\\"","\n""\t""\\""\""); } void Export::ResData2Output( MergeEntrys *pEntry, StringType nType, const OString& rTextType ) { bool bAddSemicolon = false; bool bFirst = true; OString sCur; for( size_t n = 0; n < aLanguages.size(); n++ ){ sCur = aLanguages[ n ]; OString sText; bool bText = pEntry->GetText( sText, nType, sCur , true ); if ( bText && !sText.isEmpty() ) { OStringBuffer sOutput; if ( bNextMustBeDefineEOL) { if ( bFirst ) sOutput.append("\t\\\n"); else sOutput.append(";\t\\\n"); } bFirst=false; sOutput.append("\t" + rTextType); if ( !sCur.equalsIgnoreAsciiCase("en-US") ) { sOutput.append("[ " + sCur + " ] "); } ConvertMergeContent( sText ); sOutput.append("= " + sText); if ( bDefine ) sOutput.append(";\\\n"); else if ( !bNextMustBeDefineEOL ) sOutput.append(";\n"); else bAddSemicolon = true; for ( size_t j = 1; j < nLevel; j++ ) sOutput.append("\t"); WriteToMerged( sOutput.makeStringAndClear() , true ); } } if ( bAddSemicolon ) { WriteToMerged( ";" , false ); } } void Export::MergeRest( ResData *pResData ) { if ( !pMergeDataFile ){ pMergeDataFile = new MergeDataFile( sMergeSrc, global::inputPathname, true ); aLanguages = pMergeDataFile->GetLanguages(); } MergeEntrys *pEntry = nullptr; if( pResData->bText || pResData->bQuickHelpText || pResData->bTitle ) pEntry = pMergeDataFile->GetMergeEntrysCaseSensitive( pResData ); if ( pEntry ) { if ( pResData->bText ) ResData2Output( pEntry, StringType::Text, pResData->sTextTyp ); if ( pResData->bQuickHelpText ) ResData2Output( pEntry, StringType::QuickHelpText, OString("QuickHelpText") ); if ( pResData->bTitle ) ResData2Output( pEntry, StringType::Title, OString("Title") ); } // Merge Lists if ( nList != ExportListType::NONE ) { OString sOldId = pResData->sId; OString sOldGId = pResData->sGId; OString sOldTyp = pResData->sResTyp; // Set pResData so we can find the corresponding string if (!pResData->sGId.isEmpty()) pResData->sGId = pResData->sGId + OString('.'); pResData->sGId = pResData->sGId + pResData->sId; pResData->sResTyp = lcl_GetListTyp( nList, false ); OString sSpace; for ( sal_uInt16 i = 1; i < nLevel-1; i++ ) sSpace += "\t"; OString sCur; for( size_t n = 0; n < aLanguages.size(); n++ ) { sCur = aLanguages[ n ]; sal_uInt16 nLIndex = 0; sal_uInt16 nMaxIndex = pResData->m_aList.size(); while( nLIndex < nMaxIndex ) { if ( nLIndex == 0 ) { OStringBuffer sHead; if ( bNextMustBeDefineEOL ) sHead.append("\\\n\t"); sHead.append(sSpace + lcl_GetListTyp( nList, true ) + " [ " + sCur + " ] "); if ( bDefine || bNextMustBeDefineEOL ) { sHead.append("= \\\n" + sSpace + "\t{\\\n\t"); } else { sHead.append("= \n" + sSpace + "\t{\n\t"); } WriteToMerged(sHead.makeStringAndClear() , true); } OString sLine = pResData->m_aList[ nLIndex ]; if ( sLine.indexOf( '>' ) != -1 ) { if ((( sLine.indexOf( '{' ) == -1 ) || ( sLine.indexOf( '{' ) >= sLine.indexOf( '"' ))) && (( sLine.indexOf( '<' ) == -1 ) || ( sLine.indexOf( '<' ) >= sLine.indexOf( '"' )))) { sLine = sLine.replaceFirst("\"", "< \"" ); } } // Set matching identifier if ( nList == ExportListType::Paired ) { pResData->sId = GetPairedListID ( sLine ); } else { pResData->sId = sLine.copy( sLine.indexOf('"')+1, sLine.lastIndexOf('"')-sLine.indexOf('"')-1); ConvertExportContent( pResData->sId ); } MergeEntrys* pEntrys = pMergeDataFile->GetMergeEntrysCaseSensitive( pResData ); if( pEntrys ) { OString sText; pEntrys->GetText( sText, StringType::Text, sCur ); if( !sText.isEmpty()) { ConvertMergeContent( sText ); sLine = sLine.copy( 0 , sLine.indexOf('"') ) + sText + sLine.copy( sLine.lastIndexOf('"') + 1 ); } } OString sText1( "\t" ); sText1 += sLine; if ( bDefine || bNextMustBeDefineEOL ) sText1 += " ;\\\n"; else sText1 += " ;\n"; sText1 += sSpace; sText1 += "\t"; WriteToMerged( sText1 ,true ); ++nLIndex; } if ( nLIndex > 0 ) { OString sFooter; if (!sSpace.isEmpty()) sFooter = sSpace.copy(1); if ( bNextMustBeDefineEOL ) sFooter += "};"; else if ( !bDefine ) sFooter += "};\n\t"; else sFooter += "\n\n"; WriteToMerged( sFooter ,true ); } } pResData->sId = sOldId; pResData->sGId = sOldGId; pResData->sResTyp = sOldTyp; } pParseQueue->bMflag = false; } void Export::SetChildWithText() { if ( aResStack.size() > 1 ) { for ( size_t i = 0; i < aResStack.size() - 1; i++ ) { aResStack[ i ]->bChildWithText = true; } } } void ParserQueue::Push( const QueueEntry& aEntry ) { sal_Int32 nLen = aEntry.sLine.getLength(); if( !bStart ){ aQueueCur->push( aEntry ); if( nLen > 1 && aEntry.sLine[nLen-1] == '\n' ) bStart = true; else if ( aEntry.nTyp != IGNOREDTOKENS ){ if( nLen > 1 && ( aEntry.sLine[nLen-1] == '\\') ){ // Next is Macro bCurrentIsM = true; }else{ // Next is no Macro bCurrentIsM = false; } } } else{ aQueueNext->push( aEntry ); if( nLen > 1 && aEntry.sLine[nLen-1] != '\n' ){ if( nLen > 1 && ( aEntry.sLine[nLen-1] == '\\') ){ // Next is Macro bNextIsM = true; } else{ // Next is no Macro bNextIsM = false; } }else if( nLen > 2 && aEntry.sLine[nLen-1] == '\n' ){ if( aEntry.nTyp != IGNOREDTOKENS ){ if( nLen > 2 && ( aEntry.sLine[nLen-2] == '\\') ){ // Next is Macro bNextIsM = true; } else{ // Next is no Macro bNextIsM = false; } } // Pop current Pop( *aQueueCur ); bLastWasM = bCurrentIsM; // next -> current bCurrentIsM = bNextIsM; std::queue* aQref = aQueueCur; aQueueCur = aQueueNext; aQueueNext = aQref; } else{ // Pop current Pop( *aQueueCur ); bLastWasM = bCurrentIsM; // next -> current bCurrentIsM = bNextIsM; std::queue* aQref = aQueueCur; aQueueCur = aQueueNext; aQueueNext = aQref; } } } void ParserQueue::Close(){ // Pop current Pop( *aQueueCur ); // next -> current bLastWasM = bCurrentIsM; bCurrentIsM = bNextIsM; std::queue* aQref = aQueueCur; aQueueCur = aQueueNext; aQueueNext = aQref; bNextIsM = false; Pop( *aQueueNext ); }; void ParserQueue::Pop( std::queue& aQueue ) { while (!aQueue.empty()) { QueueEntry aEntry = aQueue.front(); aQueue.pop(); aExport.Execute(aEntry.nTyp, aEntry.sLine.getStr()); } } ParserQueue::ParserQueue( Export& aExportObj ) : bCurrentIsM( false ), bNextIsM( false ) , bLastWasM( false ), bMflag( false ) , aExport( aExportObj ) , bStart( false ) { aQueueNext = new std::queue; aQueueCur = new std::queue; } ParserQueue::~ParserQueue() { delete aQueueNext; delete aQueueCur; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */