diff options
Diffstat (limited to 'l10ntools/source')
51 files changed, 23263 insertions, 0 deletions
diff --git a/l10ntools/source/cfg_yy_wrapper.c b/l10ntools/source/cfg_yy_wrapper.c new file mode 100644 index 000000000000..ecfb35b30df5 --- /dev/null +++ b/l10ntools/source/cfg_yy_wrapper.c @@ -0,0 +1,5 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +// Helper to suppress warnings in lex generated c code, see #i57362# +#include "cfg_yy.c" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/cfglex.l b/l10ntools/source/cfglex.l new file mode 100644 index 000000000000..a6f6b366a8d5 --- /dev/null +++ b/l10ntools/source/cfglex.l @@ -0,0 +1,221 @@ +%{ +/* + * lexer for parsing cfg source files + * + */ + + +/* enlarge token buffer to tokenize whole strings */ +#undef YYLMAX +#define YYLMAX 64000 + +/* to enable debug output define LEXDEBUG */ +#define LEXDEBUG 1 +#ifdef LEXDEBUG +#define OUTPUT fprintf +#else +#define OUTPUT(Par1,Par2); +#endif + +/* table of possible token ids */ +#include "tokens.h" +#include <stdlib.h> +#include <stdio.h> + +#if defined __GNUC__ +#pragma GCC system_header +#elif defined __SINPRO_CC +#pragma disable_warn +#elif defined _MSC_VER +#pragma warning(push, 1) +#endif + +int yycolumn = 1; +#define YY_USER_ACTION yycolumn += yyleng; + +/* external functions (C++ code, declared as extren "C" */ +extern int WorkOnTokenSet( int, char* ); +extern int InitCfgExport( char * , char *); +extern int EndCfgExport(); +extern int GetError(); +extern int SetError(); +extern char *GetOutputFile( int argc, char* argv[]); +extern FILE *GetCfgFile(); +extern int isQuiet(); +extern void removeTempFile(); +extern char* getFilename(); +/* forwards */ +void YYWarning(); + +int bText=0; +%} + +%p 24000 +%e 1200 +%n 500 + +%% + +\<[^\>]*"xml:lang="\""x-no-translate"\"[^\<]*\/\> { + bText = 0; + WorkOnTokenSet( CFG_TOKEN_NO_TRANSLATE, yytext ); +} + +\<.*\/\> { + bText = 0; + WorkOnTokenSet( ANYTOKEN, yytext ); +} + +\<[^\>]*"xml:lang="\".*\"[^\<]*\> { + bText = 1; + WorkOnTokenSet( CFG_TEXT_START, yytext ); +} + + +\<[^\/\!][^\>]*\> { + bText = 0; + WorkOnTokenSet( CFG_TAG, yytext ); +} + +"<!"DOCTYPE[^\>]*\> { + bText = 0; + WorkOnTokenSet( CFG_TAG, yytext ); +} + + +\<\!\-\- { + char c1 = 0, c2 = 0, c3 = input(); + char pChar[2]; + pChar[1] = 0x00; + pChar[0] = c3; + + WorkOnTokenSet( COMMEND, yytext ); + WorkOnTokenSet( COMMEND, pChar ); + + for(;;) { + if ( c3 == EOF ) + break; + if ( c1 == '-' && c2 == '-' && c3 == '>' ) + break; + c1 = c2; + c2 = c3; + c3 = input(); + pChar[0] = c3; + WorkOnTokenSet( COMMEND, pChar ); + } +} + +\<\/[^\>]*\> { + bText = 0; + WorkOnTokenSet( CFG_CLOSETAG, yytext ); +} + +\<[^\>\!]*\> { + bText = 0; + if ( yytext[ 1 ] == '!' && yytext[ 2 ] == '-' && yytext[ 3 ] == '-' ) + WorkOnTokenSet( COMMEND, yytext ); + else + WorkOnTokenSet( CFG_UNKNOWNTAG, yytext ); +} + +.|\n { + yycolumn = 1; + if ( bText == 1 ) + WorkOnTokenSet( CFG_TEXTCHAR, yytext ); + else + WorkOnTokenSet( UNKNOWNCHAR, yytext ); +} + + +%% + +/*****************************************************************************/ +int yywrap(void) +/*****************************************************************************/ +{ + return 1; +} + +/*****************************************************************************/ +void YYWarning( char *s ) +/*****************************************************************************/ +{ + /* write warning to stderr */ + fprintf( stderr, + "Warning: \"%s\" in line %d, column %d: \"%s\"\n", s, yylineno, yycolumn, yytext ); +} + +/*****************************************************************************/ +#ifdef GCC +void yyerror ( char *s, ... ) +#else +void yyerror ( char *s ) +#endif +/*****************************************************************************/ +{ + /* write error to stderr */ + fprintf( stderr, + "Error: \"%s\" in line %d, column %d: \"%s\"\n", s, yylineno, yycolumn, yytext ); + SetError(); +} + +/*****************************************************************************/ +int +#ifdef WNT +_cdecl +#endif +main( int argc, char* argv[]) +/*****************************************************************************/ +{ + /* error level */ + int nRetValue = 0; + char *pOutput; + FILE *pFile; + + pOutput = GetOutputFile( argc, argv ); + + if ( !pOutput ) { + fprintf( stdout, "Syntax: CFGEX[-p Prj][-r PrjRoot]-i FileIn [-o FileOut][-m DataBase][-e][-b][-u][-f][-d DoneFile][-g[:dtd] ][-L l1,l2,...]\n" ); + fprintf( stdout, " Prj: Project\n" ); + fprintf( stdout, " PrjRoot: Path to project root (..\\.. etc.)\n" ); + fprintf( stdout, " FileIn: Source files (*.src)\n" ); + fprintf( stdout, " FileOut: Destination file (*.*)\n" ); + fprintf( stdout, " DataBase: Mergedata (*.sdf)\n" ); + fprintf( stdout, " -e: Disable writing errorlog\n" ); + fprintf( stdout, " -b: Break when Token \"HelpText\" found in source\n" ); + fprintf( stdout, " -u: [english] and [german] are allowed, Id is Taken from DataBase \n" ); + fprintf( stdout, " -f: force extraction and merge even if only one language is existent\n" ); + fprintf( stdout, " -g[:dtd]: enables generation of properties (dtds if :dtd is set) - in this case FileOut is the output path\n" ); + fprintf( stdout, " -d: enables generation of *.don if work is done\n" ); + fprintf( stdout, " -L: Restrict the handled languages. l1,l2,... are elements of (de,en-US...)\n" ); + fprintf( stdout, " A fallback language can be defined like this: l1=f1.\n" ); + fprintf( stdout, " f1, f2,... are also elements of (de,en-US...)\n" ); + fprintf( stdout, " Example: -L de,es=en-US\n" ); + fprintf( stdout, " Restriction to de and es, en-US will be fallback for es\n" ); + return 1; + } + + pFile = GetCfgFile(); + InitCfgExport( pOutput , getFilename() ); + if ( !pFile ) + return 1; + + yyin = pFile; + + /* create global instance of class CfgExport */ + //InitCfgExport( pOutput ); + + /* start parser */ + yylex(); + + /* get error info. and end export */ + nRetValue = GetError(); + EndCfgExport(); + + + removeTempFile(); +/* return error level */ + return nRetValue; +} + + diff --git a/l10ntools/source/cfgmerge.cxx b/l10ntools/source/cfgmerge.cxx new file mode 100644 index 000000000000..cbbe329e669b --- /dev/null +++ b/l10ntools/source/cfgmerge.cxx @@ -0,0 +1,876 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_l10ntools.hxx" +#include <stdio.h> +#include <tools/string.hxx> +#include <tools/fsys.hxx> + +// local includes +#include "export.hxx" +#include "cfgmerge.hxx" +#include "tokens.h" +#include "utf8conv.hxx" + +extern "C" { int yyerror( char * ); } +extern "C" { int YYWarning( char * ); } + +// defines to parse command line +#define STATE_NON 0x0001 +#define STATE_INPUT 0x0002 +#define STATE_OUTPUT 0x0003 +#define STATE_PRJ 0x0004 +#define STATE_ROOT 0x0005 +#define STATE_MERGESRC 0x0006 +#define STATE_ERRORLOG 0x0007 +#define STATE_UTF8 0x0008 +#define STATE_LANGUAGES 0X0009 +#define STATE_ISOCODE99 0x000A +#define STATE_FORCE 0x000B + +// set of global variables +BOOL bEnableExport; +BOOL bMergeMode; +BOOL bErrorLog; +BOOL bForce; +BOOL bUTF8; +ByteString sPrj; +ByteString sPrjRoot; +ByteString sInputFileName; +ByteString sActFileName; +ByteString sFullEntry; +ByteString sOutputFile; +ByteString sMergeSrc; +String sUsedTempFile; + +CfgParser *pParser; + +extern "C" { +// the whole interface to lexer is in this extern "C" section + +/*****************************************************************************/ +extern char *GetOutputFile( int argc, char* argv[]) +/*****************************************************************************/ +{ + bEnableExport = FALSE; + bMergeMode = FALSE; + bErrorLog = TRUE; + bForce = FALSE; + bUTF8 = TRUE; + sPrj = ""; + sPrjRoot = ""; + sInputFileName = ""; + sActFileName = ""; + + USHORT nState = STATE_NON; + BOOL bInput = FALSE; + + // parse command line + for( int i = 1; i < argc; i++ ) { + ByteString sSwitch( argv[ i ] ); + sSwitch.ToUpperAscii(); + + if ( sSwitch == "-I" ) { + nState = STATE_INPUT; // next token specifies source file + } + else if ( sSwitch == "-O" ) { + nState = STATE_OUTPUT; // next token specifies the dest file + } + else if ( sSwitch == "-P" ) { + nState = STATE_PRJ; // next token specifies the cur. project + } + else if ( sSwitch == "-R" ) { + nState = STATE_ROOT; // next token specifies path to project root + } + else if ( sSwitch == "-M" ) { + nState = STATE_MERGESRC; // next token specifies the merge database + } + else if ( sSwitch == "-E" ) { + nState = STATE_ERRORLOG; + bErrorLog = FALSE; + } + else if ( sSwitch == "-UTF8" ) { + nState = STATE_UTF8; + bUTF8 = TRUE; + } + else if ( sSwitch == "-NOUTF8" ) { + nState = STATE_UTF8; + bUTF8 = FALSE; + } + else if ( sSwitch == "-F" ) { + nState = STATE_FORCE; + bForce = TRUE; + } + else if ( sSwitch == "-L" ) { + nState = STATE_LANGUAGES; + } + else if ( sSwitch.ToUpperAscii() == "-ISO99" ) { + nState = STATE_ISOCODE99; + } + else { + switch ( nState ) { + case STATE_NON: { + return NULL; // no valid command line + } + case STATE_INPUT: { + sInputFileName = argv[ i ]; + bInput = TRUE; // source file found + } + break; + case STATE_OUTPUT: { + sOutputFile = argv[ i ]; // the dest. file + } + break; + case STATE_PRJ: { + sPrj = ByteString( argv[ i ]); +// sPrj.ToLowerAscii(); // the project + } + break; + case STATE_ROOT: { + sPrjRoot = ByteString( argv[ i ]); // path to project root + } + break; + case STATE_MERGESRC: { + sMergeSrc = ByteString( argv[ i ]); + bMergeMode = TRUE; // activate merge mode, cause merge database found + } + break; + case STATE_LANGUAGES: { + Export::sLanguages = ByteString( argv[ i ]); + } + break; + } + } + } + + if ( bInput ) { + // command line is valid + bEnableExport = TRUE; + char *pReturn = new char[ sOutputFile.Len() + 1 ]; + strcpy( pReturn, sOutputFile.GetBuffer()); // #100211# - checked + return pReturn; + } + + // command line is not valid + return NULL; +} +/*****************************************************************************/ +int InitCfgExport( char *pOutput , char* pFilename ) +/*****************************************************************************/ +{ + // instanciate Export + ByteString sOutput( pOutput ); + ByteString sFilename( pFilename ); + Export::InitLanguages(); + + if ( bMergeMode ) + pParser = new CfgMerge( sMergeSrc, sOutputFile, sFilename ); + else if ( sOutputFile.Len()) + pParser = new CfgExport( sOutputFile, sPrj, sActFileName ); + + return 1; +} + +/*****************************************************************************/ +int EndCfgExport() +/*****************************************************************************/ +{ + delete pParser; + + return 1; +} + +void removeTempFile(){ + if( !sUsedTempFile.EqualsIgnoreCaseAscii( "" ) ){ + DirEntry aTempFile( sUsedTempFile ); + aTempFile.Kill(); + } +} +extern const char* getFilename() +{ + return sInputFileName.GetBuffer(); +} +/*****************************************************************************/ +extern FILE *GetCfgFile() +/*****************************************************************************/ +{ + FILE *pFile = 0; + // look for valid filename + if ( sInputFileName.Len()) { + if( Export::fileHasUTF8ByteOrderMarker( sInputFileName ) ){ + DirEntry aTempFile = Export::GetTempFile(); + DirEntry aSourceFile( String( sInputFileName , RTL_TEXTENCODING_ASCII_US ) ); + aSourceFile.CopyTo( aTempFile , FSYS_ACTION_COPYFILE ); + String sTempFile = aTempFile.GetFull(); + Export::RemoveUTF8ByteOrderMarkerFromFile( ByteString( sTempFile , RTL_TEXTENCODING_ASCII_US ) ); + pFile = fopen( ByteString( sTempFile , RTL_TEXTENCODING_ASCII_US ).GetBuffer(), "r" ); + sUsedTempFile = sTempFile; + }else{ + // able to open file? + pFile = fopen( sInputFileName.GetBuffer(), "r" ); + sUsedTempFile = String::CreateFromAscii(""); + } + if ( !pFile ){ + fprintf( stderr, "Error: Could not open file %s\n", + sInputFileName.GetBuffer()); + exit( -13 ); + } + else { + // this is a valid file which can be opened, so + // create path to project root + DirEntry aEntry( String( sInputFileName, RTL_TEXTENCODING_ASCII_US )); + aEntry.ToAbs(); + sFullEntry= ByteString( aEntry.GetFull(), RTL_TEXTENCODING_ASCII_US ); + aEntry += DirEntry( String( "..", RTL_TEXTENCODING_ASCII_US )); + aEntry += DirEntry( sPrjRoot ); + ByteString sPrjEntry( aEntry.GetFull(), RTL_TEXTENCODING_ASCII_US ); + + // create file name, beginnig with project root + // (e.g.: source\ui\src\menue.src) +// printf("sFullEntry = %s\n",sFullEntry.GetBuffer()); + sActFileName = sFullEntry.Copy( sPrjEntry.Len() + 1 ); +// printf("sActFileName = %s\n",sActFileName.GetBuffer()); + + sActFileName.SearchAndReplaceAll( "/", "\\" ); + + return pFile; + } + } + // this means the file could not be opened + return NULL; +} + +/*****************************************************************************/ +int WorkOnTokenSet( int nTyp, char *pTokenText ) +/*****************************************************************************/ +{ + pParser->Execute( nTyp, pTokenText ); + + return 1; +} + + +/*****************************************************************************/ +int SetError() +/*****************************************************************************/ +{ + return 1; +} + +/*****************************************************************************/ +int GetError() +/*****************************************************************************/ +{ + return 0; +} +} + +// +// class CfgStackData +// + +CfgStackData* CfgStack::Push( const ByteString &rTag, const ByteString &rId ) +{ + CfgStackData *pD = new CfgStackData( rTag, rId ); + maList.push_back( pD ); + return pD; +} + +// +// class CfgStack +// + +/*****************************************************************************/ +CfgStack::~CfgStack() +/*****************************************************************************/ +{ + for ( size_t i = 0, n = maList.size(); i < n; i++ ) + delete maList[ i ]; + maList.clear(); +} + +/*****************************************************************************/ +ByteString CfgStack::GetAccessPath( size_t nPos ) +/*****************************************************************************/ +{ + if ( nPos == LIST_APPEND ) + nPos = maList.size() - 1; + + ByteString sReturn; + for ( size_t i = 0; i <= nPos; i++ ) { + if ( i ) + sReturn += "."; + sReturn += GetStackData( i )->GetIdentifier(); + } + + return sReturn; +} + +/*****************************************************************************/ +CfgStackData *CfgStack::GetStackData( size_t nPos ) +/*****************************************************************************/ +{ + if ( nPos == LIST_APPEND ) + nPos = maList.size() - 1; + + return maList[ nPos ]; +} + +// +// class CfgParser +// + +/*****************************************************************************/ +CfgParser::CfgParser() +/*****************************************************************************/ + : pStackData( NULL ), + bLocalize( FALSE ) +{ +} + +/*****************************************************************************/ +CfgParser::~CfgParser() +/*****************************************************************************/ +{ +} + + +/*****************************************************************************/ +BOOL CfgParser::IsTokenClosed( const ByteString &rToken ) +/*****************************************************************************/ +{ + return rToken.GetChar( rToken.Len() - 2 ) == '/'; +} + +/*****************************************************************************/ +void CfgParser::AddText( + ByteString &rText, + const ByteString &rIsoLang, + const ByteString &rResTyp +) +/*****************************************************************************/ +{ + USHORT nTextLen = 0; + while ( rText.Len() != nTextLen ) { + nTextLen = rText.Len(); + rText.SearchAndReplaceAll( "\n", " " ); + rText.SearchAndReplaceAll( "\r", " " ); + rText.SearchAndReplaceAll( "\t", " " ); + rText.SearchAndReplaceAll( " ", " " ); + } + pStackData->sResTyp = rResTyp; + WorkOnText( rText, rIsoLang ); + + pStackData->sText[ rIsoLang ] = rText; +} + + +/*****************************************************************************/ +void CfgParser::WorkOnRessourceEnd() +/*****************************************************************************/ +{ +} + +/*****************************************************************************/ +int CfgParser::ExecuteAnalyzedToken( int nToken, char *pToken ) +/*****************************************************************************/ +{ + ByteString sToken( pToken ); + + if ( sToken == " " || sToken == "\t" ) + sLastWhitespace += sToken; + + ByteString sTokenName; + ByteString sTokenId; + + BOOL bOutput = TRUE; + + switch ( nToken ) { + case CFG_TOKEN_PACKAGE: + case CFG_TOKEN_COMPONENT: + case CFG_TOKEN_TEMPLATE: + case CFG_TOKEN_CONFIGNAME: + case CFG_TOKEN_OORNAME: + case CFG_TOKEN_OORVALUE: + case CFG_TAG: + case ANYTOKEN: + case CFG_TEXT_START: + { + sTokenName = sToken.GetToken( 1, '<' ).GetToken( 0, '>' ).GetToken( 0, ' ' ); + + if ( !IsTokenClosed( sToken )) { + ByteString sSearch; + switch ( nToken ) { + case CFG_TOKEN_PACKAGE: + sSearch = "package-id="; + break; + case CFG_TOKEN_COMPONENT: + sSearch = "component-id="; + break; + case CFG_TOKEN_TEMPLATE: + sSearch = "template-id="; + break; + case CFG_TOKEN_CONFIGNAME: + sSearch = "cfg:name="; + break; + case CFG_TOKEN_OORNAME: + sSearch = "oor:name="; + bLocalize = TRUE; + break; + case CFG_TOKEN_OORVALUE: + sSearch = "oor:value="; + break; + case CFG_TEXT_START: { + if ( sCurrentResTyp != sTokenName ) { + WorkOnRessourceEnd(); + ByteString sCur; + for( unsigned int n = 0; n < aLanguages.size(); n++ ){ + sCur = aLanguages[ n ]; + pStackData->sText[ sCur ] = ByteString(""); + } + } + sCurrentResTyp = sTokenName; + + ByteString sTemp = sToken.Copy( sToken.Search( "xml:lang=" )); + sCurrentIsoLang = sTemp.GetToken( 1, '\"' ).GetToken( 0, '\"' ); + + if ( sCurrentIsoLang == NO_TRANSLATE_ISO ) + bLocalize = FALSE; + + pStackData->sTextTag = sToken; + + sCurrentText = ""; + } + break; + } + if ( sSearch.Len()) { + ByteString sTemp = sToken.Copy( sToken.Search( sSearch )); + sTokenId = sTemp.GetToken( 1, '\"' ).GetToken( 0, '\"' ); + } + pStackData = aStack.Push( sTokenName, sTokenId ); + + if ( sSearch == "cfg:name=" ) { + ByteString sTemp( sToken ); + sTemp.ToUpperAscii(); + bLocalize = (( sTemp.Search( "CFG:TYPE=\"STRING\"" ) != STRING_NOTFOUND ) && + ( sTemp.Search( "CFG:LOCALIZED=\"TRUE\"" ) != STRING_NOTFOUND )); + } + } + else if ( sTokenName == "label" ) { + if ( sCurrentResTyp != sTokenName ) { + WorkOnRessourceEnd(); + ByteString sCur; + for( unsigned int n = 0; n < aLanguages.size(); n++ ){ + sCur = aLanguages[ n ]; + pStackData->sText[ sCur ] = ByteString(""); + } + } + sCurrentResTyp = sTokenName; + } + } + break; + case CFG_CLOSETAG: + sTokenName = sToken.GetToken( 1, '/' ).GetToken( 0, '>' ).GetToken( 0, ' ' ); + if ( aStack.GetStackData() && ( aStack.GetStackData()->GetTagType() == sTokenName )) { + if ( ! sCurrentText.Len()) + WorkOnRessourceEnd(); + aStack.Pop(); + pStackData = aStack.GetStackData(); + } + else { + ByteString sError( "Misplaced close tag: " ); + ByteString sInFile(" in file "); + sError += sToken; + sError += sInFile; + sError += sFullEntry; + Error( sError ); + exit ( 13 ); + } + break; + + case CFG_TEXTCHAR: + sCurrentText += sToken; + bOutput = FALSE; + break; + + case CFG_TOKEN_NO_TRANSLATE: + bLocalize = FALSE; + break; + } + + if ( sCurrentText.Len() && nToken != CFG_TEXTCHAR ) { + AddText( sCurrentText, sCurrentIsoLang, sCurrentResTyp ); + Output( sCurrentText ); + sCurrentText = ""; + pStackData->sEndTextTag = sToken; + } + + if ( bOutput ) + Output( sToken ); + + if ( sToken != " " && sToken != "\t" ) + sLastWhitespace = ""; + + return 1; +} + +/*****************************************************************************/ +void CfgExport::Output( const ByteString& rOutput ) +/*****************************************************************************/ +{ + // Dummy operation to suppress warnings caused by poor class design + ByteString a( rOutput ); +} + +/*****************************************************************************/ +int CfgParser::Execute( int nToken, char * pToken ) +/*****************************************************************************/ +{ + ByteString sToken( pToken ); + + switch ( nToken ) { + case CFG_TAG: + if ( sToken.Search( "package-id=" ) != STRING_NOTFOUND ) + return ExecuteAnalyzedToken( CFG_TOKEN_PACKAGE, pToken ); + else if ( sToken.Search( "component-id=" ) != STRING_NOTFOUND ) + return ExecuteAnalyzedToken( CFG_TOKEN_COMPONENT, pToken ); + else if ( sToken.Search( "template-id=" ) != STRING_NOTFOUND ) + return ExecuteAnalyzedToken( CFG_TOKEN_TEMPLATE, pToken ); + else if ( sToken.Search( "cfg:name=" ) != STRING_NOTFOUND ) + return ExecuteAnalyzedToken( CFG_TOKEN_OORNAME, pToken ); + else if ( sToken.Search( "oor:name=" ) != STRING_NOTFOUND ) + return ExecuteAnalyzedToken( CFG_TOKEN_OORNAME, pToken ); + else if ( sToken.Search( "oor:value=" ) != STRING_NOTFOUND ) + return ExecuteAnalyzedToken( CFG_TOKEN_OORVALUE, pToken ); + break; + } + return ExecuteAnalyzedToken( nToken, pToken ); +} + + +/*****************************************************************************/ +void CfgParser::Error( const ByteString &rError ) +/*****************************************************************************/ +{ +// ByteString sError( rError ); +// sError.Append("Error: In file "); +// sError.Append( sActFileName ); + yyerror(( char * ) rError.GetBuffer()); +} + + +// +// class CfgOutputParser +// + +/*****************************************************************************/ +CfgOutputParser::CfgOutputParser( const ByteString &rOutputFile ) +/*****************************************************************************/ +{ + pOutputStream = + new SvFileStream( + String( rOutputFile, RTL_TEXTENCODING_ASCII_US ), + STREAM_STD_WRITE | STREAM_TRUNC + ); + pOutputStream->SetStreamCharSet( RTL_TEXTENCODING_UTF8 ); + + if ( !pOutputStream->IsOpen()) { + ByteString sError( "ERROR: Unable to open output file: " ); + sError += rOutputFile; + Error( sError ); + delete pOutputStream; + pOutputStream = NULL; + exit( -13 ); + } +} + +/*****************************************************************************/ +CfgOutputParser::~CfgOutputParser() +/*****************************************************************************/ +{ + if ( pOutputStream ) { + pOutputStream->Close(); + delete pOutputStream; + } +} + +// +// class CfgExport +// + +/*****************************************************************************/ +CfgExport::CfgExport( + const ByteString &rOutputFile, + const ByteString &rProject, + const ByteString &rFilePath +) +/*****************************************************************************/ + : CfgOutputParser( rOutputFile ), + sPrj( rProject ), + sPath( rFilePath ) +{ + Export::InitLanguages( false ); + aLanguages = Export::GetLanguages(); +} + +/*****************************************************************************/ +CfgExport::~CfgExport() +/*****************************************************************************/ +{ +} + +/*****************************************************************************/ +void CfgExport::WorkOnRessourceEnd() +/*****************************************************************************/ +{ + if ( pOutputStream && bLocalize ) { + if (( pStackData->sText[ ByteString("en-US") ].Len() + ) || + ( bForce && + ( pStackData->sText[ ByteString("de") ].Len() || + pStackData->sText[ ByteString("en-US") ].Len() ))) + { + ByteString sFallback = pStackData->sText[ ByteString("en-US") ]; + + //if ( pStackData->sText[ ByteString("en-US") ].Len()) + // sFallback = pStackData->sText[ ByteString("en-US") ]; + + ByteString sLocalId = pStackData->sIdentifier; + ByteString sGroupId; + if ( aStack.size() == 1 ) { + sGroupId = sLocalId; + sLocalId = ""; + } + else { + sGroupId = aStack.GetAccessPath( aStack.size() - 2 ); + } + + ByteString sTimeStamp( Export::GetTimeStamp()); + + ByteString sCur; + for( unsigned int n = 0; n < aLanguages.size(); n++ ){ + sCur = aLanguages[ n ]; + + ByteString sText = pStackData->sText[ sCur ]; + if ( !sText.Len()) + sText = sFallback; + + Export::UnquotHTML( sText ); + + ByteString sOutput( sPrj ); sOutput += "\t"; + sOutput += sPath; + sOutput += "\t0\t"; + sOutput += pStackData->sResTyp; sOutput += "\t"; + sOutput += sGroupId; sOutput += "\t"; + sOutput += sLocalId; sOutput += "\t\t\t0\t"; + sOutput += sCur; + sOutput += "\t"; + + sOutput += sText; sOutput += "\t\t\t\t"; + sOutput += sTimeStamp; + + //if( !sCur.EqualsIgnoreCaseAscii("de") ||( sCur.EqualsIgnoreCaseAscii("de") && !Export::isMergingGermanAllowed( sPrj ) ) ) + pOutputStream->WriteLine( sOutput ); + } + } + } +} + +/*****************************************************************************/ +void CfgExport::WorkOnText( + ByteString &rText, + const ByteString &rIsoLang +) +/*****************************************************************************/ +{ + if( rIsoLang.Len() ) Export::UnquotHTML( rText ); +} + + +// +// class CfgMerge +// + +/*****************************************************************************/ +CfgMerge::CfgMerge( + const ByteString &rMergeSource, const ByteString &rOutputFile, + ByteString &rFilename ) +/*****************************************************************************/ + : CfgOutputParser( rOutputFile ), + pMergeDataFile( NULL ), + pResData( NULL ), + bGerman( FALSE ), + sFilename( rFilename ), + bEnglish( FALSE ) +{ + if ( rMergeSource.Len()){ + pMergeDataFile = new MergeDataFile( + rMergeSource, sInputFileName , bErrorLog, RTL_TEXTENCODING_MS_1252, true ); + if( Export::sLanguages.EqualsIgnoreCaseAscii("ALL") ){ + Export::SetLanguages( pMergeDataFile->GetLanguages() ); + aLanguages = pMergeDataFile->GetLanguages(); + } + else aLanguages = Export::GetLanguages(); + }else + aLanguages = Export::GetLanguages(); +} + +/*****************************************************************************/ +CfgMerge::~CfgMerge() +/*****************************************************************************/ +{ + delete pMergeDataFile; + delete pResData; +} + +/*****************************************************************************/ +void CfgMerge::WorkOnText( + ByteString &rText, + const ByteString& nLangIndex +) +/*****************************************************************************/ +{ + + if ( pMergeDataFile && bLocalize ) { + if ( !pResData ) { + ByteString sLocalId = pStackData->sIdentifier; + ByteString sGroupId; + if ( aStack.size() == 1 ) { + sGroupId = sLocalId; + sLocalId = ""; + } + else { + sGroupId = aStack.GetAccessPath( aStack.size() - 2 ); + } + + ByteString sPlatform( "" ); + + pResData = new ResData( sPlatform, sGroupId , sFilename ); + pResData->sId = sLocalId; + pResData->sResTyp = pStackData->sResTyp; + } + + //if ( nLangIndex.EqualsIgnoreCaseAscii("de") ) + // bGerman = TRUE; + if (( nLangIndex.EqualsIgnoreCaseAscii("en-US") )) + bEnglish = TRUE; + + PFormEntrys *pEntrys = pMergeDataFile->GetPFormEntrysCaseSensitive( pResData ); + if ( pEntrys ) { + ByteString sContent; + pEntrys->GetText( sContent, STRING_TYP_TEXT, nLangIndex ); + + if ( Export::isAllowed( nLangIndex ) && + ( sContent != "-" ) && ( sContent.Len())) + { +#ifdef MERGE_SOURCE_LANGUAGES + if( nLangIndex.EqualsIgnoreCaseAscii("de") || nLangIndex.EqualsIgnoreCaseAscii("en-US") ) + rText = sContent; +#endif + Export::QuotHTML( rText ); + } + } + } +} + +/*****************************************************************************/ +void CfgMerge::Output( const ByteString& rOutput ) +/*****************************************************************************/ +{ + if ( pOutputStream ) + pOutputStream->Write( rOutput.GetBuffer(), rOutput.Len()); +} + +size_t CfgStack::Push( CfgStackData *pStackData ) +{ + maList.push_back( pStackData ); + return maList.size() - 1; +} + +/*****************************************************************************/ +void CfgMerge::WorkOnRessourceEnd() +/*****************************************************************************/ +{ + + if ( pMergeDataFile && pResData && bLocalize && (( bEnglish ) || bForce )) { + PFormEntrys *pEntrys = pMergeDataFile->GetPFormEntrysCaseSensitive( pResData ); + if ( pEntrys ) { + ByteString sCur; + + for( unsigned int n = 0; n < aLanguages.size(); n++ ){ + sCur = aLanguages[ n ]; + + ByteString sContent; + pEntrys->GetText( sContent, STRING_TYP_TEXT, sCur , TRUE ); + if ( + // (!sCur.EqualsIgnoreCaseAscii("de") ) && + ( !sCur.EqualsIgnoreCaseAscii("en-US") ) && + + ( sContent != "-" ) && ( sContent.Len())) + { + + ByteString sText = sContent; + Export::QuotHTML( sText ); + + ByteString sAdditionalLine( "\t" ); + + ByteString sTextTag = pStackData->sTextTag; + ByteString sTemp = sTextTag.Copy( sTextTag.Search( "xml:lang=" )); + + ByteString sSearch = sTemp.GetToken( 0, '\"' ); + sSearch += "\""; + sSearch += sTemp.GetToken( 1, '\"' ); + sSearch += "\""; + + ByteString sReplace = sTemp.GetToken( 0, '\"' ); + sReplace += "\""; + sReplace += sCur; + sReplace += "\""; + + sTextTag.SearchAndReplace( sSearch, sReplace ); + + sAdditionalLine += sTextTag; + sAdditionalLine += sText; + sAdditionalLine += pStackData->sEndTextTag; + + sAdditionalLine += "\n"; + sAdditionalLine += sLastWhitespace; + + Output( sAdditionalLine ); + } + } + } + } + delete pResData; + pResData = NULL; + bGerman = FALSE; + bEnglish = FALSE; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/directory.cxx b/l10ntools/source/directory.cxx new file mode 100644 index 000000000000..bca2e399170c --- /dev/null +++ b/l10ntools/source/directory.cxx @@ -0,0 +1,273 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_l10ntools.hxx" +#include <l10ntools/directory.hxx> +#include "tools/string.hxx" +#include <iostream> +#include <vector> +#include <algorithm> + +namespace transex +{ + +Directory::Directory( const rtl::OUString sFullpath ) : bSkipLinks( false ) +{ + sFullName = sFullpath; +} + +Directory::Directory( const rtl::OUString sFullPath , const rtl::OUString sEntry ) : bSkipLinks( false ) +{ + sFullName = sFullPath; + sDirectoryName = sEntry; +} + + +Directory::Directory( const ByteString sFullPath ) : bSkipLinks( false ) +{ + sDirectoryName = rtl::OUString( sFullPath.GetBuffer() , RTL_TEXTENCODING_UTF8 , sFullPath.Len() ); +} + +bool Directory::lessDir ( const Directory& rKey1, const Directory& rKey2 ) +{ + rtl::OUString sName1( ( static_cast< Directory >( rKey1 ) ).getDirectoryName() ); + rtl::OUString sName2( ( static_cast< Directory >( rKey2 ) ).getDirectoryName() ); + + return sName1.compareTo( sName2 ) < 0 ; +} + + +void Directory::dump() +{ + + for( std::vector< transex::File >::iterator iter = aFileVec.begin() ; iter != aFileVec.end() ; ++iter ) + { + std::cout << "FILE " << rtl::OUStringToOString( (*iter).getFullName().getStr() , RTL_TEXTENCODING_UTF8 , (*iter).getFullName().getLength() ).getStr() << "\n"; + } + + for( std::vector< transex::Directory >::iterator iter = aDirVec.begin() ; iter != aDirVec.end() ; ++iter ) + { + std::cout << "DIR " << rtl::OUStringToOString( (*iter).getFullName().getStr() , RTL_TEXTENCODING_UTF8 , (*iter).getFullName().getLength() ).getStr() << "\n"; + } + +} + +void Directory::scanSubDir( int nLevels ) +{ + readDirectory( sFullName ); + dump(); + if( nLevels > 0 ) { + for( std::vector< transex::Directory >::iterator iter = aDirVec.begin() ; iter != aDirVec.end() || nLevels > 0 ; ++iter , nLevels-- ) + { + ( *iter ).scanSubDir(); + } + } +} + +void Directory::setSkipLinks( bool is_skipped ) +{ + bSkipLinks = is_skipped; +} + +void Directory::readDirectory() +{ + readDirectory( sFullName ); +} + +#ifdef WNT +#include <tools/prewin.h> +#include <windows.h> +#include <tools/postwin.h> + +void Directory::readDirectory ( const rtl::OUString& sFullpath ) +{ + BOOL fFinished; + HANDLE hList; + TCHAR szDir[MAX_PATH+1]; + TCHAR szSubDir[MAX_PATH+1]; + WIN32_FIND_DATA FileData; + + rtl::OString sFullpathext = rtl::OUStringToOString( sFullpath , RTL_TEXTENCODING_UTF8 , sFullpath.getLength() ); + const char *dirname = sFullpathext.getStr(); + + // Get the proper directory path + sprintf(szDir, "%s\\*", dirname); + + // Get the first file + hList = FindFirstFile(szDir, &FileData); + if (hList == INVALID_HANDLE_VALUE) + { + //FindClose(hList); + //printf("No files found %s\n", szDir ); return; + } + else + { + fFinished = FALSE; + while (!fFinished) + { + + sprintf(szSubDir, "%s\\%s", dirname, FileData.cFileName); + rtl::OString myfile( FileData.cFileName ); + rtl::OString mydir( szSubDir ); + + if (FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if ( (strcmp(FileData.cFileName, ".") != 0 ) && + (strcmp(FileData.cFileName, "..") != 0 ) ) + { + //sprintf(szSubDir, "%s\\%s", dirname, FileData.cFileName); + transex::Directory aDir( rtl::OStringToOUString( mydir , RTL_TEXTENCODING_UTF8 , mydir.getLength() ), + rtl::OStringToOUString( myfile , RTL_TEXTENCODING_UTF8 , myfile.getLength() ) ); + aDirVec.push_back( aDir ); + } + } + else + { + transex::File aFile( rtl::OStringToOUString( mydir , RTL_TEXTENCODING_UTF8 , mydir.getLength() ), + rtl::OStringToOUString( myfile , RTL_TEXTENCODING_UTF8 , myfile.getLength() ) ); + aFileVec.push_back( aFile ); + } + if (!FindNextFile(hList, &FileData)) + { + if (GetLastError() == ERROR_NO_MORE_FILES) + { + fFinished = TRUE; + } + } + } + } + + FindClose(hList); + + ::std::sort( aFileVec.begin() , aFileVec.end() , File::lessFile ); + ::std::sort( aDirVec.begin() , aDirVec.end() , Directory::lessDir ); +} + +#else + +class dirholder +{ +private: + DIR *mpDir; +public: + dirholder(DIR *pDir) : mpDir(pDir) {} + int close() { int nRet = mpDir ? closedir(mpDir) : 0; mpDir = NULL; return nRet; } + ~dirholder() { close(); } +}; + +void Directory::readDirectory( const rtl::OUString& sFullpath ) +{ + struct stat statbuf; + struct stat statbuf2; + struct dirent *dirp; + DIR *dir; + + if( sFullpath.getLength() < 1 ) return; + + rtl::OString sFullpathext = rtl::OUStringToOString( sFullpath , RTL_TEXTENCODING_UTF8 ); + const char* path = sFullpathext.getStr(); + + // stat + if( stat( path , &statbuf ) < 0 ){ printf("warning: Can not stat %s" , path ); return; } + + if( S_ISDIR(statbuf.st_mode ) == 0 ) { return; } + + if( (dir = opendir( path ) ) == NULL ) {printf("readerror 2 in %s \n",path); return; } + dirholder aHolder(dir); + + const rtl::OString sDot ( "." ) ; + const rtl::OString sDDot( ".." ); + + if ( chdir( path ) == -1 ) { printf("chdir error in %s \n",path); return; } + + sFullpathext += rtl::OString( "/" ); + + while( ( dirp = readdir( dir ) ) != NULL ) + { + rtl::OString sEntryName( dirp->d_name ); + + if( sEntryName.equals( sDot ) || sEntryName.equals( sDDot ) ) + continue; + + // add dir entry + rtl::OString sEntity = sFullpathext; + sEntity += sEntryName; + + // stat new entry + if( lstat( sEntity.getStr() , &statbuf2 ) < 0 ) + { + printf("error on entry %s\n" , sEntity.getStr() ) ; + continue; + } + + // add file / dir to vector + switch( statbuf2.st_mode & S_IFMT ) + { + case S_IFREG: + { + rtl::OString sFile = sFullpathext; + sFile += sEntryName ; + transex::File aFile( rtl::OStringToOUString( sEntity , RTL_TEXTENCODING_UTF8 , sEntity.getLength() ) , + rtl::OStringToOUString( sEntryName , RTL_TEXTENCODING_UTF8 , sEntryName.getLength() ) + ); + + aFileVec.push_back( aFile ) ; + break; + } + case S_IFLNK: + { + if( bSkipLinks ) break; + } + case S_IFDIR: + { + rtl::OString sDir = sFullpathext; + sDir += sEntryName ; + + transex::Directory aDir( + rtl::OStringToOUString( sEntity , RTL_TEXTENCODING_UTF8 , sEntity.getLength() ) , + rtl::OStringToOUString( sEntryName , RTL_TEXTENCODING_UTF8 , sEntryName.getLength() ) + ) ; + aDirVec.push_back( aDir ) ; + break; + } + } + } + if ( chdir( ".." ) == -1 ) { printf("chdir error in .. \n"); return; } + if( aHolder.close() < 0 ) return ; + + std::sort( aFileVec.begin() , aFileVec.end() , File::lessFile ); + std::sort( aDirVec.begin() , aDirVec.end() , Directory::lessDir ); + +} + +#endif +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/export.cxx b/l10ntools/source/export.cxx new file mode 100644 index 000000000000..865065b31191 --- /dev/null +++ b/l10ntools/source/export.cxx @@ -0,0 +1,2507 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_l10ntools.hxx" +#include <stdio.h> +#include <stdlib.h> +#include <tools/fsys.hxx> +#include "export.hxx" +#include "tokens.h" +#include "utf8conv.hxx" +#include <iostream> +#include <vector> + +extern "C" { int yyerror( char * ); } +extern "C" { int YYWarning( char * ); } + +Export *pExport = 0L; + +// defines to parse command line +#define STATE_NON 0x0001 +#define STATE_INPUT 0x0002 +#define STATE_OUTPUT 0x0003 +#define STATE_PRJ 0x0004 +#define STATE_ROOT 0x0005 +#define STATE_MERGESRC 0x0006 +#define STATE_ERRORLOG 0x0007 +#define STATE_BREAKHELP 0x0008 +#define STATE_UNMERGE 0x0009 +#define STATE_UTF8 0x000A +#define STATE_LANGUAGES 0X000B + +// set of global variables +typedef ::std::vector< ByteString* > FileList; +FileList aInputFileList; +BOOL bEnableExport; +BOOL bMergeMode; +BOOL bErrorLog; +BOOL bBreakWhenHelpText; +BOOL bUnmerge; +BOOL bUTF8; +ByteString sPrj; +ByteString sPrjRoot; +ByteString sActFileName; +ByteString sOutputFile; +ByteString sMergeSrc; +ByteString sTempFile; +ByteString sFile; +MergeDataFile *pMergeDataFile; +FILE *pTempFile; + + +ByteString sStrBuffer; +bool bMarcro = false; + +extern "C" { +// the whole interface to lexer is in this extern "C" section + + +/*****************************************************************************/ +extern char *GetOutputFile( int argc, char* argv[]) +/*****************************************************************************/ +{ + bEnableExport = FALSE; + bMergeMode = FALSE; + bErrorLog = TRUE; + bBreakWhenHelpText = FALSE; + bUnmerge = FALSE; + bUTF8 = TRUE; + sPrj = ""; + sPrjRoot = ""; + sActFileName = ""; + Export::sLanguages = ""; + Export::sForcedLanguages = ""; + sTempFile = ""; + pTempFile = NULL; + USHORT nState = STATE_NON; + BOOL bInput = FALSE; + + // parse command line + for( int i = 1; i < argc; i++ ) { + ByteString sSwitch( argv[ i ] ); + + if (sSwitch == "-i" || sSwitch == "-I" ) { + nState = STATE_INPUT; // next tokens specifies source files + } + else if (sSwitch == "-o" || sSwitch == "-O" ) { + nState = STATE_OUTPUT; // next token specifies the dest file + } + else if (sSwitch == "-p" || sSwitch == "-P" ) { + nState = STATE_PRJ; // next token specifies the cur. project + } + + else if (sSwitch == "-r" || sSwitch == "-R" ) { + nState = STATE_ROOT; // next token specifies path to project root + } + else if (sSwitch == "-m" || sSwitch == "-M" ) { + nState = STATE_MERGESRC; // next token specifies the merge database + } + else if (sSwitch == "-e" || sSwitch == "-E" ) { + nState = STATE_ERRORLOG; + bErrorLog = FALSE; + } + else if (sSwitch == "-b" || sSwitch == "-B" ) { + nState = STATE_BREAKHELP; + bBreakWhenHelpText = TRUE; + } + else if (sSwitch == "-u" || sSwitch == "-U" ) { + nState = STATE_UNMERGE; + bUnmerge = TRUE; + bMergeMode = TRUE; + } + else if ( sSwitch.ToUpperAscii() == "-UTF8" ) { + nState = STATE_UTF8; + bUTF8 = TRUE; + } + else if ( sSwitch.ToUpperAscii() == "-NOUTF8" ) { + nState = STATE_UTF8; + bUTF8 = FALSE; + } + else if ( sSwitch == "-l" || sSwitch == "-L" ) { + nState = STATE_LANGUAGES; + } + else { + switch ( nState ) { + case STATE_NON: { + return NULL; // no valid command line + } + case STATE_INPUT: { + aInputFileList.push_back( new ByteString( argv[ i ] ) ); + bInput = TRUE; // min. one source file found + } + break; + case STATE_OUTPUT: { + sOutputFile = ByteString( argv[ i ]); // the dest. file + } + break; + case STATE_PRJ: { + sPrj = ByteString( argv[ i ]); + } + break; + case STATE_ROOT: { + sPrjRoot = ByteString( argv[ i ]); // path to project root + } + break; + case STATE_MERGESRC: { + sMergeSrc = ByteString( argv[ i ]); + bMergeMode = TRUE; // activate merge mode, cause merge database found + } + break; + case STATE_LANGUAGES: { + Export::sLanguages = ByteString( argv[ i ]); + } + break; + } + } + } + if( bUnmerge ) sMergeSrc = ByteString(); + if ( bInput ) { + // command line is valid + bEnableExport = TRUE; + char *pReturn = new char[ sOutputFile.Len() + 1 ]; + strcpy( pReturn, sOutputFile.GetBuffer()); // #100211# - checked + return pReturn; + } + + // command line is not valid + return NULL; +} +/*****************************************************************************/ +int InitExport( char *pOutput , char* pFilename ) +/*****************************************************************************/ +{ + // instanciate Export + ByteString sOutput( pOutput ); + ByteString sFilename( pFilename ); + + if ( bMergeMode && !bUnmerge ) { + // merge mode enabled, so read database + pExport = new Export(sOutput, bEnableExport, sPrj, sPrjRoot, sMergeSrc , sFilename ); + } + else + // no merge mode, only export + pExport = new Export( sOutput, bEnableExport, sPrj, sPrjRoot , sFilename ); + return 1; +} + +/*****************************************************************************/ +int EndExport() +/*****************************************************************************/ +{ + delete pExport; + return 1; +} + +extern const char* getFilename() +{ + return (*(aInputFileList[ 0 ])).GetBuffer(); +} +/*****************************************************************************/ +extern FILE *GetNextFile() +/*****************************************************************************/ +{ + // look for next valid filename in input file list + if ( sTempFile.Len()) { + fclose( pTempFile ); + String sTemp( sTempFile, RTL_TEXTENCODING_ASCII_US ); + DirEntry aTemp( sTemp ); + aTemp.Kill(); + } + + while ( !aInputFileList.empty() ) { + ByteString sFileName( *(aInputFileList[ 0 ]) ); + + ByteString sOrigFile( sFileName ); + + sFileName = Export::GetNativeFile( sFileName ); + delete aInputFileList[ 0 ]; + aInputFileList.erase( aInputFileList.begin() ); + + if ( sFileName == "" ) { + fprintf( stderr, "ERROR: Could not precompile File %s\n", + sOrigFile.GetBuffer()); + return GetNextFile(); + } + + sTempFile = sFileName; + Export::RemoveUTF8ByteOrderMarkerFromFile( sFileName ); + + // able to open file? + FILE *pFile = fopen( sFileName.GetBuffer(), "r" ); + if ( !pFile ) + fprintf( stderr, "Error: Could not open File %s\n", + sFileName.GetBuffer()); + else { + pTempFile = pFile; + + // this is a valid file which can be opened, so + // create path to project root + DirEntry aEntry( String( sOrigFile, RTL_TEXTENCODING_ASCII_US )); + aEntry.ToAbs(); + ByteString sFullEntry( aEntry.GetFull(), RTL_TEXTENCODING_ASCII_US ); + aEntry += DirEntry( String( "..", RTL_TEXTENCODING_ASCII_US )); + aEntry += DirEntry( sPrjRoot ); + ByteString sPrjEntry( aEntry.GetFull(), RTL_TEXTENCODING_ASCII_US ); + + // create file name, beginnig with project root + // (e.g.: source\ui\src\menue.src) + sActFileName = sFullEntry.Copy( sPrjEntry.Len() + 1 ); + + + sActFileName.SearchAndReplaceAll( "/", "\\" ); + sFile = sActFileName; + + if ( pExport ) { + // create instance of class export + pExport->Init(); + } + // return the valid file handle + return pFile; + } + } + // this means the file could not be opened + return NULL; +} + +int Parse( int nTyp, const char *pTokenText ){ + pExport->Execute( nTyp , pTokenText ); + return 1; +} +void Close(){ + pExport->pParseQueue->Close(); +} +/*****************************************************************************/ +int WorkOnTokenSet( int nTyp, char *pTokenText ) +/*****************************************************************************/ +{ + + pExport->pParseQueue->Push( QueueEntry( nTyp , ByteString( pTokenText ) ) ); + return 1; +} + +} // extern + +extern "C" { +/*****************************************************************************/ +int SetError() +/*****************************************************************************/ +{ + // set error at global instance of class Export + pExport->SetError(); + return 1; +} +} + +extern "C" { +/*****************************************************************************/ +int GetError() +/*****************************************************************************/ +{ + // get error at global instance of class Export + if ( pExport->GetError()) + return 1; + return FALSE; +} +} + +// +// class ResData +// + +void ResData::Dump(){ + printf("**************\nResData\n"); + printf("sPForm = %s , sResTyp = %s , sId = %s , sGId = %s , sHelpId = %s\n",sPForm.GetBuffer() + ,sResTyp.GetBuffer(),sId.GetBuffer(),sGId.GetBuffer(),sHelpId.GetBuffer()); + + ByteString a("*pStringList"); + ByteString b("*pUIEntries"); + ByteString c("*pFilterList"); + ByteString d("*pItemList"); + ByteString e("*pPairedList"); + ByteString f("sText"); + + Export::DumpMap( f , sText ); + + if( pStringList ) Export::DumpExportList( a , *pStringList ); + if( pUIEntries ) Export::DumpExportList( b , *pUIEntries ); + if( pFilterList ) Export::DumpExportList( c , *pFilterList ); + if( pItemList ) Export::DumpExportList( d , *pItemList ); + if( pPairedList ) Export::DumpExportList( e , *pPairedList ); + printf("\n"); +} + +void ResData::addFallbackData( ByteString& sId_in , const ByteString& sText_in ){ + aFallbackData[ sId_in ] = sText_in; +} +bool ResData::getFallbackData( ByteString& sId_in , ByteString& sText_inout ){ + sText_inout = aFallbackData[ sId_in ]; + return sText_inout.Len() > 0; +} + +void ResData::addMergedLanguage( ByteString& sLang ){ + aMergedLanguages[ sLang ]=ByteString("1"); +} +bool ResData::isMerged( ByteString& sLang ){ + return aMergedLanguages[ sLang ].Equals("1"); +} + +/*****************************************************************************/ +BOOL ResData::SetId( const ByteString &rId, USHORT nLevel ) +/*****************************************************************************/ +{ + if ( nLevel > nIdLevel ) + { + nIdLevel = nLevel; + sId = rId; + + if ( bChild && bChildWithText ) { + ByteString sError( "ResId after child definition" ); + yyerror( sError.GetBufferAccess()); + sError.ReleaseBufferAccess(); + SetError(); + } + + if ( sId.Len() > 255 ) { + ByteString sWarning( "LocalId > 255 chars, truncating..." ); + YYWarning( sWarning.GetBufferAccess()); + sWarning.ReleaseBufferAccess(); + sId.Erase( 255 ); + sId.EraseTrailingChars( ' ' ); + sId.EraseTrailingChars( '\t' ); + } + + return TRUE; + } + + return FALSE; +} + +// +// class Export +// + +/*****************************************************************************/ +Export::Export( const ByteString &rOutput, BOOL bWrite, + const ByteString &rPrj, const ByteString &rPrjRoot , const ByteString& rFile ) +/*****************************************************************************/ + : + pWordTransformer( NULL ), + aCharSet( RTL_TEXTENCODING_MS_1252 ), + bDefine( FALSE ), + bNextMustBeDefineEOL( FALSE ), + nLevel( 0 ), + nList( LIST_NON ), + nListIndex( 0 ), + nListLevel( 0 ), + bSkipFile( false ), + sProject( sPrj ), + sRoot( sPrjRoot ), + bEnableExport( bWrite ), + bMergeMode( bUnmerge ), + bError( FALSE ), + bReadOver( FALSE ), + bDontWriteOutput( FALSE ), + sFilename( rFile ) +{ + pParseQueue = new ParserQueue( *this ); + (void) rPrj; + (void) rPrjRoot; + (void) rFile; + + if( !isInitialized ) InitLanguages(); + // used when export is enabled + + // open output stream + if ( bEnableExport ) { + aOutput.Open( String( rOutput, RTL_TEXTENCODING_ASCII_US ), STREAM_STD_WRITE | STREAM_TRUNC ); + if( !aOutput.IsOpen() ) { + printf("ERROR : Can't open file %s\n",rOutput.GetBuffer()); + exit ( -1 ); + } + aOutput.SetStreamCharSet( RTL_TEXTENCODING_UTF8 ); + + aOutput.SetLineDelimiter( LINEEND_CRLF ); + } +} + +/*****************************************************************************/ +Export::Export( const ByteString &rOutput, BOOL bWrite, + const ByteString &rPrj, const ByteString &rPrjRoot, + const ByteString &rMergeSource , const ByteString& rFile ) +/*****************************************************************************/ + : + pWordTransformer( NULL ), + aCharSet( RTL_TEXTENCODING_MS_1252 ), + bDefine( FALSE ), + bNextMustBeDefineEOL( FALSE ), + nLevel( 0 ), + nList( LIST_NON ), + nListIndex( 0 ), + nListLevel( 0 ), + bSkipFile( false ), + sProject( sPrj ), + sRoot( sPrjRoot ), + bEnableExport( bWrite ), + bMergeMode( TRUE ), + sMergeSrc( rMergeSource ), + bError( FALSE ), + bReadOver( FALSE ), + bDontWriteOutput( FALSE ), + sFilename( rFile ) +{ + (void) rPrj; + (void) rPrjRoot; + (void) rFile; + pParseQueue = new ParserQueue( *this ); + if( !isInitialized ) InitLanguages( bMergeMode ); + // used when merge is enabled + + // open output stream + if ( bEnableExport ) { + aOutput.Open( String( rOutput, RTL_TEXTENCODING_ASCII_US ), STREAM_STD_WRITE | STREAM_TRUNC ); + aOutput.SetStreamCharSet( RTL_TEXTENCODING_UTF8 ); + aOutput.SetLineDelimiter( LINEEND_CRLF ); + } + +} + +/*****************************************************************************/ +void Export::Init() +/*****************************************************************************/ +{ + // resets the internal status, used before parseing another file + sActPForm = ""; + bDefine = FALSE; + bNextMustBeDefineEOL = FALSE; + nLevel = 0; + nList = LIST_NON; + nListLang = ByteString( String::CreateFromAscii(""),RTL_TEXTENCODING_ASCII_US ); + nListIndex = 0; + for ( size_t i = 0, n = aResStack.size(); i < n; ++i ) + delete aResStack[ i ]; + aResStack.clear(); +} + +/*****************************************************************************/ +Export::~Export() +/*****************************************************************************/ +{ + if( pParseQueue ) + delete pParseQueue; + // close output stream + if ( bEnableExport ) + aOutput.Close(); + for ( size_t i = 0, n = aResStack.size(); i < n; ++i ) + delete aResStack[ i ]; + aResStack.clear(); + + if ( bMergeMode && !bUnmerge ) { + if ( !pMergeDataFile ) + pMergeDataFile = new MergeDataFile( sMergeSrc,sFile , bErrorLog, aCharSet);//, bUTF8 ); + + delete pMergeDataFile; + } +} + +/*****************************************************************************/ +int Export::Execute( int nToken, const char * pToken ) +/*****************************************************************************/ +{ + + ByteString sToken( pToken ); + ByteString sOrig( sToken ); + BOOL bWriteToMerged = bMergeMode; + + if ( nToken == CONDITION ) { + ByteString sTestToken( pToken ); + sTestToken.EraseAllChars( '\t' ); + sTestToken.EraseAllChars( ' ' ); + if (( !bReadOver ) && ( sTestToken.Search( "#ifndef__RSC_PARSER" ) == 0 )) + bReadOver = TRUE; + else if (( bReadOver ) && ( sTestToken.Search( "#endif" ) == 0 )) + 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 ); // ... ore whrite them directly to dest. + return 0; + } + + ResData *pResData = NULL; + if ( nLevel ) { + // res. exists at cur. level + pResData = ( (nLevel-1) < aResStack.size() ) ? aResStack[ nLevel-1 ] : NULL; + } + else if (( nToken != RESSOURCE ) && + ( nToken != RESSOURCEEXPR ) && + ( nToken != SMALRESSOURCE ) && + ( nToken != LEVELUP ) && + ( nToken != NORMDEFINE ) && + ( nToken != RSCDEFINE ) && + ( nToken != CONDITION ) && + ( nToken != PRAGMA )) + { + // no res. exists at cur. level so return + if ( bMergeMode ) + WriteToMerged( sOrig , false ); + return 0; + } + // #define NO_LOCALIZE_EXPORT + if( bSkipFile ){ + if ( bMergeMode ) { + WriteToMerged( sOrig , false ); + } + return 1; + } + + + 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; + if ( bMergeMode ) { + MergeRest( pResData ); + } + bNextMustBeDefineEOL = FALSE; + Execute( LEVELDOWN, "" ); + } + else { + // next line also in macro definition + bNextMustBeDefineEOL = FALSE; + if ( bMergeMode ) + WriteToMerged( sOrig , false ); + return 1; + } + } + else if (( nToken != LISTASSIGNMENT ) && ( nToken != UIENTRIES )){ + // cur. line has macro line end + ByteString sTmpLine( sToken ); + sTmpLine.EraseAllChars( '\t' ); sTmpLine.EraseAllChars( ' ' ); + } + } + } + + BOOL bExecuteDown = FALSE; + if ( nToken != LEVELDOWN ) { + USHORT nOpen = 0; + USHORT nClose = 0; + BOOL bReadOver1 = FALSE; + USHORT i = 0; + for ( i = 0; i < sToken.Len(); i++ ) { + if ( sToken.GetChar( i ) == '\"' ) + bReadOver1 = !bReadOver1; + if ( !bReadOver1 && ( sToken.GetChar( i ) == '{' )) + nOpen++; + } + + bReadOver1 = FALSE; + for ( i = 0; i < sToken.Len(); i++ ) { + if ( sToken.GetChar( i ) == '\"' ) + bReadOver1 = !bReadOver1; + if ( !bReadOver1 && ( sToken.GetChar( i ) == '}' )) + nClose++; + } + + if ( nOpen < nClose ) + bExecuteDown = TRUE; + } + switch ( nToken ) { + + case NORMDEFINE: + while( sToken.SearchAndReplace( "\r", " " ) != STRING_NOTFOUND ) {}; + while( sToken.SearchAndReplace( "\t", " " ) != STRING_NOTFOUND ) {}; + while( sToken.SearchAndReplace( " ", " " ) != STRING_NOTFOUND ) {}; + if( sToken.EqualsIgnoreCaseAscii( "#define NO_LOCALIZE_EXPORT" ) ){ + bSkipFile = true; + return 0; + } + if ( bMergeMode ) + WriteToMerged( sOrig , false ); + + return 0; + + + case RSCDEFINE: + bDefine = TRUE; // res. defined in macro + + case RESSOURCE: + case RESSOURCEEXPR: { + bDontWriteOutput = FALSE; + 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( sActPForm, FullId() , sFilename ); + aResStack.push_back( pResData ); + ByteString sBackup( sToken ); + sToken.EraseAllChars( '\n' ); + sToken.EraseAllChars( '\r' ); + sToken.EraseAllChars( '{' ); + while( sToken.SearchAndReplace( "\t", " " ) != STRING_NOTFOUND ) {}; + sToken.EraseTrailingChars( ' ' ); + ByteString sT = sToken.GetToken( 0, ' ' ); + pResData->sResTyp = sT.ToLowerAscii(); + ByteString sId( sToken.Copy( pResData->sResTyp.Len() + 1 )); + ByteString sCondition; + if ( sId.Search( "#" ) != STRING_NOTFOUND ) { + // between ResTyp, Id and paranthes is a precomp. condition + sCondition = "#"; + sCondition += sId.GetToken( 1, '#' ); + sId = sId.GetToken( 0, '#' ); + } + sId = sId.GetToken( 0, '/' ); + CleanValue( sId ); + sId = sId.EraseAllChars( '\t' ); + pResData->SetId( sId, ID_LEVEL_IDENTIFIER ); + if ( sCondition.Len()) { + ByteString sEmpty( "" ); + Execute( CONDITION, sEmpty.GetBufferAccess()); // execute the + // precomp. + // condition + sEmpty.ReleaseBufferAccess(); + } + } + break; + case SMALRESSOURCE: { + bDontWriteOutput = FALSE; + // 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( sActPForm, FullId() , sFilename ); + aResStack.push_back( pResData ); + sToken.EraseAllChars( '\n' ); + sToken.EraseAllChars( '\r' ); + sToken.EraseAllChars( '{' ); + sToken.EraseAllChars( '\t' ); + sToken.EraseAllChars( ' ' ); + sToken.EraseAllChars( '\\' ); + pResData->sResTyp = sToken.ToLowerAscii(); + } + break; + case LEVELUP: { + // push + if ( nList ) + nListLevel++; + if ( nList ) + break; + + bDontWriteOutput = FALSE; + ByteString sLowerTyp; + if ( pResData ) + sLowerTyp = "unknown"; + nLevel++; + if ( nLevel > 1 ) { + aResStack[ nLevel - 2 ]->bChild = TRUE; + } + + ResData *pNewData = new ResData( sActPForm, FullId() , sFilename ); + pNewData->sResTyp = sLowerTyp; + aResStack.push_back( pNewData ); + } + break; + case LEVELDOWN: { + // pop + if ( !nList ) { + bDontWriteOutput = FALSE; + 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--; + } + } + else { + if ( bDefine ) + bNextMustBeDefineEOL = TRUE; + if ( !nListLevel ) { + if ( bMergeMode ) + MergeRest( pResData, MERGE_MODE_LIST ); + nList = LIST_NON; + } + else + nListLevel--; + } + } + break; + case ASSIGNMENT: { + bDontWriteOutput = FALSE; + // interpret different types of assignement + ByteString sKey = sToken.GetToken( 0, '=' ); + sKey.EraseAllChars( ' ' ); + sKey.EraseAllChars( '\t' ); + ByteString sValue = sToken.GetToken( 1, '=' ); + CleanValue( sValue ); + if ( sKey.ToUpperAscii() == "IDENTIFIER" ) { + ByteString sId( sValue.EraseAllChars( '\t' )); + pResData->SetId( sId.EraseAllChars( ' ' ), ID_LEVEL_IDENTIFIER ); + } + else if ( sKey == "HELPID" ) { + pResData->sHelpId = sValue; + } + else if ( sKey == "STRINGLIST" ) { + pResData->bList = TRUE; + nList = LIST_STRING; + nListLang = SOURCE_LANGUAGE; + nListIndex = 0; + nListLevel = 0; + } + else if ( sKey == "FILTERLIST" ) { + pResData->bList = TRUE; + nList = LIST_FILTER; + nListLang = SOURCE_LANGUAGE; + nListIndex = 0; + nListLevel = 0; + } + else if ( sKey == "UIENTRIES" ) { + pResData->bList = TRUE; + nList = LIST_UIENTRIES; + nListLang = SOURCE_LANGUAGE; + nListIndex = 0; + nListLevel = 0; + } + if (( sToken.Search( "{" ) != STRING_NOTFOUND ) && + ( sToken.GetTokenCount( '{' ) > sToken.GetTokenCount( '}' ))) + { + Parse( LEVELUP, "" ); + } + } + break; + case UIENTRIES: + case LISTASSIGNMENT: { + bDontWriteOutput = FALSE; + ByteString sTmpToken( sToken); + sTmpToken.EraseAllChars(' '); + USHORT nPos = 0; + nPos = sTmpToken.ToLowerAscii().Search("[en-us]="); + if( nPos != STRING_NOTFOUND ) { + ByteString sKey = sTmpToken.Copy( 0 , nPos ); + sKey.EraseAllChars( ' ' ); + sKey.EraseAllChars( '\t' ); + ByteString sValue = sToken.GetToken( 1, '=' ); + CleanValue( sValue ); + if ( sKey.ToUpperAscii() == "STRINGLIST" ) { + pResData->bList = TRUE; + nList = LIST_STRING; + nListLang = SOURCE_LANGUAGE; + nListIndex = 0; + nListLevel = 0; + } + else if ( sKey == "FILTERLIST" ) { + pResData->bList = TRUE; + nList = LIST_FILTER; + nListLang = SOURCE_LANGUAGE; + nListIndex = 0; + nListLevel = 0; + } + // PairedList + else if ( sKey == "PAIREDLIST" ) { + pResData->bList = TRUE; + nList = LIST_PAIRED; + nListLang = SOURCE_LANGUAGE; + nListIndex = 0; + nListLevel = 0; + } + + else if ( sKey == "ITEMLIST" ) { + pResData->bList = TRUE; + nList = LIST_ITEM; + nListLang = SOURCE_LANGUAGE; + nListIndex = 0; + nListLevel = 0; + } + else if ( sKey == "UIENTRIES" ) { + pResData->bList = TRUE; + nList = LIST_UIENTRIES; + nListLang = SOURCE_LANGUAGE; + nListIndex = 0; + nListLevel = 0; + } + } + else { + // new res. is a String- or FilterList + ByteString sKey = sToken.GetToken( 0, '[' ); + sKey.EraseAllChars( ' ' ); + sKey.EraseAllChars( '\t' ); + if ( sKey.ToUpperAscii() == "STRINGLIST" ) + nList = LIST_STRING; + else if ( sKey == "FILTERLIST" ) + nList = LIST_FILTER; + else if ( sKey == "PAIREDLIST" ) + nList = LIST_PAIRED; // abcd + else if ( sKey == "ITEMLIST" ) + nList = LIST_ITEM; + else if ( sKey == "UIENTRIES" ) + nList = LIST_UIENTRIES; + if ( nList ) { + ByteString sLang=sToken.GetToken( 1, '[' ).GetToken( 0, ']' ); + CleanValue( sLang ); + nListLang = sLang; + nListIndex = 0; + nListLevel = 0; + } + } + } + break; + case TEXT: + case _LISTTEXT: + case LISTTEXT: { + // this is an entry for a String- or FilterList + if ( nList ) { + SetChildWithText(); + ByteString sEntry( sToken.GetToken( 1, '\"' )); + if ( sToken.GetTokenCount( '\"' ) > 3 ) + sEntry += "\""; + if ( sEntry == "\\\"" ) + sEntry = "\""; + InsertListEntry( sEntry, sOrig ); + if ( bMergeMode && ( sEntry != "\"" )) { + PrepareTextToMerge( sOrig, nList, nListLang, pResData ); + } + } + } + break; + case LONGTEXTLINE: + case TEXTLINE: + bDontWriteOutput = FALSE; + if ( nLevel ) { + CutComment( sToken ); + + // this is a text line!!! + ByteString sKey = sToken.GetToken( 0, '=' ).GetToken( 0, '[' ); + sKey.EraseAllChars( ' ' ); + sKey.EraseAllChars( '\t' ); + ByteString sText( GetText( sToken, nToken )); + if ( !bMergeMode ) + sText = sText.Convert( aCharSet, RTL_TEXTENCODING_MS_1252 ); + ByteString sLang; + if ( sToken.GetToken( 0, '=' ).Search( "[" ) != STRING_NOTFOUND ) { + sLang = sToken.GetToken( 0, '=' ).GetToken( 1, '[' ).GetToken( 0, ']' ); + CleanValue( sLang ); + } + ByteString nLangIndex = sLang; + ByteString sOrigKey = sKey; + if ( sText.Len() && sLang.Len() ) { + if (( sKey.ToUpperAscii() == "TEXT" ) || + ( sKey == "MESSAGE" ) || + ( sKey == "CUSTOMUNITTEXT" ) || + ( sKey == "SLOTNAME" ) || + ( sKey == "UINAME" )) + { + SetChildWithText(); + if ( Export::isSourceLanguage( nLangIndex ) ) + pResData->SetId( sText, ID_LEVEL_TEXT ); + + pResData->bText = TRUE; + pResData->sTextTyp = sOrigKey; + if ( bMergeMode ) { + PrepareTextToMerge( sOrig, STRING_TYP_TEXT, nLangIndex, pResData ); + } + else { + if ( pResData->sText[ nLangIndex ].Len()) { + ByteString sError( "Language " ); + sError += nLangIndex; + sError += " defined twice"; + } + pResData->sText[ nLangIndex ] = sText; + } + } + else if ( sKey == "HELPTEXT" ) { + SetChildWithText(); + pResData->bHelpText = TRUE; + if ( bBreakWhenHelpText ) { + ByteString sError( "\"HelpText\" found in source\n" ); + YYWarning( sError.GetBufferAccess()); + sError.ReleaseBufferAccess(); + SetError(); + } + if ( bMergeMode ) + PrepareTextToMerge( sOrig, STRING_TYP_HELPTEXT, nLangIndex, pResData ); + else { + if ( pResData->sHelpText[ nLangIndex ].Len()) { + ByteString sError( "Language " ); + sError += nLangIndex; + sError += " defined twice"; + } + pResData->sHelpText[ nLangIndex ] = sText; + } + } + else if ( sKey == "QUICKHELPTEXT" ) { + SetChildWithText(); + pResData->bQuickHelpText = TRUE; + if ( bMergeMode ) + PrepareTextToMerge( sOrig, STRING_TYP_QUICKHELPTEXT, nLangIndex, pResData ); + else { + if ( pResData->sQuickHelpText[ nLangIndex ].Len()) { + ByteString sError( "Language " ); + sError += nLangIndex; + sError += " defined twice"; + } + pResData->sQuickHelpText[ nLangIndex ] = sText; + } + } + else if ( sKey == "TITLE" ) { + SetChildWithText(); + pResData->bTitle = TRUE; + if ( bMergeMode ) + PrepareTextToMerge( sOrig, STRING_TYP_TITLE, nLangIndex, pResData ); + else { + if ( pResData->sTitle[ nLangIndex ].Len()) { + ByteString sError( "Language " ); + sError += nLangIndex; + sError += " defined twice"; + } + pResData->sTitle[ nLangIndex ] = sText; + } + } + else if ( sKey == "ACCESSPATH" ) { + pResData->SetId( sText, ID_LEVEL_ACCESSPATH ); + } + else if ( sKey == "FIELDNAME" ) { + pResData->SetId( sText, ID_LEVEL_FIELDNAME ); + } + } + } + break; + case NEWTEXTINRES: { + bDontWriteOutput = TRUE; + } + break; + case APPFONTMAPPING: { + bDontWriteOutput = FALSE; + // this is a AppfontMapping, so look if its a definition + // of field size + ByteString sKey = sToken.GetToken( 0, '=' ); + sKey.EraseAllChars( ' ' ); + sKey.EraseAllChars( '\t' ); + ByteString sMapping = sToken.GetToken( 1, '=' ); + sMapping = sMapping.GetToken( 1, '(' ); + sMapping = sMapping.GetToken( 0, ')' ); + sMapping.EraseAllChars( ' ' ); + sMapping.EraseAllChars( '\t' ); + if ( sKey.ToUpperAscii() == "SIZE" ) { + pResData->nWidth = ( USHORT ) sMapping.GetToken( 0, ',' ).ToInt64(); + } + else if ( sKey == "POSSIZE" ) { + pResData->nWidth = ( USHORT ) sMapping.GetToken( 2, ',' ).ToInt64(); + } + } + break; + case RSCDEFINELEND: + bDontWriteOutput = FALSE; + break; + case CONDITION: { + bDontWriteOutput = FALSE; + while( sToken.SearchAndReplace( "\r", " " ) != STRING_NOTFOUND ) {}; + while( sToken.SearchAndReplace( "\t", " " ) != STRING_NOTFOUND ) {}; + while( sToken.SearchAndReplace( " ", " " ) != STRING_NOTFOUND ) {}; + ByteString sCondition = sToken.GetToken( 0, ' ' ); + if ( sCondition == "#ifndef" ) { + sActPForm = "!defined "; + sActPForm += sToken.GetToken( 1, ' ' ); + } + else if ( sCondition == "#ifdef" ) { + sActPForm = "defined "; + sActPForm += sToken.GetToken( 1, ' ' ); + } + else if ( sCondition == "#if" ) { + sActPForm = sToken.Copy( 4 ); + while ( sActPForm.SearchAndReplace( "||", "\\or" ) != STRING_NOTFOUND ) {}; + } + else if ( sCondition == "#elif" ) { + sActPForm = sToken.Copy( 6 ); + while ( sActPForm.SearchAndReplace( "||", "\\or" ) != STRING_NOTFOUND ) {}; + } + else if ( sCondition == "#else" ) { + sActPForm = sCondition; + } + else if ( sCondition == "#endif" ) { + sActPForm = ""; + } + else break; + if ( nLevel ) { + WriteData( pResData, TRUE ); + pResData->sPForm = sActPForm; + } + } + break; + case EMPTYLINE : { + bDontWriteOutput = FALSE; + if ( bDefine ) { + bNextMustBeDefineEOL = FALSE; + bDefine = FALSE; + while ( nLevel ) + Parse( LEVELDOWN, "" ); + } + } + break; + case PRAGMA : { + bDontWriteOutput = FALSE; + while( sToken.SearchAndReplace( "\t", " " ) != STRING_NOTFOUND ) {}; + while( sToken.SearchAndReplace( " ", " " ) != STRING_NOTFOUND ) {}; + sToken.EraseLeadingChars( ' ' ); + sToken.EraseTrailingChars( ' ' ); + + ByteString sCharset = sToken.GetToken( 1, ' ' ); + ByteString sSet = sToken.GetToken( 2, ' ' ); + if (( sCharset.ToUpperAscii() == "CHARSET_IBMPC" ) || + ( sCharset == "RTL_TEXTENCODING_IBM_850" ) || + (( sCharset == "CHARSET" ) && ( sSet.ToUpperAscii() == "IBMPC" ))) + { + aCharSet = RTL_TEXTENCODING_IBM_850; + } + else if (( sCharset == "CHARSET_ANSI" ) || + ( sCharset == "RTL_TEXTENCODING_MS_1252" ) || + (( sCharset == "CHARSET" ) && ( sSet.ToUpperAscii() == "ANSI" ))) + { + aCharSet = RTL_TEXTENCODING_MS_1252; + } + } + break; + case TEXTREFID : { + bDontWriteOutput = TRUE; + } + } + if ( bWriteToMerged ) { + // the current token must be written to dest. without merging + + if( bDefine && sOrig.Len() > 2 ){ + for( USHORT n = 0 ; n < sOrig.Len() ; n++ ){ + if( sOrig.GetChar( n ) == '\n' && sOrig.GetChar( n-1 ) != '\\'){ + sOrig.Insert('\\' , n++ ); + } + } + } + WriteToMerged( sOrig , false); + } + + if ( bExecuteDown ) { + Parse( LEVELDOWN, "" ); + } + + return 1; +} + +/*****************************************************************************/ +void Export::CutComment( ByteString &rText ) +/*****************************************************************************/ +{ + if ( rText.Search( "//" ) != STRING_NOTFOUND ) { + ByteString sWork( rText ); + sWork.SearchAndReplaceAll( "\\\"", "XX" ); + USHORT i = 0; + BOOL bInner = FALSE; + + while ( i < sWork.Len() - 1 ) { + if ( sWork.GetChar( i ) == '\"' ) + bInner = !bInner; + else if + (( sWork.GetChar( i ) == '/' ) && + ( !bInner ) && + ( sWork.GetChar( i + 1 ) == '/' )) + { + rText.Erase( i ); + return; + } + i++; + } + } +} + +void Export::UnmergeUTF8( ByteString& sOrig ){ + USHORT nPos1 = sOrig.Search('\"'); + USHORT nPos2 = sOrig.SearchBackward('\"'); + if( nPos1 > 0 && nPos2 > 0 && nPos1 < nPos2){ + ByteString sPart = sOrig.Copy(nPos1+1 , nPos2-1); + ByteString sPartUTF8 = sPart; + sPartUTF8.Convert( RTL_TEXTENCODING_MS_1252 , RTL_TEXTENCODING_UTF8 ); + sOrig.SearchAndReplace( sPart , sPartUTF8 ); + } +} + +/*****************************************************************************/ +BOOL Export::ListExists( ResData *pResData, USHORT nLst ) +/*****************************************************************************/ +{ + switch ( nLst ) { + case LIST_STRING: return pResData->pStringList != NULL; + case LIST_FILTER: return pResData->pFilterList != NULL; + case LIST_ITEM: return pResData->pItemList != NULL; + case LIST_PAIRED: return pResData->pPairedList != NULL; + case LIST_UIENTRIES: return pResData->pUIEntries != NULL; + } + return FALSE; +} + +/*****************************************************************************/ +BOOL Export::WriteData( ResData *pResData, BOOL bCreateNew ) +/*****************************************************************************/ +{ + if ( bMergeMode ) { + MergeRest( pResData ); + return TRUE; + } + + if ( bUnmerge ) + return TRUE; + +/* ByteStringHashMap::iterator pos3 = pResData->sText.begin(); + ByteStringHashMap::iterator end3 = pResData->sText.end(); + for(;pos3!=end3;++pos3){ + + printf("[%s]=%s\n", pos3->first.GetBuffer(), pos3->second.GetBuffer() ); + }*/ + // mandatory to export: en-US + + if (( //pResData->sText[ ByteString("de") ].Len() && + ( pResData->sText[ SOURCE_LANGUAGE ].Len())) + || + ( //pResData->sHelpText[ ByteString("de") ].Len() && + ( pResData->sHelpText[ SOURCE_LANGUAGE ].Len())) + || + ( //pResData->sQuickHelpText[ ByteString("de") ].Len() && + ( pResData->sQuickHelpText[ SOURCE_LANGUAGE ].Len())) + || + ( //pResData->sTitle[ ByteString("de") ].Len() && + ( pResData->sTitle[ SOURCE_LANGUAGE ].Len()))) + + { + FillInFallbacks( pResData ); + + ByteString sGID = pResData->sGId; + ByteString sLID; + if ( !sGID.Len()) + sGID = pResData->sId; + else + sLID = pResData->sId; + + ByteString sXText; + ByteString sXHText; + ByteString sXQHText; + ByteString sXTitle; + + ByteString sTimeStamp( Export::GetTimeStamp()); + ByteString sCur; + + for( unsigned int n = 0; n < aLanguages.size(); n++ ){ + sCur = aLanguages[ n ]; + if ( !sCur.EqualsIgnoreCaseAscii("x-comment") ){ + if ( pResData->sText[ sCur ].Len()) + sXText = pResData->sText[ sCur ]; + else { + sXText = pResData->sText[ SOURCE_LANGUAGE ]; + /*if ( !sXText.Len()) + sXText = pResData->sText[ ByteString("en") ]; + if ( !sXText.Len()) + sXText = pResData->sText[ ByteString("de") ];*/ + } + + if ( pResData->sHelpText[ sCur ].Len()) + sXHText = pResData->sHelpText[ sCur ]; + else { + sXHText = pResData->sHelpText[ SOURCE_LANGUAGE ]; + /*if ( !sXHText.Len()) + sXHText = pResData->sHelpText[ ByteString("en") ]; + if ( !sXText.Len()) + sXHText = pResData->sHelpText[ ByteString("de") ];*/ + } + + if ( pResData->sQuickHelpText[ sCur ].Len()) + sXQHText = pResData->sQuickHelpText[ sCur ]; + else { + sXQHText = pResData->sQuickHelpText[ SOURCE_LANGUAGE ]; + /*if ( !sXQHText.Len()) + sXQHText = pResData->sQuickHelpText[ ByteString("en") ]; + if ( !sXQHText.Len()) + sXQHText = pResData->sQuickHelpText[ ByteString("de") ];*/ + } + + if ( pResData->sTitle[ sCur ].Len()) + sXTitle = pResData->sTitle[ sCur ]; + else { + sXTitle = pResData->sTitle[ SOURCE_LANGUAGE ]; + /*if ( !sXTitle.Len()) + sXTitle = pResData->sTitle[ ByteString("en") ]; + if ( !sXTitle.Len()) + sXTitle = pResData->sTitle[ ByteString("de") ];*/ + } + + if ( !sXText.Len()) + sXText = "-"; + + if ( !sXHText.Len()) { + /*if ( pResData->sHelpText[ ByteString("de") ].Len()) + sXHText = pResData->sHelpText[ ByteString("de") ];*/ + if ( pResData->sHelpText[ SOURCE_LANGUAGE ].Len()) + sXHText = pResData->sHelpText[ SOURCE_LANGUAGE ]; + /*else if ( pResData->sHelpText[ ByteString("en") ].Len()) + sXHText = pResData->sHelpText[ ByteString("en") ];*/ + } + } + else + sXText = pResData->sText[ sCur ]; + + if ( bEnableExport ) { + ByteString sOutput( sProject ); sOutput += "\t"; + if ( sRoot.Len()) + sOutput += sActFileName; + sOutput += "\t0\t"; + sOutput += pResData->sResTyp; sOutput += "\t"; + sOutput += sGID; sOutput += "\t"; + sOutput += sLID; sOutput += "\t"; + sOutput += pResData->sHelpId; sOutput += "\t"; + sOutput += pResData->sPForm; sOutput += "\t"; + sOutput += ByteString::CreateFromInt64( pResData->nWidth ); sOutput += "\t"; + sOutput += sCur; sOutput += "\t"; + + + sOutput += sXText; sOutput += "\t"; + sOutput += sXHText; sOutput += "\t"; + sOutput += sXQHText; sOutput+= "\t"; + sOutput += sXTitle; sOutput += "\t"; + sOutput += sTimeStamp; + + // if( !sCur.EqualsIgnoreCaseAscii("de") ||( sCur.EqualsIgnoreCaseAscii("de") && !Export::isMergingGermanAllowed( sProject ) ) ) + aOutput.WriteLine( sOutput ); + } + + if ( bCreateNew ) { + pResData->sText[ sCur ] = ""; + pResData->sHelpText[ sCur ] = ""; + pResData->sQuickHelpText[ sCur ]= ""; + pResData->sTitle[ sCur ] = ""; + } + } + } + FillInFallbacks( pResData ); + if ( pResData->pStringList ) { + ByteString sList( "stringlist" ); + WriteExportList( pResData, pResData->pStringList, sList, bCreateNew ); + if ( bCreateNew ) + pResData->pStringList = 0; + } + if ( pResData->pFilterList ) { + ByteString sList( "filterlist" ); + WriteExportList( pResData, pResData->pFilterList, sList, bCreateNew ); + if ( bCreateNew ) + pResData->pFilterList = 0; + } + if ( pResData->pItemList ) { + ByteString sList( "itemlist" ); + WriteExportList( pResData, pResData->pItemList, sList, bCreateNew ); + if ( bCreateNew ) + pResData->pItemList = 0; + } + if ( pResData->pPairedList ) { + ByteString sList( "pairedlist" ); + WriteExportList( pResData, pResData->pPairedList, sList, bCreateNew ); + if ( bCreateNew ) + pResData->pItemList = 0; + } + if ( pResData->pUIEntries ) { + ByteString sList( "uientries" ); + WriteExportList( pResData, pResData->pUIEntries, sList, bCreateNew ); + if ( bCreateNew ) + pResData->pUIEntries = 0; + } + return TRUE; +} +ByteString Export::GetPairedListID( const ByteString& sText ){ +// < "STRING" ; IDENTIFIER ; > ; + ByteString sIdent = sText.GetToken( 1, ';' ); + sIdent.ToUpperAscii(); + while( sIdent.SearchAndReplace( "\t", " " ) != STRING_NOTFOUND ) {}; + sIdent.EraseTrailingChars( ' ' ); + sIdent.EraseLeadingChars( ' ' ); + return sIdent; +} +ByteString Export::GetPairedListString( const ByteString& sText ){ +// < "STRING" ; IDENTIFIER ; > ; + ByteString sString = sText.GetToken( 0, ';' ); + while( sString.SearchAndReplace( "\t", " " ) != STRING_NOTFOUND ) {}; + sString.EraseTrailingChars( ' ' ); + ByteString s1 = sString.Copy( sString.Search( '\"' )+1 ); + sString = s1.Copy( 0 , s1.SearchBackward( '\"' ) ); + sString.EraseTrailingChars( ' ' ); + sString.EraseLeadingChars( ' ' ); + return sString; +} +ByteString Export::StripList( const ByteString& sText ){ + ByteString s1 = sText.Copy( sText.Search( '\"' ) + 1 ); + return s1.Copy( 0 , s1.SearchBackward( '\"' ) ); +} + +/*****************************************************************************/ +BOOL Export::WriteExportList( ResData *pResData, ExportList *pExportList, + const ByteString &rTyp, BOOL bCreateNew ) +/*****************************************************************************/ +{ + ByteString sGID = pResData->sGId; + if ( !sGID.Len()) + sGID = pResData->sId; + else { + sGID += "."; + sGID += pResData->sId; + sGID.EraseTrailingChars( '.' ); + } + + ByteString sTimeStamp( Export::GetTimeStamp()); + ByteString sCur; + for ( size_t i = 0; pExportList != NULL && i < pExportList->size(); i++ ) { + ExportListEntry *pEntry = (*pExportList)[ i ]; + // mandatory for export: german and eng. and/or enus + // ByteString a("Export::WriteExportList::pEntry"); + // Export::DumpMap( a, *pEntry ); + + ByteString sLID( ByteString::CreateFromInt64( i + 1 )); + for( unsigned int n = 0; n < aLanguages.size(); n++ ){ + sCur = aLanguages[ n ]; + if ( //1 ) + //(*pEntry)[ ByteString("de") ].Len() && + (*pEntry)[ SOURCE_LANGUAGE ].Len() ) + //|| + // (*pEntry)[ ByteString("en") ].Len())) + { + if ( bEnableExport ) + { + ByteString sText((*pEntry)[ SOURCE_LANGUAGE ] ); + + // Strip PairList Line String + if( rTyp.EqualsIgnoreCaseAscii("pairedlist") ){ + sLID = GetPairedListID( sText ); + if ((*pEntry)[ sCur ].Len()) + sText = (*pEntry)[ sCur ]; + sText = GetPairedListString( sText ); + } + else{ + //if ((*pEntry)[ sCur ].Len()){ + // if( sCur.EqualsIgnoreCaseAscii("de") ){ + // sText = StripList( (*pEntry)[ sCur ] ); + // } + // else + sText = StripList( (*pEntry)[ sCur ] ); + if( sText == "\\\"" ) + sText = "\""; + //} + } + + ByteString sOutput( sProject ); sOutput += "\t"; + if ( sRoot.Len()) + sOutput += sActFileName; + sOutput += "\t0\t"; + sOutput += rTyp; sOutput += "\t"; + sOutput += sGID; sOutput += "\t"; + sOutput += sLID; sOutput += "\t\t"; + sOutput += pResData->sPForm; sOutput += "\t0\t"; + sOutput += sCur; sOutput += "\t"; + + sOutput += sText; sOutput += "\t\t\t\t"; + sOutput += sTimeStamp; + + //if( !sCur.EqualsIgnoreCaseAscii("de") ||( sCur.EqualsIgnoreCaseAscii("de") && !Export::isMergingGermanAllowed( sProject ) ) ) + aOutput.WriteLine( sOutput ); + + } + } + } + if ( bCreateNew ) + delete [] pEntry; + } + if ( bCreateNew ) + delete pExportList; + + return TRUE; +} + +/*****************************************************************************/ +ByteString Export::FullId() +/*****************************************************************************/ +{ + ByteString sFull; + if ( nLevel > 1 ) { + sFull = aResStack[ 0 ]->sId; + for ( size_t i = 1; i < nLevel - 1; i++ ) { + ByteString sToAdd = aResStack[ i ]->sId; + if ( sToAdd.Len()) { + sFull += "."; + sFull += sToAdd; + } + } + } + if ( sFull.Len() > 255 ) { + ByteString sError( "GroupId > 255 chars" ); + printf("GroupID = %s\n",sFull.GetBuffer()); + yyerror( sError.GetBufferAccess()); + sError.ReleaseBufferAccess(); + } + + return sFull; +} + +/*****************************************************************************/ +void Export::InsertListEntry( const ByteString &rText, const ByteString &rLine ) +/*****************************************************************************/ +{ + ResData *pResData = ( nLevel-1 < aResStack.size() ) ? aResStack[ nLevel-1 ] : NULL; + + ExportList *pList = NULL; + if ( nList == LIST_STRING ) { + pList = pResData->pStringList; + if ( !pList ) { + pResData->pStringList = new ExportList(); + pList = pResData->pStringList; + nListIndex = 0; + } + } + else if ( nList == LIST_FILTER ) { + pList = pResData->pFilterList; + if ( !pList ) { + pResData->pFilterList = new ExportList(); + pList = pResData->pFilterList; + nListIndex = 0; + } + } + else if ( nList == LIST_ITEM ) { + pList = pResData->pItemList; + if ( !pList ) { + pResData->pItemList = new ExportList(); + pList = pResData->pItemList; + nListIndex = 0; + } + } + else if ( nList == LIST_PAIRED ) { + pList = pResData->pPairedList; + if ( !pList ) { + pResData->pPairedList = new ExportList(); + pList = pResData->pPairedList; + nListIndex = 0; + } + } + else if ( nList == LIST_UIENTRIES ) { + pList = pResData->pUIEntries; + if ( !pList ) { + pResData->pUIEntries = new ExportList(); + pList = pResData->pUIEntries; + nListIndex = 0; + } + } + else + return; + + if ( nListIndex + 1 > pList->size()) { + ExportListEntry *pNew = new ExportListEntry(); + (*pNew)[ LIST_REFID ] = ByteString::CreateFromInt32( REFID_NONE ); + pList->push_back( pNew ); + } + ExportListEntry *pCurEntry = (*pList)[ nListIndex ]; + + // For paired list use the line to set proper lid + if( nList == LIST_PAIRED ){ + (*pCurEntry)[ nListLang ] = rLine; + }else + (*pCurEntry)[ nListLang ] = rText; + + // Remember en-US fallback string, so each list has the same amount of elements + //if ( nListLang.EqualsIgnoreCaseAscii("en-US") ) { + if ( Export::isSourceLanguage( nListLang ) ) { + if( nList == LIST_PAIRED ){ + const ByteString sPlist("pairedlist"); + ByteString sKey = MergeDataFile::CreateKey( sPlist , pResData->sId , GetPairedListID( rLine ) , sFilename ); + pResData->addFallbackData( sKey , rText ); + } + // new fallback + else{ + const ByteString sPlist("list"); + ByteString a( pResData->sGId ); + a.Append( "." ); + a.Append( pResData->sId ); + sal_Int64 x = nListIndex+1; + ByteString b( ByteString::CreateFromInt64( x ) ); + ByteString sKey = MergeDataFile::CreateKey( sPlist , a , b , sFilename ); + pResData->addFallbackData( sKey , rText ); + } + // new fallback + } + + //if ( nListLang.EqualsIgnoreCaseAscii("en-US") ) { + if ( Export::isSourceLanguage( nListLang ) ) { + if( nList == LIST_PAIRED ){ + (*pCurEntry)[ SOURCE_LANGUAGE ] = rLine; + } + else + (*pCurEntry)[ SOURCE_LANGUAGE ] = rLine; + + pList->NewSourceLanguageListEntry(); + } + + //printf("Export::InsertListEntry ResData.id = %s ResData.ListData = %s\n",pResData->sId.GetBuffer() ,(*pCurEntry)[ nListLang ].GetBuffer()); + nListIndex++; +} + +/*****************************************************************************/ +void Export::CleanValue( ByteString &rValue ) +/*****************************************************************************/ +{ + while ( rValue.Len()) { + if (( rValue.GetChar( 0 ) == ' ' ) || ( rValue.GetChar( 0 ) == '\t' )) + rValue = rValue.Copy( 1 ); + else + break; + } + + if ( rValue.Len()) { + for ( USHORT i = rValue.Len() - 1; i > 0; i-- ) { + if (( rValue.GetChar( i ) == ' ' ) || ( rValue.GetChar( i ) == '\t' ) || + ( rValue.GetChar( i ) == '\n' ) || ( rValue.GetChar( i ) == ';' ) || + ( rValue.GetChar( i ) == '{' ) || ( rValue.GetChar( i ) == '\\' ) || + ( rValue.GetChar( i ) == '\r' )) + rValue.Erase( i ); + else + break; + } + } +} + + +/*****************************************************************************/ +ByteString Export::GetText( const ByteString &rSource, int nToken ) +/*****************************************************************************/ +#define TXT_STATE_NON 0x000 +#define TXT_STATE_TEXT 0x001 +#define TXT_STATE_MACRO 0x002 +{ + ByteString sReturn; + switch ( nToken ) { + case TEXTLINE: + case LONGTEXTLINE: { + ByteString sTmp( rSource.Copy( rSource.Search( "=" ))); + CleanValue( sTmp ); + sTmp.EraseAllChars( '\n' ); + sTmp.EraseAllChars( '\r' ); + + while ( sTmp.SearchAndReplace( "\\\\\"", "-=<[BSlashBSlashHKom]>=-\"" ) + != STRING_NOTFOUND ) {}; + while ( sTmp.SearchAndReplace( "\\\"", "-=<[Hochkomma]>=-" ) + != STRING_NOTFOUND ) {}; + while ( sTmp.SearchAndReplace( "\\", "-=<[0x7F]>=-" ) + != STRING_NOTFOUND ) {}; + while ( sTmp.SearchAndReplace( "\\0x7F", "-=<[0x7F]>=-" ) + != STRING_NOTFOUND ) {}; + + USHORT nStart = 0; + USHORT nState = TXT_STATE_MACRO; + + nState = TXT_STATE_TEXT; + nStart = 1; + + + for ( USHORT i = nStart; i < sTmp.GetTokenCount( '\"' ); i++ ) { + ByteString sToken = sTmp.GetToken( i, '\"' ); + if ( sToken.Len()) { + if ( nState == TXT_STATE_TEXT ) { + sReturn += sToken; + nState = TXT_STATE_MACRO; + } + else { + while( sToken.SearchAndReplace( "\t", " " ) != + STRING_NOTFOUND ) {}; + while( sToken.SearchAndReplace( " ", " " ) != + STRING_NOTFOUND ) {}; + sToken.EraseLeadingChars( ' ' ); + sToken.EraseTrailingChars( ' ' ); + if ( sToken.Len()) { + sReturn += "\\\" "; + sReturn += sToken; + sReturn += " \\\""; + } + nState = TXT_STATE_TEXT; + } + } + } + + while ( sReturn.SearchAndReplace( "-=<[0x7F]>=-", "" ) + != STRING_NOTFOUND ) {}; + while ( sReturn.SearchAndReplace( "-=<[Hochkomma]>=-", "\"" ) + != STRING_NOTFOUND ) {}; + while ( sReturn.SearchAndReplace( "-=<[BSlashBSlashHKom]>=-", "\\\\" ) + != STRING_NOTFOUND ) {}; + + + while ( sReturn.SearchAndReplace( "\\\\", "-=<[BSlashBSlash]>=-" ) + != STRING_NOTFOUND ) {}; + while ( sReturn.SearchAndReplace( "-=<[BSlashBSlash]>=-", "\\" ) + != STRING_NOTFOUND ) {}; + + } + break; + } + return sReturn; +} + +/*****************************************************************************/ +void Export::WriteToMerged( const ByteString &rText , bool bSDFContent ) +/*****************************************************************************/ +{ + static ByteString SLASH ('\\'); + static ByteString RETURN ('\n'); + //printf("%s\n",rText.GetBuffer() ); + + if ( !bDontWriteOutput || !bUnmerge ) { + ByteString sText( rText ); + while ( sText.SearchAndReplace( " \n", "\n" ) != STRING_NOTFOUND ) {}; + if( pParseQueue->bNextIsM && bSDFContent && sText.Len() > 2 ){ + for( USHORT n = 0 ; n < sText.Len() ; n++ ){ + if( sText.GetChar( n ) == '\n' && sText.GetChar( n-1 ) != '\\'){ + sText.Insert('\\' , n++ ); + + } + } + } + else if( pParseQueue->bLastWasM && sText.Len() > 2 ){ + for( USHORT n = 0 ; n < sText.Len() ; n++ ){ + if( sText.GetChar( n ) == '\n' && sText.GetChar( n-1 ) != '\\'){ + sText.Insert('\\' , n++ ); + } + if( sText.GetChar( n ) == '\n' )pParseQueue->bMflag=true; + } + } + else if( pParseQueue->bCurrentIsM && bSDFContent && sText.Len() > 2 ){ + for( USHORT n = 0 ; n < sText.Len() ; n++ ){ + if( sText.GetChar( n ) == '\n' && sText.GetChar( n-1 ) != '\\'){ + sText.Insert('\\' , n++ ); + pParseQueue->bMflag=true; + } + } + } + else if( pParseQueue->bMflag ){ + for( USHORT n = 1 ; n < sText.Len() ; n++ ){ + if( sText.GetChar( n ) == '\n' && sText.GetChar( n-1 ) != '\\'){ + sText.Insert('\\' , n++ ); + } + } + } + for ( USHORT i = 0; i < sText.Len(); i++ ) { + if ( sText.GetChar( i ) != '\n' ){ + aOutput.Write( ByteString( sText.GetChar( i )).GetBuffer(), 1 ); + + } + else{ + aOutput.WriteLine( ByteString()); + } + + } + } +} + +/*****************************************************************************/ +void Export::ConvertMergeContent( ByteString &rText ) +/*****************************************************************************/ +{ + BOOL bNoOpen = ( rText.Search( "\\\"" ) != 0 ); + ByteString sClose( rText.Copy( rText.Len() - 2 )); + BOOL bNoClose = ( sClose != "\\\"" ); + ByteString sNew; + for ( USHORT i = 0; i < rText.Len(); i++ ) { + ByteString sChar( rText.GetChar( i )); + if ( sChar == "\\" ) { + if (( i + 1 ) < rText.Len()) { + ByteString sNext( rText.GetChar( i + 1 )); + if ( sNext == "\"" ) { + sChar = "\""; + i++; + } + else if ( sNext == "n" ) { + sChar = "\\n"; + i++; + } + else if ( sNext == "t" ) { + sChar = "\\t"; + i++; + } + else if ( sNext == "\'" ) { + sChar = "\\\'"; + i++; + } + else + sChar = "\\\\"; + } + else { + sChar = "\\\\"; + } + } + else if ( sChar == "\"" ) { + sChar = "\\\""; + } + else if ( sChar == "" ) { + sChar = "\\0x7F"; + } + sNew += sChar; + } + + rText = sNew; + + if ( bNoOpen ) { + ByteString sTmp( rText ); + rText = "\""; + rText += sTmp; + } + if ( bNoClose ) + rText += "\""; +} + +/*****************************************************************************/ +BOOL Export::PrepareTextToMerge( ByteString &rText, USHORT nTyp, + ByteString &nLangIndex, ResData *pResData ) +/*****************************************************************************/ +{ + // position to merge in: + USHORT nStart = 0; + USHORT nEnd = 0; + ByteString sOldId = pResData->sId; + ByteString sOldGId = pResData->sGId; + ByteString sOldTyp = pResData->sResTyp; + + ByteString sOrigText( rText ); + + switch ( nTyp ) { + case LIST_STRING : + case LIST_UIENTRIES : + case LIST_FILTER : + case LIST_PAIRED: + case LIST_ITEM : + { + if ( bUnmerge ) + return TRUE; + + ExportList *pList = NULL; + switch ( nTyp ) { + case LIST_STRING : { + pResData->sResTyp = "stringlist"; + pList = pResData->pStringList; + } + break; + case LIST_UIENTRIES : { + pResData->sResTyp = "uientries"; + pList = pResData->pUIEntries; + } + break; + case LIST_FILTER : { + pResData->sResTyp = "filterlist"; + pList = pResData->pFilterList; + } + break; + case LIST_ITEM : { + pResData->sResTyp = "itemlist"; + pList = pResData->pItemList; + } + break; + case LIST_PAIRED : { + pResData->sResTyp = "pairedlist"; + pList = pResData->pPairedList; + } + break; + + } + if ( pList ) { + ExportListEntry *pCurEntry = (*pList)[ nListIndex - 1 ]; + if ( pCurEntry ) { + rText = (*pCurEntry)[ SOURCE_LANGUAGE ]; + if( nTyp == LIST_PAIRED ){ + pResData->addMergedLanguage( nLangIndex ); + } + } + } + + nStart = rText.Search( "\"" ); + if ( nStart == STRING_NOTFOUND ) { + rText = sOrigText; + return FALSE; + } + + BOOL bFound = FALSE; + for ( nEnd = nStart + 1; nEnd < rText.Len() && !bFound; nEnd++ ) { + if ( rText.GetChar( nEnd ) == '\"' ) + bFound = TRUE; + } + if ( !bFound ) { + rText = sOrigText; + return FALSE; + } + + nEnd --; + sLastListLine = rText; + if (( sLastListLine.Search( ">" ) != STRING_NOTFOUND ) && + ( sLastListLine.Search( "<" ) == STRING_NOTFOUND )) + { + ByteString sTmp = sLastListLine; + sLastListLine = "<"; + sLastListLine += sTmp; + } + if ( pResData->sResTyp.EqualsIgnoreCaseAscii( "pairedlist" ) ){ + pResData->sId = GetPairedListID( sLastListLine ); + } + else pResData->sId = ByteString::CreateFromInt32( nListIndex ); + + if ( pResData->sGId.Len()) + pResData->sGId += "."; + pResData->sGId += sOldId; + nTyp = STRING_TYP_TEXT; + } + break; + case STRING_TYP_TEXT : + case STRING_TYP_HELPTEXT : + case STRING_TYP_QUICKHELPTEXT : + case STRING_TYP_TITLE : + { + nStart = rText.Search( "=" ); + if ( nStart == STRING_NOTFOUND ) { + rText = sOrigText; + return FALSE; + } + + nStart++; + BOOL bFound = FALSE; + while(( nStart < rText.Len()) && !bFound ) { + if (( rText.GetChar( nStart ) != ' ' ) && ( rText.GetChar( nStart ) != '\t' )) + bFound = TRUE; + else + nStart ++; + } + + // no start position found + if ( !bFound ) { + rText = sOrigText; + return FALSE; + } + + // position to end mergeing in + nEnd = rText.Len() - 1; + bFound = FALSE; + + while (( nEnd > nStart ) && !bFound ) { + if (( rText.GetChar( nEnd ) != ' ' ) && ( rText.GetChar( nEnd ) != '\t' ) && + ( rText.GetChar( nEnd ) != '\n' ) && ( rText.GetChar( nEnd ) != ';' ) && + ( rText.GetChar( nEnd ) != '{' ) && ( rText.GetChar( nEnd ) != '\\' )) + { + bFound = TRUE; + } + else + nEnd --; + } + } + break; + } + + // search for merge data + if ( !pMergeDataFile ){ + pMergeDataFile = new MergeDataFile( sMergeSrc, sFile , bErrorLog, aCharSet);//, bUTF8 ); + + // Init Languages + ByteString sTmp = Export::sLanguages; + if( sTmp.ToUpperAscii().Equals("ALL") ) + SetLanguages( pMergeDataFile->GetLanguages() ); + else if( !isInitialized )InitLanguages(); + + } + + PFormEntrys *pEntrys = pMergeDataFile->GetPFormEntrys( pResData ); + pResData->sId = sOldId; + pResData->sGId = sOldGId; + pResData->sResTyp = sOldTyp; + + if ( !pEntrys ) { + rText = sOrigText; + return FALSE; // no data found + } + + ByteString sContent; + pEntrys->GetTransex3Text( sContent, nTyp, nLangIndex ); + if ( !sContent.Len() && ( ! Export::isSourceLanguage( nLangIndex ) )) { + rText = sOrigText; + return FALSE; // no data found + } + + if ( Export::isSourceLanguage( nLangIndex ) ) { + return FALSE; + } + + ByteString sPostFix( rText.Copy( ++nEnd )); + rText.Erase( nStart ); + + ConvertMergeContent( sContent ); + + + + // merge new res. in text line + rText += sContent; + rText += sPostFix; + + return TRUE; +} + +/*****************************************************************************/ +void Export::MergeRest( ResData *pResData, USHORT nMode ) +/*****************************************************************************/ +{ + if ( !pMergeDataFile ){ + pMergeDataFile = new MergeDataFile( sMergeSrc, sFile ,bErrorLog, aCharSet);//, bUTF8 ); + + // Init Languages + ByteString sTmp = Export::sLanguages; + if( sTmp.ToUpperAscii().Equals("ALL") ) + SetLanguages( pMergeDataFile->GetLanguages() ); + else if( !isInitialized )InitLanguages(); + + } + switch ( nMode ) { + case MERGE_MODE_NORMAL : { + PFormEntrys *pEntry = pMergeDataFile->GetPFormEntrys( pResData ); + + bool bWriteNoSlash = false; + if ( pEntry && pResData->bText ) { + + BOOL bAddSemikolon = FALSE; + BOOL bFirst = TRUE; + ByteString sCur; + ByteString sTmp = Export::sLanguages; + + for( unsigned int n = 0; n < aLanguages.size(); n++ ){ + sCur = aLanguages[ n ]; + + ByteString sText; + BOOL bText = pEntry->GetTransex3Text( sText, STRING_TYP_TEXT, sCur , TRUE ); + if ( bText && sText.Len() && sText != "-" ) { + ByteString sOutput; + if ( bNextMustBeDefineEOL) { + if ( bFirst ) + sOutput += "\t\\\n"; + else + sOutput += ";\t\\\n"; + } + bFirst=FALSE; + sOutput += "\t"; + sOutput += pResData->sTextTyp; + if ( ! Export::isSourceLanguage( sCur ) ) { + sOutput += "[ "; + sOutput += sCur; + sOutput += " ] "; + } + sOutput += "= "; + ConvertMergeContent( sText ); + sOutput += sText; + + if ( bDefine && bWriteNoSlash ) + sOutput += ";\n"; + + if ( bDefine ) + sOutput += ";\\\n"; + else if ( !bNextMustBeDefineEOL ) + sOutput += ";\n"; + else + bAddSemikolon = TRUE; + for ( USHORT j = 1; j < nLevel; j++ ) + sOutput += "\t"; + WriteToMerged( sOutput , true ); + } + } + + + if ( bAddSemikolon ) { + ByteString sOutput( ";" ); + WriteToMerged( sOutput , false ); + } + } + + if ( pEntry && pResData->bQuickHelpText ) { + BOOL bAddSemikolon = FALSE; + BOOL bFirst = TRUE; + ByteString sCur; + + for( unsigned int n = 0; n < aLanguages.size(); n++ ){ + sCur = aLanguages[ n ]; + + ByteString sText; + BOOL bText = pEntry->GetTransex3Text( sText, STRING_TYP_QUICKHELPTEXT, sCur, TRUE ); + if ( bText && sText.Len() && sText != "-" ) { + ByteString sOutput; + if ( bNextMustBeDefineEOL) { + if ( bFirst ) + sOutput += "\t\\\n"; + else + sOutput += ";\t\\\n"; + } + bFirst=FALSE; + sOutput += "\t"; + sOutput += "QuickHelpText"; + if ( ! Export::isSourceLanguage( sCur ) ) { + sOutput += "[ "; + sOutput += sCur; + sOutput += " ] "; + } + sOutput += "= "; + ConvertMergeContent( sText ); + sOutput += sText; + if ( bDefine ) + sOutput += ";\\\n"; + else if ( !bNextMustBeDefineEOL ) + sOutput += ";\n"; + else + bAddSemikolon = TRUE; + for ( USHORT j = 1; j < nLevel; j++ ) + sOutput += "\t"; + WriteToMerged( sOutput ,true ); + } + } + if ( bAddSemikolon ) { + ByteString sOutput( ";" ); + WriteToMerged( sOutput , false ); + } + } + + if ( pEntry && pResData->bTitle ) { + BOOL bAddSemikolon = FALSE; + BOOL bFirst = TRUE; + ByteString sCur; + + for( unsigned int n = 0; n < aLanguages.size(); n++ ){ + sCur = aLanguages[ n ]; + + ByteString sText; + BOOL bText = pEntry->GetTransex3Text( sText, STRING_TYP_TITLE, sCur, TRUE ); + if ( bText && sText.Len() && sText != "-" ) { + ByteString sOutput; + if ( bNextMustBeDefineEOL) { + if ( bFirst ) + sOutput += "\t\\\n"; + else + sOutput += ";\t\\\n"; + } + bFirst=FALSE; + sOutput += "\t"; + sOutput += "Title"; + if ( ! Export::isSourceLanguage( sCur ) ) { + sOutput += "[ "; + sOutput += sCur; + sOutput += " ] "; + } + sOutput += "= "; + ConvertMergeContent( sText ); + sOutput += sText; + if ( bDefine ) + sOutput += ";\\\n"; + else if ( !bNextMustBeDefineEOL ) + sOutput += ";\n"; + else + bAddSemikolon = TRUE; + for ( USHORT j = 1; j < nLevel; j++ ) + sOutput += "\t"; + WriteToMerged( sOutput ,true ); + } + } + if ( bAddSemikolon ) { + ByteString sOutput( ";" ); + WriteToMerged( sOutput ,false); + } + } + // Merge Lists + + if ( pResData->bList ) { + bool bPairedList = false; + ByteString sOldId = pResData->sId; + ByteString sOldGId = pResData->sGId; + ByteString sOldTyp = pResData->sResTyp; + if ( pResData->sGId.Len()) + pResData->sGId += "."; + pResData->sGId += sOldId; + ByteString sSpace; + for ( USHORT i = 1; i < nLevel-1; i++ ) + sSpace += "\t"; + for ( USHORT nT = LIST_STRING; nT <= LIST_UIENTRIES; nT++ ) { + ExportList *pList = NULL; + switch ( nT ) { + case LIST_STRING : pResData->sResTyp = "stringlist"; pList = pResData->pStringList; bPairedList = false; break; + case LIST_FILTER : pResData->sResTyp = "filterlist"; pList = pResData->pFilterList; bPairedList = false; break; + case LIST_UIENTRIES : pResData->sResTyp = "uientries"; pList = pResData->pUIEntries;bPairedList = false; break; + case LIST_ITEM : pResData->sResTyp = "itemlist"; pList = pResData->pItemList; bPairedList = false; break; + case LIST_PAIRED : pResData->sResTyp = "pairedlist"; pList = pResData->pPairedList; bPairedList = true; break; + } + ByteString sCur; + for( unsigned int n = 0; n < aLanguages.size(); n++ ){ + sCur = aLanguages[ n ]; + USHORT nIdx = 1; + + // Set matching pairedlist identifier + if( bPairedList && pResData->pPairedList && ( nIdx == 1 ) ){ + ExportListEntry* pListE = ( ExportListEntry* ) (*pResData->pPairedList)[ nIdx-1 ]; + pResData->sId = GetPairedListID ( (*pListE)[ SOURCE_LANGUAGE ] ); + } + else + pResData->sId = ByteString("1"); + + PFormEntrys *pEntrys; + ULONG nLIndex = 0; + ULONG nMaxIndex = 0; + if ( pList ) + nMaxIndex = pList->GetSourceLanguageListEntryCount(); + pEntrys = pMergeDataFile->GetPFormEntrys( pResData ); + while( pEntrys && ( nLIndex < nMaxIndex )) { + ByteString sText; + BOOL bText; + bText = pEntrys->GetTransex3Text( sText, STRING_TYP_TEXT, sCur, TRUE ); + if( !bText ) + bText = pEntrys->GetTransex3Text( sText , STRING_TYP_TEXT, SOURCE_LANGUAGE , FALSE ); + + // Use fallback, if data is missing in sdf file + if( !bText && bPairedList ){ + if( pResData->isMerged( sCur ) ) break; + const ByteString sPlist("pairedlist"); + ByteString sKey = MergeDataFile::CreateKey( sPlist , pResData->sGId , pResData->sId , sFilename ); + bText = pResData->getFallbackData( sKey , sText ); + }else if ( !bText ){// new fallback + if( pResData->isMerged( sCur ) ) break; + const ByteString sPlist("list"); + ByteString sKey = MergeDataFile::CreateKey( sPlist , pResData->sGId , pResData->sId , sFilename ); + bText = pResData->getFallbackData( sKey , sText ); + } // new fallback + + if ( bText && sText.Len()) { + if ( nIdx == 1 ) { + ByteString sHead; + if ( bNextMustBeDefineEOL ) + sHead = "\\\n\t"; + sHead += sSpace; + switch ( nT ) { + case LIST_STRING : sHead += "StringList "; break; + case LIST_FILTER : sHead += "FilterList "; break; + case LIST_ITEM : sHead += "ItemList "; break; + case LIST_PAIRED : sHead += "PairedList "; break; + case LIST_UIENTRIES : sHead += "UIEntries "; break; + } + sHead += "[ "; + sHead += sCur; + sHead += " ] "; + //} + if ( bDefine || bNextMustBeDefineEOL ) { + sHead += "= \\\n"; + sHead += sSpace; + sHead += "\t{\\\n\t"; + } + else { + sHead += "= \n"; + sHead += sSpace; + sHead += "\t{\n\t"; + } + WriteToMerged( sHead , true); + } + ByteString sLine; + if ( pList && (*pList)[ nLIndex ] ) + sLine = ( *(*pList)[ nLIndex ])[ SOURCE_LANGUAGE ]; + if ( !sLine.Len()) + sLine = sLastListLine; + + if ( sLastListLine.Search( "<" ) != STRING_NOTFOUND ) { + if (( nT != LIST_UIENTRIES ) && + (( sLine.Search( "{" ) == STRING_NOTFOUND ) || + ( sLine.Search( "{" ) >= sLine.Search( "\"" ))) && + (( sLine.Search( "<" ) == STRING_NOTFOUND ) || + ( sLine.Search( "<" ) >= sLine.Search( "\"" )))) + { + sLine.SearchAndReplace( "\"", "< \"" ); + } + } + + USHORT nStart, nEnd; + nStart = sLine.Search( "\"" ); + + ByteString sPostFix; + if( !bPairedList ){ + nEnd = sLine.SearchBackward( '\"' ); + sPostFix = ByteString( sLine.Copy( ++nEnd )); + sLine.Erase( nStart ); + } + + + ConvertMergeContent( sText ); + + // merge new res. in text line + if( bPairedList ){ + sLine = MergePairedList( sLine , sText ); + } + else{ + sLine += sText; + sLine += sPostFix; + } + + ByteString sText1( "\t" ); + sText1 += sLine; + if ( bDefine || bNextMustBeDefineEOL ) + sText1 += " ;\\\n"; + else + sText1 += " ;\n"; + sText1 += sSpace; + sText1 += "\t"; + WriteToMerged( sText1 ,true ); + + // Set matching pairedlist identifier + if ( bPairedList ){ + nIdx++; + ExportListEntry* pListE = ( ExportListEntry* )(*pResData->pPairedList)[ ( nIdx ) -1 ]; + if( pListE ){ + pResData->sId = GetPairedListID ( (*pListE)[ SOURCE_LANGUAGE ] ); + } + } + else + pResData->sId = ByteString::CreateFromInt32( ++nIdx ); + } + else + break; + nLIndex ++; + PFormEntrys *oldEntry = pEntrys; + pEntrys = pMergeDataFile->GetPFormEntrys( pResData ); // <--- game over + if( !pEntrys ) + pEntrys = oldEntry; + } + if ( nIdx > 1 ) { + ByteString 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; + } + } + break; + case MERGE_MODE_LIST : { + ExportList *pList = NULL; + switch ( nList ) { + // PairedList + case LIST_STRING : pList = pResData->pStringList; break; + case LIST_FILTER : pList = pResData->pFilterList; break; + case LIST_UIENTRIES : pList = pResData->pUIEntries; break; + case LIST_ITEM : pList = pResData->pItemList; break; + case LIST_PAIRED : pList = pResData->pPairedList; break; + + } + + nListIndex++; + ULONG nMaxIndex = 0; + if ( pList ) + nMaxIndex = pList->GetSourceLanguageListEntryCount(); + ByteString sLine; + if ( pList && (*pList)[ nListIndex ] ) + sLine = ( *(*pList)[ nListIndex ])[ SOURCE_LANGUAGE ]; + if ( !sLine.Len()) + sLine = sLastListLine; + + if ( sLastListLine.Search( "<" ) != STRING_NOTFOUND ) { + if (( nList != LIST_UIENTRIES ) && + (( sLine.Search( "{" ) == STRING_NOTFOUND ) || + ( sLine.Search( "{" ) >= sLine.Search( "\"" ))) && + (( sLine.Search( "<" ) == STRING_NOTFOUND ) || + ( sLine.Search( "<" ) >= sLine.Search( "\"" )))) + { + sLine.SearchAndReplace( "\"", "< \"" ); + } + } + + while( PrepareTextToMerge( sLine, nList, nListLang, pResData ) && ( nListIndex <= nMaxIndex )) { + ByteString sText( "\t" ); + sText += sLine; + sText += " ;"; + sText += "\n"; + for ( USHORT i = 0; i < nLevel; i++ ) + sText += "\t"; + WriteToMerged( sText ,false ); + nListIndex++; + if ( pList && (*pList)[ nListIndex ]) + sLine = ( *(*pList)[ nListIndex ])[ SOURCE_LANGUAGE ]; + if ( !sLine.Len()) + sLine = sLastListLine; + sLine += " ;"; + } + } + break; + } + pParseQueue->bMflag = false; +} + +ByteString Export::MergePairedList( ByteString& sLine , ByteString& sText ){ +// < "xy" ; IDENTIFIER ; > + ByteString sPre = sLine.Copy( 0 , sLine.Search('\"') ); + ByteString sPost = sLine.Copy( sLine.SearchBackward('\"') + 1 , sLine.Len() ); + sPre.Append( sText ); + sPre.Append( sPost ); + return sPre; +} + +/*****************************************************************************/ +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 ){ + USHORT nLen = aEntry.sLine.Len(); + + if( !bStart ){ + aQueueCur->push( aEntry ); + if( nLen > 1 && aEntry.sLine.GetChar( nLen-1 ) == '\n' ) + bStart = true; + else if ( aEntry.nTyp != IGNOREDTOKENS ){ + if( nLen > 1 && ( aEntry.sLine.GetChar( nLen-1 ) == '\\') ){ + // Next is Macro + bCurrentIsM = true; + }else{ + // Next is no Macro + bCurrentIsM = false; + } + } + } + else{ + aQueueNext->push( aEntry ); + if( nLen > 1 && aEntry.sLine.GetChar( nLen-1 ) != '\n' ){ + if( nLen > 1 && ( aEntry.sLine.GetChar( nLen-1 ) == '\\') ){ + // Next is Macro + bNextIsM = true; + } + else{ + // Next is no Macro + bNextIsM = false; + } + }else if( nLen > 2 && aEntry.sLine.GetChar( nLen-1 ) == '\n' ){ + if( aEntry.nTyp != IGNOREDTOKENS ){ + if( nLen > 2 && ( aEntry.sLine.GetChar( nLen-2 ) == '\\') ){ + // Next is Macro + bNextIsM = true; + } + else{ + // Next is no Macro + bNextIsM = false; + } + } + // Pop current + Pop( *aQueueCur ); + bLastWasM = bCurrentIsM; + // next -> current + bCurrentIsM = bNextIsM; + aQref = aQueueCur; + aQueueCur = aQueueNext; + aQueueNext = aQref; + + } + + else{ + // Pop current + Pop( *aQueueCur ); + bLastWasM = bCurrentIsM; + // next -> current + bCurrentIsM = bNextIsM; + aQref = aQueueCur; + aQueueCur = aQueueNext; + aQueueNext = aQref; + } + } +} + +void ParserQueue::Close(){ + // Pop current + Pop( *aQueueCur ); + // next -> current + bLastWasM = bCurrentIsM; + bCurrentIsM = bNextIsM; + aQref = aQueueCur; + aQueueCur = aQueueNext; + aQueueNext = aQref; + bNextIsM = false; + Pop( *aQueueNext ); +}; +void ParserQueue::Pop( std::queue<QueueEntry>& aQueue ){ + while( !aQueue.empty() ){ + QueueEntry aEntry = aQueue.front(); + aQueue.pop(); + aExport.Execute( aEntry.nTyp , (char*) aEntry.sLine.GetBuffer() ); + } +} +ParserQueue::ParserQueue( Export& aExportObj ) + : + bCurrentIsM( false ), + bNextIsM( false ) , + bLastWasM( false ), + bMflag( false ) , + aExport( aExportObj ) , + bStart( false ) , + bStartNext( false ) +{ + aQueueNext = new std::queue<QueueEntry>; + aQueueCur = new std::queue<QueueEntry>; +} + + +ParserQueue::~ParserQueue(){ + if( aQueueNext ) delete aQueueNext; + if( aQueueCur ) delete aQueueCur; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/export2.cxx b/l10ntools/source/export2.cxx new file mode 100644 index 000000000000..cd34fae43d88 --- /dev/null +++ b/l10ntools/source/export2.cxx @@ -0,0 +1,712 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_l10ntools.hxx" +#include "export.hxx" +#include "utf8conv.hxx" +#include <tools/datetime.hxx> +#include <tools/isofallback.hxx> +#include <stdio.h> +#include <osl/time.h> +#include <osl/process.h> +#include <rtl/ustring.hxx> +#include <sal/macros.h> +#include <iostream> +#include <iomanip> +#include <tools/urlobj.hxx> +#include <time.h> +#include <stdlib.h> + +using namespace std; +// +// class ResData(); +// + +/*****************************************************************************/ +ResData::~ResData() +/*****************************************************************************/ +{ + if ( pStringList ) { + // delete existing res. of type StringList + for ( size_t i = 0; i < pStringList->size(); i++ ) { + ExportListEntry* test = (*pStringList)[ i ]; + if( test != NULL ) delete test; + } + delete pStringList; + } + if ( pFilterList ) { + // delete existing res. of type FilterList + for ( size_t i = 0; i < pFilterList->size(); i++ ) { + ExportListEntry* test = (*pFilterList)[ i ]; + delete test; + } + delete pFilterList; + } + if ( pItemList ) { + // delete existing res. of type ItemList + for ( size_t i = 0; i < pItemList->size(); i++ ) { + ExportListEntry* test = (*pItemList)[ i ]; + delete test; + } + delete pItemList; + } + if ( pUIEntries ) { + // delete existing res. of type UIEntries + for ( size_t i = 0; i < pUIEntries->size(); i++ ) { + ExportListEntry* test = (*pUIEntries)[ i ]; + delete test; + } + delete pUIEntries; + } +} + +// +// class Export +// + +/*****************************************************************************/ +ByteString Export::sLanguages; +ByteString Export::sForcedLanguages; +//ByteString Export::sIsoCode99; +/*****************************************************************************/ + +void Export::DumpExportList( ByteString& sListName , ExportList& aList ){ + printf( "%s\n", sListName.GetBuffer() ); + ByteString l(""); + ExportListEntry* aEntry; + for( unsigned int x = 0; x < aList.size() ; x++ ){ + aEntry = (ExportListEntry*) aList[ x ]; + Export::DumpMap( l , *aEntry ); + } + printf("\n"); +} +ByteString Export::DumpMap( ByteString& sMapName , ByteStringHashMap& aMap ){ + ByteStringHashMap::const_iterator idbg; + ByteString sReturn; + + if( sMapName.Len() ) + printf("MapName %s\n", sMapName.GetBuffer()); + if( aMap.size() < 1 ) return ByteString(); + for( idbg = aMap.begin() ; idbg != aMap.end(); ++idbg ){ + ByteString a( idbg->first ); + ByteString b( idbg->second ); + printf("[%s]= %s",a.GetBuffer(),b.GetBuffer()); + printf("\n"); + } + printf("\n"); + return sReturn; +} +/*****************************************************************************/ +void Export::SetLanguages( std::vector<ByteString> val ){ +/*****************************************************************************/ + aLanguages = val; + isInitialized = true; +} +/*****************************************************************************/ +std::vector<ByteString> Export::GetLanguages(){ +/*****************************************************************************/ + return aLanguages; +} +/*****************************************************************************/ +std::vector<ByteString> Export::GetForcedLanguages(){ +/*****************************************************************************/ + return aForcedLanguages; +} +std::vector<ByteString> Export::aLanguages = std::vector<ByteString>(); +std::vector<ByteString> Export::aForcedLanguages = std::vector<ByteString>(); + + +/*****************************************************************************/ +void Export::QuotHTMLXRM( ByteString &rString ) +/*****************************************************************************/ +{ + ByteString sReturn; + //BOOL bBreak = FALSE; + for ( USHORT i = 0; i < rString.Len(); i++ ) { + ByteString sTemp = rString.Copy( i ); + if ( sTemp.Search( "<Arg n=" ) == 0 ) { + while ( i < rString.Len() && rString.GetChar( i ) != '>' ) { + sReturn += rString.GetChar( i ); + i++; + } + if ( rString.GetChar( i ) == '>' ) { + sReturn += ">"; + i++; + } + } + + if ( i < rString.Len()) { + switch ( rString.GetChar( i )) { + case '<': + if( i+2 < rString.Len() && + (rString.GetChar( i+1 ) == 'b' || rString.GetChar( i+1 ) == 'B') && + rString.GetChar( i+2 ) == '>' ) + { + sReturn +="<b>"; + i += 2; + } + else if( i+3 < rString.Len() && + rString.GetChar( i+1 ) == '/' && + (rString.GetChar( i+2 ) == 'b' || rString.GetChar( i+2 ) == 'B') && + rString.GetChar( i+3 ) == '>' ) + { + sReturn +="</b>"; + i += 3; + } + else + sReturn += "<"; + break; + + case '>': + sReturn += ">"; + break; + + case '\"': + sReturn += """; + break; + + case '\'': + sReturn += "'"; + break; + + case '&': + if ((( i + 4 ) < rString.Len()) && + ( rString.Copy( i, 5 ) == "&" )) + sReturn += rString.GetChar( i ); + else + sReturn += "&"; + break; + + default: + sReturn += rString.GetChar( i ); + break; + } + } + } + rString = sReturn; +} +/*****************************************************************************/ +void Export::QuotHTML( ByteString &rString ) +/*****************************************************************************/ +{ + ByteString sReturn; + for ( USHORT i = 0; i < rString.Len(); i++ ) { + ByteString sTemp = rString.Copy( i ); + if ( sTemp.Search( "<Arg n=" ) == 0 ) { + while ( i < rString.Len() && rString.GetChar( i ) != '>' ) { + sReturn += rString.GetChar( i ); + i++; + } + if ( rString.GetChar( i ) == '>' ) { + sReturn += ">"; + i++; + } + } + if ( i < rString.Len()) { + switch ( rString.GetChar( i )) { + case '<': + sReturn += "<"; + break; + + case '>': + sReturn += ">"; + break; + + case '\"': + sReturn += """; + break; + + case '\'': + sReturn += "'"; + break; + + case '&': + if ((( i + 4 ) < rString.Len()) && + ( rString.Copy( i, 5 ) == "&" )) + sReturn += rString.GetChar( i ); + else + sReturn += "&"; + break; + + default: + sReturn += rString.GetChar( i ); + break; + } + } + } + rString = sReturn; +} + +void Export::RemoveUTF8ByteOrderMarker( ByteString &rString ){ + if( hasUTF8ByteOrderMarker( rString ) ) + rString.Erase( 0 , 3 ); +} + +bool Export::hasUTF8ByteOrderMarker( const ByteString &rString ){ + // Byte order marker signature + + const unsigned char c1 = 0xEF; + const unsigned char c2 = 0xBB; + const unsigned char c3 = 0xBF; + + const char bom[ 3 ] = { c1 , c2 , c3 }; + + return rString.Len() >= 3 && + rString.GetChar( 0 ) == bom[ 0 ] && + rString.GetChar( 1 ) == bom[ 1 ] && + rString.GetChar( 2 ) == bom[ 2 ] ; +} +bool Export::fileHasUTF8ByteOrderMarker( const ByteString &rString ){ + SvFileStream aFileIn( String( rString , RTL_TEXTENCODING_ASCII_US ) , STREAM_READ ); + ByteString sLine; + if( !aFileIn.IsEof() ) { + aFileIn.ReadLine( sLine ); + if( aFileIn.IsOpen() ) aFileIn.Close(); + return hasUTF8ByteOrderMarker( sLine ); + } + if( aFileIn.IsOpen() ) aFileIn.Close(); + return false; +} +void Export::RemoveUTF8ByteOrderMarkerFromFile( const ByteString &rFilename ){ + SvFileStream aFileIn( String( rFilename , RTL_TEXTENCODING_ASCII_US ) , STREAM_READ ); + ByteString sLine; + if( !aFileIn.IsEof() ) { + aFileIn.ReadLine( sLine ); + // Test header + if( hasUTF8ByteOrderMarker( sLine ) ){ + DirEntry aTempFile = Export::GetTempFile(); + ByteString sTempFile = ByteString( aTempFile.GetFull() , RTL_TEXTENCODING_ASCII_US ); + SvFileStream aNewFile( String( sTempFile , RTL_TEXTENCODING_ASCII_US ) , STREAM_WRITE ); + // Remove header + RemoveUTF8ByteOrderMarker( sLine ); + aNewFile.WriteLine( sLine ); + // Copy the rest + while( !aFileIn.IsEof() ){ + aFileIn.ReadLine( sLine ); + aNewFile.WriteLine( sLine ); + } + if( aFileIn.IsOpen() ) aFileIn.Close(); + if( aNewFile.IsOpen() ) aNewFile.Close(); + DirEntry aEntry( rFilename.GetBuffer() ); + aEntry.Kill(); + DirEntry( sTempFile ).MoveTo( DirEntry( rFilename.GetBuffer() ) ); + } + } + if( aFileIn.IsOpen() ) aFileIn.Close(); +} + +bool Export::CopyFile( const ByteString& source , const ByteString& dest ) +{ + const int BUFFERSIZE = 8192; + char buf[ BUFFERSIZE ]; + + FILE* IN_FILE = fopen( source.GetBuffer() , "r" ); + if( IN_FILE == NULL ) + { + cerr << "Export::CopyFile WARNING: Could not open " << source.GetBuffer() << "\n"; + return false; + } + + FILE* OUT_FILE = fopen( dest.GetBuffer() , "w" ); + if( OUT_FILE == NULL ) + { + cerr << "Export::CopyFile WARNING: Could not open/create " << dest.GetBuffer() << " for writing\n"; + fclose( IN_FILE ); + return false; + } + + while( fgets( buf , BUFFERSIZE , IN_FILE ) != NULL ) + { + if( fputs( buf , OUT_FILE ) == EOF ) + { + cerr << "Export::CopyFile WARNING: Write problems " << source.GetBuffer() << "\n"; + fclose( IN_FILE ); + fclose( OUT_FILE ); + return false; + } + } + if( ferror( IN_FILE ) ) + { + cerr << "Export::CopyFile WARNING: Read problems " << dest.GetBuffer() << "\n"; + fclose( IN_FILE ); + fclose( OUT_FILE ); + return false; + } + fclose ( IN_FILE ); + fclose ( OUT_FILE ); + + return true; +} + +/*****************************************************************************/ +void Export::UnquotHTML( ByteString &rString ) +/*****************************************************************************/ +{ + ByteString sReturn; + while ( rString.Len()) { + if ( rString.Copy( 0, 5 ) == "&" ) { + sReturn += "&"; + rString.Erase( 0, 5 ); + } + else if ( rString.Copy( 0, 4 ) == "<" ) { + sReturn += "<"; + rString.Erase( 0, 4 ); + } + else if ( rString.Copy( 0, 4 ) == ">" ) { + sReturn += ">"; + rString.Erase( 0, 4 ); + } + else if ( rString.Copy( 0, 6 ) == """ ) { + sReturn += "\""; + rString.Erase( 0, 6 ); + } + else if ( rString.Copy( 0, 6 ) == "'" ) { + sReturn += "\'"; + rString.Erase( 0, 6 ); + } + else { + sReturn += rString.GetChar( 0 ); + rString.Erase( 0, 1 ); + } + } + rString = sReturn; +} +bool Export::isSourceLanguage( const ByteString &sLanguage ) +{ + return !isAllowed( sLanguage ); +} +bool Export::isAllowed( const ByteString &sLanguage ){ + return ! ( sLanguage.EqualsIgnoreCaseAscii("en-US") ); +} +/*****************************************************************************/ +bool Export::LanguageAllowed( const ByteString &nLanguage ) +/*****************************************************************************/ +{ + return std::find( aLanguages.begin() , aLanguages.end() , nLanguage ) != aLanguages.end(); +} + +bool Export::isInitialized = false; + +/*****************************************************************************/ +void Export::InitLanguages( bool bMergeMode ){ +/*****************************************************************************/ + if( !isInitialized ){ + ByteString sTmp; + ByteStringBoolHashMap aEnvLangs; + for ( USHORT x = 0; x < sLanguages.GetTokenCount( ',' ); x++ ){ + sTmp = sLanguages.GetToken( x, ',' ).GetToken( 0, '=' ); + sTmp.EraseLeadingAndTrailingChars(); + if( bMergeMode && !isAllowed( sTmp ) ){} + else if( !( (sTmp.GetChar(0)=='x' || sTmp.GetChar(0)=='X') && sTmp.GetChar(1)=='-' ) ){ + aLanguages.push_back( sTmp ); + } + } + InitForcedLanguages( bMergeMode ); + isInitialized = true; + } +} +/*****************************************************************************/ +void Export::InitForcedLanguages( bool bMergeMode ){ +/*****************************************************************************/ + ByteString sTmp; + ByteStringBoolHashMap aEnvLangs; + for ( USHORT x = 0; x < sForcedLanguages.GetTokenCount( ',' ); x++ ){ + sTmp = sForcedLanguages.GetToken( x, ',' ).GetToken( 0, '=' ); + sTmp.EraseLeadingAndTrailingChars(); + if( bMergeMode && isAllowed( sTmp ) ){} + else if( !( (sTmp.GetChar(0)=='x' || sTmp.GetChar(0)=='X') && sTmp.GetChar(1)=='-' ) ) + aForcedLanguages.push_back( sTmp ); + } +} + +/*****************************************************************************/ +ByteString Export::GetFallbackLanguage( const ByteString nLanguage ) +/*****************************************************************************/ +{ + ByteString sFallback=nLanguage; + GetIsoFallback( sFallback ); + return sFallback; +} + +void Export::replaceEncoding( ByteString& rString ) +{ +// ™ -> \u2122 + + for( xub_StrLen idx = 0; idx <= rString.Len()-8 ; idx++ ) + { + if( rString.GetChar( idx ) == '&' && + rString.GetChar( idx+1 ) == '#' && + rString.GetChar( idx+2 ) == 'x' && + rString.GetChar( idx+7 ) == ';' ) + { + ByteString sTmp = rString.Copy( 0 , idx ); + sTmp.Append( "\\u" ); + sTmp.Append( rString.GetChar( idx+3 ) ); + sTmp.Append( rString.GetChar( idx+4 ) ); + sTmp.Append( rString.GetChar( idx+5 ) ); + sTmp.Append( rString.GetChar( idx+6 ) ); + sTmp.Append( rString.Copy( idx+8 , rString.Len() ) ); + rString = sTmp; + } + } +} + +/*****************************************************************************/ +void Export::FillInFallbacks( ResData *pResData ) +/*****************************************************************************/ +{ + ByteString sCur; + for( unsigned int n = 0; n < aLanguages.size(); n++ ){ + sCur = aLanguages[ n ]; + if( isAllowed( sCur ) ){ + ByteString nFallbackIndex = GetFallbackLanguage( sCur ); + if( nFallbackIndex.Len() ){ + if ( !pResData->sText[ sCur ].Len()) + pResData->sText[ sCur ] = + pResData->sText[ nFallbackIndex ]; + + if ( !pResData->sHelpText[ sCur ].Len()) + pResData->sHelpText[ sCur ] = + pResData->sHelpText[ nFallbackIndex ]; + + if ( !pResData->sQuickHelpText[ sCur ].Len()) + pResData->sQuickHelpText[ sCur ] = + pResData->sQuickHelpText[ nFallbackIndex ]; + + if ( !pResData->sTitle[ sCur ].Len()) + pResData->sTitle[ sCur ] = + pResData->sTitle[ nFallbackIndex ]; + + if ( pResData->pStringList ) + FillInListFallbacks( + pResData->pStringList, sCur, nFallbackIndex ); + + if ( pResData->pPairedList ) + FillInListFallbacks( + pResData->pPairedList, sCur, nFallbackIndex ); + + if ( pResData->pFilterList ) + FillInListFallbacks( + pResData->pFilterList, sCur, nFallbackIndex ); + + if ( pResData->pItemList ) + FillInListFallbacks( + pResData->pItemList, sCur, nFallbackIndex ); + + if ( pResData->pUIEntries ) + FillInListFallbacks( + pResData->pUIEntries, sCur, nFallbackIndex ); + } + } + } +} + +/*****************************************************************************/ +void Export::FillInListFallbacks( + ExportList *pList, const ByteString &nSource, const ByteString &nFallback ) +/*****************************************************************************/ +{ + + for ( size_t i = 0; i < pList->size(); i++ ) { + ExportListEntry *pEntry = (*pList)[ i ]; + if ( !( *pEntry )[ nSource ].Len()){ + ( *pEntry )[ nSource ] = ( *pEntry )[ nFallback ]; + ByteString x = ( *pEntry )[ nSource ]; + ByteString y = ( *pEntry )[ nFallback ]; + } + } +} + +/*****************************************************************************/ +ByteString Export::GetTimeStamp() +/*****************************************************************************/ +{ +// return "xx.xx.xx"; + char buf[20]; + Time aTime; + + snprintf(buf, sizeof(buf), "%8d %02d:%02d:%02d", int(Date().GetDate()), + int(aTime.GetHour()), int(aTime.GetMin()), int(aTime.GetSec())); + return ByteString(buf); +} + +/*****************************************************************************/ +BOOL Export::ConvertLineEnds( + ByteString sSource, ByteString sDestination ) +/*****************************************************************************/ +{ + String sSourceFile( sSource, RTL_TEXTENCODING_ASCII_US ); + String sDestinationFile( sDestination, RTL_TEXTENCODING_ASCII_US ); + + SvFileStream aSource( sSourceFile, STREAM_READ ); + if ( !aSource.IsOpen()) + return FALSE; + SvFileStream aDestination( sDestinationFile, STREAM_STD_WRITE | STREAM_TRUNC ); + if ( !aDestination.IsOpen()) { + aSource.Close(); + return FALSE; + } + + ByteString sLine; + + while ( !aSource.IsEof()) { + aSource.ReadLine( sLine ); + if ( !aSource.IsEof()) { + sLine.EraseAllChars( '\r' ); + aDestination.WriteLine( sLine ); + } + else + aDestination.WriteByteString( sLine ); + } + + aSource.Close(); + aDestination.Close(); + + return TRUE; +} + +/*****************************************************************************/ +ByteString Export::GetNativeFile( ByteString sSource ) +/*****************************************************************************/ +{ + DirEntry aTemp( GetTempFile()); + ByteString sReturn( aTemp.GetFull(), RTL_TEXTENCODING_ASCII_US ); + + for ( USHORT i = 0; i < 10; i++ ) + if ( ConvertLineEnds( sSource, sReturn )) + return sReturn; + + return ""; +} + +const char* Export::GetEnv( const char *pVar ) +{ + char *pRet = getenv( pVar ); + if ( !pRet ) + pRet = 0; + return pRet; +} + + +int Export::getCurrentDirectory( rtl::OUString& base_fqurl_out, rtl::OUString& base_out ) +{ + DirEntry aDir("."); + aDir.ToAbs(); + base_out = rtl::OUString( aDir.GetFull() ); + return osl::File::getFileURLFromSystemPath( base_out , base_fqurl_out ); +} + +void Export::getCurrentDir( string& dir ) +{ + char buffer[64000]; + if( getcwd( buffer , sizeof( buffer ) ) == 0 ){ + cerr << "Error: getcwd failed!\n"; + exit( -1 ); + } + dir = string( buffer ); +} + + +// Stolen from sal/osl/unx/tempfile.c + +#define RAND_NAME_LENGTH 6 + +void Export::getRandomName( const ByteString& sPrefix , ByteString& sRandStr , const ByteString& sPostfix ) +{ + static const char LETTERS[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + static const int COUNT_OF_LETTERS = SAL_N_ELEMENTS(LETTERS) - 1; + sRandStr.Append( sPrefix ); + + static sal_uInt64 value; + char buffer[RAND_NAME_LENGTH]; + + TimeValue tv; + sal_uInt64 v; + int i; + + osl_getSystemTime( &tv ); + oslProcessInfo proInfo; + proInfo.Size = sizeof(oslProcessInfo); + osl_getProcessInfo( 0 , osl_Process_IDENTIFIER , &proInfo ); + + value += ((sal_uInt64) ( tv.Nanosec / 1000 ) << 16) ^ ( tv.Nanosec / 1000 ) ^ proInfo.Ident; + + v = value; + + for (i = 0; i < RAND_NAME_LENGTH; i++) + { + buffer[i] = LETTERS[v % COUNT_OF_LETTERS]; + v /= COUNT_OF_LETTERS; + } + + sRandStr.Append( buffer , RAND_NAME_LENGTH ); + sRandStr.Append( sPostfix ); +} + +void Export::getRandomName( ByteString& sRandStr ) +{ + const ByteString sEmpty; + getRandomName( sEmpty , sRandStr , sEmpty ); +} + +/*****************************************************************************/ +DirEntry Export::GetTempFile() +/*****************************************************************************/ +{ + rtl::OUString* sTempFilename = new rtl::OUString(); + + // Create a temp file + int nRC = osl::FileBase::createTempFile( 0 , 0 , sTempFilename ); + if( nRC ) printf(" osl::FileBase::createTempFile RC = %d",nRC); + + String strTmp( *sTempFilename ); + + INetURLObject::DecodeMechanism eMechanism = INetURLObject::DECODE_TO_IURI; + String sDecodedStr = INetURLObject::decode( strTmp , '%' , eMechanism ); + ByteString sTmp( sDecodedStr , RTL_TEXTENCODING_UTF8 ); + +#if defined(WNT) || defined(OS2) + sTmp.SearchAndReplace("file:///",""); + sTmp.SearchAndReplaceAll('/','\\'); +#else + // Set file permission to 644 + const sal_uInt64 nPerm = osl_File_Attribute_OwnRead | osl_File_Attribute_OwnWrite | + osl_File_Attribute_GrpRead | osl_File_Attribute_OthRead ; + + nRC = osl::File::setAttributes( *sTempFilename , nPerm ); + if( nRC ) printf(" osl::File::setAttributes RC = %d",nRC); + + sTmp.SearchAndReplace("file://",""); +#endif + DirEntry aDirEntry( sTmp ); + delete sTempFilename; + return aDirEntry; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/file.cxx b/l10ntools/source/file.cxx new file mode 100644 index 000000000000..d57c20d92c04 --- /dev/null +++ b/l10ntools/source/file.cxx @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_l10ntools.hxx" +#include <l10ntools/file.hxx> + +namespace transex +{ + +File::File( const rtl::OUString sFile ) +{ + sFileName = sFile; +} + +File::File( const rtl::OUString sFullPath , const rtl::OUString sFile ) +{ + sFileName = sFile; + sFullName = sFullPath; +} + +bool File::lessFile ( const File& rKey1, const File& rKey2 ) +{ + rtl::OUString sName1( ( static_cast< File >( rKey1 ) ).getFileName() ); + rtl::OUString sName2( ( static_cast< File >( rKey2 ) ).getFileName() ); + + return sName1.compareTo( sName2 ) < 0 ; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/filter/merge/FCFGMerge.cfg b/l10ntools/source/filter/merge/FCFGMerge.cfg new file mode 100644 index 000000000000..cae30bdd0260 --- /dev/null +++ b/l10ntools/source/filter/merge/FCFGMerge.cfg @@ -0,0 +1,121 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +#************************************************ +# Specify the verbose mode of this tool. +# 1 = show errors only +# 2 = show errors/warnings (default) +# 3 = show errors/warnings and some generic infos +# 4 = show anything (including detailed infos) +# +# [OPTIONAL] +#************************************************ + +loglevel = 2 + +#************************************************ +# This extension is used for all XML files. It doesnt +# matter if its used for reading fragments or writing +# XML packages. +# Must be given without any additional signes like "." +# or "*."! +# +# [REQUIRED] +#************************************************ + +extension_xcu=xcu + +#************************************************ +# This extension is used for all Package files. It doesnt +# matter if its used for reading such files or writing +# it. +# Must be given without any additional signes like "." +# or "*."! +# +# [REQUIRED] +#************************************************ + +extension_pkg=pkg + +#************************************************ +# These values are used to generate a correct XML +# header. +# Note: The property "xmlpackage" must be specified +# via command line. There exists more then one +# possible value. +# +# [REQUIRED] +#************************************************ + +xmlversion = 1.0 +xmlencoding = UTF-8 +xmlpath = org.openoffice.TypeDetection +#xmlpackage = + +#************************************************ +# These values are used to name the configuration +# sets inside the generated XCM file for different +# item groups like e.g. types, filters etcpp. +# +# [REQUIRED] +#************************************************ + +setname_types = Types +setname_filters = Filters +setname_frameloaders = FrameLoaders +setname_contenthandlers = ContentHandlers + +subdir_types = types +subdir_filters = filters +subdir_frameloaders = frameloaders +subdir_contenthandlers = contenthandlers + +#************************************************ +# This delimiter is used to split every +# item list of the package configuration files +# (which are temp. created by the make proccess) +# into its tokens. +# +# [REQUIRED] +#************************************************ +delimiter=, + +#************************************************ +# Enable/disable removing of leading/trailing withespaces +# during splitting stringlists. +# +# [REQUIRED] +#************************************************ +trim=true + +#************************************************ +# Enable/disable removing of leading/trailing "-signs +# during splitting stringlists. +# +# [REQUIRED] +#************************************************ +decode=false diff --git a/l10ntools/source/filter/merge/FCFGMerge.java b/l10ntools/source/filter/merge/FCFGMerge.java new file mode 100644 index 000000000000..2c2f35b66d1b --- /dev/null +++ b/l10ntools/source/filter/merge/FCFGMerge.java @@ -0,0 +1,128 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +package com.sun.star.filter.config.tools.merge; + +//_______________________________________________ + +import java.lang.*; +import java.util.*; +import java.io.*; +import com.sun.star.filter.config.tools.utils.*; + +//_______________________________________________ + +/** + * Its a simple command line tool, which can merge different XML fragments + * together. Such fragments must exist as files on disk, will be moved into + * one file together on disk. + * + * + */ +public class FCFGMerge +{ + //___________________________________________ + // const + + private static final java.lang.String CFGFILE = "com/sun/star/filter/config/tools/merge/FCFGMerge.cfg"; + private static final java.lang.String PROP_LOGLEVEL = "loglevel"; + + //___________________________________________ + // main + + public static void main(java.lang.String[] sCmdLine) + { + FCFGMerge.printCopyright(); + + // create log object in default mode "WARNINGS" + // If a command line parameter indicates another + // level - change it! + Logger aLog = new Logger(); + + try + { + // merge config file and overwrite properties + // via command line + ConfigHelper aCfg = null; + aCfg = new ConfigHelper(CFGFILE, sCmdLine); + + // update log level + int nLogLevel = aCfg.getInt(PROP_LOGLEVEL, Logger.LEVEL_WARNINGS); + aLog = new Logger(nLogLevel); + + // help requested? + if (aCfg.isHelp()) + { + FCFGMerge.printHelp(); + System.exit(-1); + } + + // create new merge object and start operation + Merger aMerger = new Merger(aCfg, aLog); + aMerger.merge(); + } + catch(java.lang.Throwable ex) + { + aLog.setException(ex); + System.exit(-1); + } + + System.exit(0); + } + + //___________________________________________ + + /** prints out a copyright message on stdout. + */ + private static void printCopyright() + { + java.lang.StringBuffer sOut = new java.lang.StringBuffer(256); + sOut.append("FCFGMerge\n"); + sOut.append("Copyright: 2003 by Sun Microsystems, Inc.\n"); + sOut.append("All Rights Reserved.\n"); + System.out.println(sOut.toString()); + } + + //___________________________________________ + + /** prints out a help message on stdout. + */ + private static void printHelp() + { + java.lang.StringBuffer sOut = new java.lang.StringBuffer(256); + sOut.append("____________________________________________________________\n"); + sOut.append("usage: FCFGMerge cfg=<file name>\n" ); + sOut.append("parameters:\n" ); + sOut.append("\tcfg=<file name>\n" ); + sOut.append("\t\tmust point to a system file, which contains\n" ); + sOut.append("\t\tall neccessary configuration data for the merge process.\n"); + sOut.append("\n\tFurther cou can specify every parameter allowed in the\n" ); + sOut.append("\n\tconfig file as command line parameter too, to overwrite\n" ); + sOut.append("\n\tthe value from the file.\n" ); + System.out.println(sOut.toString()); + } +} diff --git a/l10ntools/source/filter/merge/Manifest.mf b/l10ntools/source/filter/merge/Manifest.mf new file mode 100644 index 000000000000..1337eaf4d39a --- /dev/null +++ b/l10ntools/source/filter/merge/Manifest.mf @@ -0,0 +1 @@ +Main-Class: com.sun.star.filter.config.tools.merge.FCFGMerge diff --git a/l10ntools/source/filter/merge/Merger.java b/l10ntools/source/filter/merge/Merger.java new file mode 100644 index 000000000000..3125732733f8 --- /dev/null +++ b/l10ntools/source/filter/merge/Merger.java @@ -0,0 +1,361 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +package com.sun.star.filter.config.tools.merge; + +//_______________________________________________ + +import java.lang.*; +import java.util.*; +import java.io.*; +import com.sun.star.filter.config.tools.utils.*; + +//_______________________________________________ + +/** can merge different xml fragments together. + * + * + */ +public class Merger +{ + //___________________________________________ + // const + + private static final java.lang.String PROP_XMLVERSION = "xmlversion" ; // <= global cfg file + private static final java.lang.String PROP_XMLENCODING = "xmlencoding" ; // <= global cfg file + private static final java.lang.String PROP_XMLPATH = "xmlpath" ; // <= global cfg file + private static final java.lang.String PROP_XMLPACKAGE = "xmlpackage" ; // <= global cfg file + + private static final java.lang.String PROP_SETNAME_TYPES = "setname_types" ; // <= global cfg file + private static final java.lang.String PROP_SETNAME_FILTERS = "setname_filters" ; // <= global cfg file + private static final java.lang.String PROP_SETNAME_LOADERS = "setname_frameloaders" ; // <= global cfg file + private static final java.lang.String PROP_SETNAME_HANDLERS = "setname_contenthandlers" ; // <= global cfg file + + private static final java.lang.String PROP_SUBDIR_TYPES = "subdir_types" ; // <= global cfg file + private static final java.lang.String PROP_SUBDIR_FILTERS = "subdir_filters" ; // <= global cfg file + private static final java.lang.String PROP_SUBDIR_LOADERS = "subdir_frameloaders" ; // <= global cfg file + private static final java.lang.String PROP_SUBDIR_HANDLERS = "subdir_contenthandlers" ; // <= global cfg file + + private static final java.lang.String PROP_EXTENSION_XCU = "extension_xcu" ; // <= global cfg file + private static final java.lang.String PROP_EXTENSION_PKG = "extension_pkg" ; // <= global cfg file + + private static final java.lang.String PROP_DELIMITER = "delimiter" ; // <= global cfg file + private static final java.lang.String PROP_TRIM = "trim" ; // <= global cfg file + private static final java.lang.String PROP_DECODE = "decode" ; // <= global cfg file + + private static final java.lang.String PROP_FRAGMENTSDIR = "fragmentsdir" ; // <= cmdline + private static final java.lang.String PROP_TEMPDIR = "tempdir" ; // <= cmdline + private static final java.lang.String PROP_OUTDIR = "outdir" ; // <= cmdline + private static final java.lang.String PROP_PKG = "pkg" ; // <= cmdline + private static final java.lang.String PROP_DEBUG = "debug" ; // <= cmdline + + private static final java.lang.String PROP_TCFG = "tcfg" ; // <= cmdline + private static final java.lang.String PROP_FCFG = "fcfg" ; // <= cmdline + private static final java.lang.String PROP_LCFG = "lcfg" ; // <= cmdline + private static final java.lang.String PROP_CCFG = "ccfg" ; // <= cmdline + private static final java.lang.String PROP_LANGUAGEPACK = "languagepack" ; // <= cmdline + + private static final java.lang.String PROP_ITEMS = "items" ; // <= pkg cfg files! + + //___________________________________________ + // member + + //------------------------------------------- + /** TODO */ + private ConfigHelper m_aCfg; + + //------------------------------------------- + /** TODO */ + private Logger m_aLog; + + //------------------------------------------- + /** TODO */ + private java.io.File m_aFragmentsDir; + + //------------------------------------------- + /** TODO */ + private java.io.File m_aTempDir; + + //------------------------------------------- + /** TODO */ + private java.io.File m_aOutDir; + + //------------------------------------------- + /** TODO */ + private java.util.Vector m_lTypes; + private java.util.Vector m_lFilters; + private java.util.Vector m_lLoaders; + private java.util.Vector m_lHandlers; + + //___________________________________________ + // interface + + //------------------------------------------- + /** initialize a new instance of this class and + * try to get all needed resources from the config module. + * + * @param aCfg + * provides access to all values of the global + * config file and to the command line. + * + * @param aLog + * can be used to print out log informations. + */ + public Merger(ConfigHelper aCfg, + Logger aLog) + throws java.lang.Exception + { + m_aCfg = aCfg; + m_aLog = aLog; + + m_aFragmentsDir = new java.io.File(m_aCfg.getString(PROP_FRAGMENTSDIR)); + m_aTempDir = new java.io.File(m_aCfg.getString(PROP_TEMPDIR )); +// m_aOutDir = new java.io.File(m_aCfg.getString(PROP_OUTDIR )); + + java.lang.String sDelimiter = m_aCfg.getString(PROP_DELIMITER); + boolean bTrim = m_aCfg.getBoolean(PROP_TRIM); + boolean bDecode = m_aCfg.getBoolean(PROP_DECODE); + + try + { + ConfigHelper aFcfg = new ConfigHelper(m_aCfg.getString(PROP_TCFG), null); + m_lTypes = aFcfg.getStringList(PROP_ITEMS, sDelimiter, bTrim, bDecode); + } + catch(java.util.NoSuchElementException ex1) + { + m_lTypes = new java.util.Vector(); + //m_aLog.setWarning("Fragment list of types is missing. Parameter \"items\" seems to be invalid."); + } + + try + { + ConfigHelper aFcfg = new ConfigHelper(m_aCfg.getString(PROP_FCFG), null); + m_lFilters = aFcfg.getStringList(PROP_ITEMS, sDelimiter, bTrim, bDecode); + } + catch(java.util.NoSuchElementException ex1) + { + m_lFilters = new java.util.Vector(); + //m_aLog.setWarning("Fragment list of filters is missing. Parameter \"items\" seems to be invalid."); + } + + try + { + ConfigHelper aFcfg = new ConfigHelper(m_aCfg.getString(PROP_LCFG), null); + m_lLoaders = aFcfg.getStringList(PROP_ITEMS, sDelimiter, bTrim, bDecode); + } + catch(java.util.NoSuchElementException ex1) + { + m_lLoaders = new java.util.Vector(); + //m_aLog.setWarning("Fragment list of frame loader objects is missing. Parameter \"items\" seems to be invalid."); + } + + try + { + ConfigHelper aFcfg = new ConfigHelper(m_aCfg.getString(PROP_CCFG), null); + m_lHandlers = aFcfg.getStringList(PROP_ITEMS, sDelimiter, bTrim, bDecode); + } + catch(java.util.NoSuchElementException ex1) + { + m_lHandlers = new java.util.Vector(); + //m_aLog.setWarning("Fragment list of content handler objects is missing. Parameter \"items\" seems to be invalid."); + } + } + + //------------------------------------------- + /** TODO */ + public synchronized void merge() + throws java.lang.Exception + { + java.lang.StringBuffer sBuffer = new java.lang.StringBuffer(1000000); + java.lang.String sPackage = m_aCfg.getString(PROP_PKG); + + m_aLog.setGlobalInfo("create package \""+sPackage+"\" ..."); + m_aLog.setDetailedInfo("generate package header ... "); + + sBuffer.append( + XMLHelper.generateHeader( + m_aCfg.getString (PROP_XMLVERSION ), + m_aCfg.getString (PROP_XMLENCODING ), + m_aCfg.getString (PROP_XMLPATH ), + m_aCfg.getString (PROP_XMLPACKAGE ), + m_aCfg.getBoolean(PROP_LANGUAGEPACK, false))); + + // counts all transfered fragments + // Can be used later to decide, if a generated package file + // contains "nothing"! + int nItemCount = 0; + + for (int i=0; i<4; ++i) + { + java.lang.String sSetName = null; + java.lang.String sSubDir = null; + java.util.Vector lFragments = null; + + try + { + switch(i) + { + case 0: // types + { + m_aLog.setDetailedInfo("generate set for types ... "); + sSetName = m_aCfg.getString(PROP_SETNAME_TYPES); + sSubDir = m_aCfg.getString(PROP_SUBDIR_TYPES ); + lFragments = m_lTypes; + } + break; + + case 1: // filters + { + m_aLog.setDetailedInfo("generate set for filter ... "); + sSetName = m_aCfg.getString(PROP_SETNAME_FILTERS); + sSubDir = m_aCfg.getString(PROP_SUBDIR_FILTERS ); + lFragments = m_lFilters; + } + break; + + case 2: // loaders + { + m_aLog.setDetailedInfo("generate set for frame loader ... "); + sSetName = m_aCfg.getString(PROP_SETNAME_LOADERS); + sSubDir = m_aCfg.getString(PROP_SUBDIR_LOADERS ); + lFragments = m_lLoaders; + } + break; + + case 3: // handlers + { + m_aLog.setDetailedInfo("generate set for content handler ... "); + sSetName = m_aCfg.getString(PROP_SETNAME_HANDLERS); + sSubDir = m_aCfg.getString(PROP_SUBDIR_HANDLERS ); + lFragments = m_lHandlers; + } + break; + } + + nItemCount += lFragments.size(); + + getFragments( + new java.io.File(m_aFragmentsDir, sSubDir), + sSetName, + lFragments, + 1, + sBuffer); + } + catch(java.util.NoSuchElementException exIgnore) + { continue; } + } + + m_aLog.setDetailedInfo("generate package footer ... "); + sBuffer.append(XMLHelper.generateFooter()); + + // Attention! + // If the package seem to be empty, it make no sense to generate a corresponding + // xml file. We should suppress writing of this file on disk completly ... + if (nItemCount < 1) + { + m_aLog.setWarning("Package is empty and will not result into a xml file on disk!? Please check configuration file."); + return; + } + m_aLog.setGlobalInfo("package contains "+nItemCount+" items"); + + java.io.File aPackage = new File(sPackage); + m_aLog.setGlobalInfo("write temp package \""+aPackage.getPath()); // TODO encoding must be readed from the configuration + FileHelper.writeEncodedBufferToFile(aPackage, "UTF-8", false, sBuffer); // check for success is done inside this method! + } + + //------------------------------------------- + /** TODO */ + private void getFragments(java.io.File aDir , + java.lang.String sSetName , + java.util.Vector lFragments , + int nPrettyTabs, + java.lang.StringBuffer sBuffer ) + throws java.lang.Exception + { + if (lFragments.size()<1) + { + m_aLog.setWarning("List of fragments is empty!? Will be ignored ..."); + return; + } + + java.util.Enumeration pFragments = lFragments.elements(); + java.lang.String sExtXcu = m_aCfg.getString(PROP_EXTENSION_XCU); + + for (int tabs=0; tabs<nPrettyTabs; ++tabs) + sBuffer.append("\t"); + sBuffer.append("<node oor:name=\""+sSetName+"\">\n"); + ++nPrettyTabs; + + // special mode for generating language packs. + // In such case we must live with some missing fragment files. + // Reason behind; Not all filters are realy localized. + // But we dont use a different fragment list. We try to locate + // any fragment file in its language-pack version ... + boolean bHandleLanguagePacks = m_aCfg.getBoolean(PROP_LANGUAGEPACK, false); + boolean bDebug = m_aCfg.getBoolean(PROP_DEBUG , false); + java.lang.String sEncoding = "UTF-8"; + if (bDebug) + sEncoding = "UTF-8Special"; + + while(pFragments.hasMoreElements()) + { + java.lang.String sFragment = (java.lang.String)pFragments.nextElement(); + java.io.File aFragment = new java.io.File(aDir, sFragment+"."+sExtXcu); + + // handle simple files only and check for existence! + if (!aFragment.exists()) + { + if (bHandleLanguagePacks) + { + m_aLog.setWarning("language fragment \""+aFragment.getPath()+"\" does not exist. Will be ignored."); + continue; + } + else + throw new java.io.IOException("fragment \""+aFragment.getPath()+"\" does not exists."); + } + + if (!aFragment.isFile()) + { + m_aLog.setWarning("fragment \""+aFragment.getPath()+"\" seem to be not a valid file."); + continue; + } + + // copy file content of original fragment + // Note: A FileNotFoundException will be thrown automaticly by the + // used reader objects. Let it break this method too. Our calli is interested + // on such errors :-) + m_aLog.setDetailedInfo("merge fragment \""+aFragment.getPath()+"\" ..."); + FileHelper.readEncodedBufferFromFile(aFragment, sEncoding, sBuffer); + + sBuffer.append("\n"); + } + + --nPrettyTabs; + for (int tabs=0; tabs<nPrettyTabs; ++tabs) + sBuffer.append("\t"); + sBuffer.append("</node>\n"); + } +} diff --git a/l10ntools/source/filter/merge/makefile.mk b/l10ntools/source/filter/merge/makefile.mk new file mode 100644 index 000000000000..f8f8fb640249 --- /dev/null +++ b/l10ntools/source/filter/merge/makefile.mk @@ -0,0 +1,92 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/.. +TARGET = FCFGMerge +PRJNAME = l10ntools +PACKAGE = com$/sun$/star$/filter$/config$/tools$/merge + +# --- Settings ----------------------------------------------------- + +.INCLUDE: settings.mk + +#----- compile .java files ----------------------------------------- +#.IF "$(L10N_framework)"=="" + +OWNCOPY = \ + $(MISC)$/$(TARGET)_copied.done + +#JARFILES = \ +# ridl.jar \ +# unoil.jar \ +# jurt.jar \ +# juh.jar \ +# java_uno.jar + +CFGFILES = \ + FCFGMerge.cfg + +JAVACLASSFILES = \ + $(CLASSDIR)$/$(PACKAGE)$/Merger.class \ + $(CLASSDIR)$/$(PACKAGE)$/FCFGMerge.class + +CUSTOMMANIFESTFILE = \ + Manifest.mf + +MAXLINELENGTH = 100000 + +#----- make a jar from compiled files ------------------------------ + +JARCLASSDIRS = \ + com$/sun$/star$/filter$/config$/tools$/utils \ + com$/sun$/star$/filter$/config$/tools$/merge + +JARTARGET = $(TARGET).jar + +JARCOMPRESS = TRUE + +# --- targets ----------------------------------------------------- + +.INCLUDE : target.mk + +.IF "$(SOLAR_JAVA)" != "" || "$(GUI)"=="OS2" +ALLTAR : $(OWNCOPY) + +.IF "$(JARTARGETN)" != "" +$(JARTARGETN) : $(OWNCOPY) +.ENDIF + +$(OWNCOPY) : $(CFGFILES) + -$(MKDIRHIER) $(CLASSDIR)$/$(PACKAGE) + $(COPY) $? $(CLASSDIR)$/$(PACKAGE) && $(TOUCH) $@ + +.ENDIF # "$(SOLAR_JAVA)" != "" + +#.ELSE +#pseudo: + +#.ENDIF diff --git a/l10ntools/source/filter/utils/AnalyzeStartupLog.java b/l10ntools/source/filter/utils/AnalyzeStartupLog.java new file mode 100644 index 000000000000..60444338b67b --- /dev/null +++ b/l10ntools/source/filter/utils/AnalyzeStartupLog.java @@ -0,0 +1,325 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +package com.sun.star.filter.config.tools.utils; + +//_______________________________________________ +// imports +import java.util.*; +import java.lang.*; + +//_______________________________________________ +// implementation +public class AnalyzeStartupLog +{ + private class OperationTime + { + /** name the measured operation. */ + public java.lang.String sOperation; + + /** contains the time value, when this operation was started. */ + public long nStartTime; + + /** contains the time value, when this operation was finished. */ + public long nEndTime; + + /** text inside log file, which identifies the start time value. */ + public java.lang.String sStartMsg; + + /** text inside log file, which identifies the end time value. */ + public java.lang.String sEndMsg; + } + + //_________________________________ + // main + + public static void main(java.lang.String[] lCmdLine) + { + int nExit = 0; + try + { + // analyze command line + ConfigHelper aCmdLine = new ConfigHelper("", lCmdLine); + java.lang.String sLogDir = aCmdLine.getString("logdir" ); + java.lang.String sDataFile = aCmdLine.getString("datafile"); + + if (sLogDir == null || sDataFile == null) + { + System.err.println("AnalyzeStartupLog lodir=<dir> datafile=<file>"); + System.err.println("E.g.: AnalyzeStartupLog lodir=c:\\temp\\logs datafile=c:\\temp\\data.csv"); + System.exit(--nExit); + } + + // get list of all log files + boolean bRecursive = true; + java.util.Vector lLogs = FileHelper.getSystemFilesFromDir(new java.io.File(sLogDir), bRecursive); + if (lLogs == null || lLogs.isEmpty()) + { + System.err.println("log dir is empty"); + System.exit(--nExit); + } + + // analyze it + java.lang.StringBuffer sOut = new java.lang.StringBuffer(1000); + sOut.append("log;t_cfg_start;t_cfg_end;t_fwk_start;t_fwk_end;t_sfx_start;t_sfx_end;t_types_start;t_types_end;t_filters_start;t_filters_end;"); + sOut.append("t_filters_swriter_start;t_filters_swriter_end;t_filters_sweb_start;t_filters_sweb_end;t_filters_sglobal_start;t_filters_sglobal_end;t_filters_scalc_start;t_filters_scalc_end;t_filters_sdraw_start;t_filters_sdraw_end;t_filters_simpress_start;t_filters_simpress_end;t_filters_schart_start;t_filters_schart_end;t_filters_smath_start;t_filters_smath_end;"); + sOut.append("t_others_start;t_others_end;d_cfg;d_fwk;d_sfx;d_types;d_filters;d_others;d_complete\n"); + + java.util.Enumeration aIt = lLogs.elements(); + while (aIt.hasMoreElements()) + { + java.io.File aLog = (java.io.File)aIt.nextElement(); + java.io.FileReader aReader = new java.io.FileReader(aLog); + java.io.BufferedReader aBuffer = new java.io.BufferedReader(aReader); + + long t_cfg_start = 0; + long t_cfg_end = 0; + + long t_fwk_start = 0; + long t_fwk_end = 0; + + long t_sfx_start = 0; + long t_sfx_end = 0; + + long t_types_start = 0; + long t_types_end = 0; + + long t_filters_start = 0; + long t_filters_end = 0; + + long t_filters_swriter_start = 0; + long t_filters_swriter_end = 0; + + long t_filters_sweb_start = 0; + long t_filters_sweb_end = 0; + + long t_filters_sglobal_start = 0; + long t_filters_sglobal_end = 0; + + long t_filters_scalc_start = 0; + long t_filters_scalc_end = 0; + + long t_filters_sdraw_start = 0; + long t_filters_sdraw_end = 0; + + long t_filters_simpress_start = 0; + long t_filters_simpress_end = 0; + + long t_filters_schart_start = 0; + long t_filters_schart_end = 0; + + long t_filters_smath_start = 0; + long t_filters_smath_end = 0; + + long t_others_start = 0; + long t_others_end = 0; + + while (true) + { + java.lang.String sLine = aBuffer.readLine(); + if (sLine == null) + break; + + if (sLine.endsWith("| framework (as96863) ::FilterCache::FilterCache : { creation ConfigItem [file=standard, version=6, mode=3]")) + t_cfg_start = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("| framework (as96863) ::FilterCache::FilterCache : } creation ConfigItem")) + t_cfg_end = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("| framework (as96863) ::FilterCache::FilterCache : { reading TypeDetection.xml")) + t_fwk_start = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("| framework (as96863) ::FilterCache::FilterCache : } reading TypeDetection.xml")) + t_fwk_end = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("{ framework (as96863) ::FilterCFGAccess::impl_loadTypes")) + t_types_start = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("} framework (as96863) ::FilterCFGAccess::impl_loadTypes")) + t_types_end = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("{ framework (as96863) ::FilterCFGAccess::impl_loadFilters")) + t_filters_start = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("} framework (as96863) ::FilterCFGAccess::impl_loadFilters")) + t_filters_end = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("{ reading FilterGroup [swriter]")) + t_filters_swriter_start = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("} reading FilterGroup [swriter]")) + t_filters_swriter_end = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("{ reading FilterGroup [sweb]")) + t_filters_sweb_start = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("} reading FilterGroup [sweb]")) + t_filters_sweb_end = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("{ reading FilterGroup [sglobal]")) + t_filters_sglobal_start = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("} reading FilterGroup [sglobal]")) + t_filters_sglobal_end = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("{ reading FilterGroup [scalc]")) + t_filters_scalc_start = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("} reading FilterGroup [scalc]")) + t_filters_scalc_end = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("{ reading FilterGroup [sdraw]")) + t_filters_sdraw_start = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("} reading FilterGroup [sdraw]")) + t_filters_sdraw_end = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("{ reading FilterGroup [simpress]")) + t_filters_simpress_start = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("} reading FilterGroup [simpress]")) + t_filters_simpress_end = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("{ reading FilterGroup [schart]")) + t_filters_schart_start = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("} reading FilterGroup [schart]")) + t_filters_schart_end = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("{ reading FilterGroup [smath]")) + t_filters_smath_start = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("} reading FilterGroup [smath]")) + t_filters_smath_end = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("{ framework (as96863) ::FilterCFGAccess::impl_loadDetectors")) + t_others_start = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("} framework (as96863) ::FilterCFGAccess::impl_loadContentHandlers")) + t_others_end = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("} framework (as96863) ::FilterCache::FilterCache")) + t_sfx_start = new java.lang.Long(sLine.substring(0, 6)).longValue(); + else + if (sLine.endsWith("} desktop (lo119109) OfficeWrapper::OfficeWrapper")) + t_sfx_end = new java.lang.Long(sLine.substring(0, 6)).longValue(); + } + + sOut.append(aLog.getName() ); + sOut.append(";" ); + sOut.append(t_cfg_start ); + sOut.append(";" ); + sOut.append(t_cfg_end ); + sOut.append(";" ); + sOut.append(t_fwk_start ); + sOut.append(";" ); + sOut.append(t_fwk_end ); + sOut.append(";" ); + sOut.append(t_sfx_start ); + sOut.append(";" ); + sOut.append(t_sfx_end ); + sOut.append(";" ); + sOut.append(t_types_start ); + sOut.append(";" ); + sOut.append(t_types_end ); + sOut.append(";" ); + sOut.append(t_filters_start ); + sOut.append(";" ); + sOut.append(t_filters_end ); + sOut.append(";" ); + + sOut.append(t_filters_swriter_start ); + sOut.append(";" ); + sOut.append(t_filters_swriter_end ); + sOut.append(";" ); + sOut.append(t_filters_sweb_start ); + sOut.append(";" ); + sOut.append(t_filters_sweb_end ); + sOut.append(";" ); + sOut.append(t_filters_sglobal_start ); + sOut.append(";" ); + sOut.append(t_filters_sglobal_end ); + sOut.append(";" ); + sOut.append(t_filters_scalc_start ); + sOut.append(";" ); + sOut.append(t_filters_scalc_end ); + sOut.append(";" ); + sOut.append(t_filters_sdraw_start ); + sOut.append(";" ); + sOut.append(t_filters_sdraw_end ); + sOut.append(";" ); + sOut.append(t_filters_simpress_start ); + sOut.append(";" ); + sOut.append(t_filters_simpress_end ); + sOut.append(";" ); + sOut.append(t_filters_schart_start ); + sOut.append(";" ); + sOut.append(t_filters_schart_end ); + sOut.append(";" ); + sOut.append(t_filters_smath_start ); + sOut.append(";" ); + sOut.append(t_filters_smath_end ); + sOut.append(";" ); + + sOut.append(t_others_start ); + sOut.append(";" ); + sOut.append(t_others_end ); + sOut.append(";" ); + sOut.append(t_cfg_end -t_cfg_start ); + sOut.append(";" ); + sOut.append(t_fwk_end -t_fwk_start ); + sOut.append(";" ); + sOut.append(t_sfx_end -t_sfx_start ); + sOut.append(";" ); + sOut.append(t_types_end -t_types_start ); + sOut.append(";" ); + sOut.append(t_filters_end-t_filters_start); + sOut.append(";" ); + sOut.append(t_others_end -t_others_start ); + sOut.append(";" ); + sOut.append(t_others_end -t_cfg_start ); + sOut.append("\n" ); + + aBuffer.close(); + } + + java.io.FileWriter aCSV = new java.io.FileWriter(sDataFile); + java.lang.String sData = sOut.toString(); + aCSV.write(sData, 0, sData.length()); + aCSV.flush(); + aCSV.close(); + } + catch(java.lang.Throwable exAny) + { + System.err.println(exAny.getMessage()); + exAny.printStackTrace(); + System.exit(--nExit); + } + + System.exit(0); + } +} diff --git a/l10ntools/source/filter/utils/Cache.java b/l10ntools/source/filter/utils/Cache.java new file mode 100644 index 000000000000..02bb1c302d8d --- /dev/null +++ b/l10ntools/source/filter/utils/Cache.java @@ -0,0 +1,2446 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +package com.sun.star.filter.config.tools.utils; + +//_______________________________________________ + +import java.lang.*; +import java.util.*; +import java.io.*; + +//_______________________________________________ + +/** + * It implements a container for all possible entries which are part of the type + * and filter mechanism of an office - means all items of the configuration file + * "TypeDetection". How these entries will be readed or written can be switch + * in different modes. That would make it possible to edit an xml directly or + * to contact a running office instance. + * + * + */ +public class Cache +{ + //___________________________________________ + // public const + + /** identifies a file type item of this cache. */ + public static final int E_TYPE = 0; + + /** identifies a filter item of this cache. */ + public static final int E_FILTER = 1; + + /** identifies a detect service item of this cache. */ + public static final int E_DETECTSERVICE = 2; + + /** identifies a frame loader item of this cache. */ + public static final int E_FRAMELOADER = 3; + + /** identifies a content handler item of this cache. */ + public static final int E_CONTENTHANDLER = 4; + + /** indicates an unsupported xml format => error! */ + public static final int FORMAT_UNSUPPORTED = -1; + + /** identify the configuration format of an office 6.0. + * The own formated data string is used. */ + public static final int FORMAT_60 = 0; + + /** identify the configuration format of an office 6.y. + * Properties are realy xml tags again. */ + public static final int FORMAT_6Y = 1; + + /** identify the configuration format which is used inside + * this tooling project. */ + public static final int FORMAT_INTERNAL = 2; + + /** right value for a command line parameter to define a 6.0 version. */ + public static final java.lang.String CMDVAL_FORMAT_60 = "6.0"; + + /** right value for a command line parameter to define a 6.Y version. */ + public static final java.lang.String CMDVAL_FORMAT_6Y = "6.Y"; + + /** right value for a command line parameter to define an internal xml version! */ + public static final java.lang.String CMDVAL_FORMAT_INTERNAL = "internal"; + + // general + public static final java.lang.String PROPNAME_DATA = "Data"; + public static final java.lang.String PROPNAME_NAME = "Name"; + public static final java.lang.String PROPNAME_UINAME = "UIName"; + public static final java.lang.String PROPNAME_UINAMES = "UINames"; + + // type 6.0 ... + public static final java.lang.String PROPNAME_MEDIATYPE = "MediaType"; + public static final java.lang.String PROPNAME_PREFERRED = "Preferred"; + public static final java.lang.String PROPNAME_CLIPBOARDFORMAT = "ClipboardFormat"; + public static final java.lang.String PROPNAME_DOCUMENTICONID = "DocumentIconID"; + public static final java.lang.String PROPNAME_URLPATTERN = "URLPattern"; + public static final java.lang.String PROPNAME_EXTENSIONS = "Extensions"; + // ... +6.y + public static final java.lang.String PROPNAME_UIORDER = "UIOrder"; + public static final java.lang.String PROPNAME_PREFERREDFILTER = "PreferredFilter"; + public static final java.lang.String PROPNAME_DETECTSERVICE = "DetectService"; + public static final java.lang.String PROPNAME_FRAMELOADER = "FrameLoader"; + public static final java.lang.String PROPNAME_CONTENTHANDLER = "ContentHandler"; + + // filter + public static final java.lang.String PROPNAME_DOCUMENTSERVICE = "DocumentService"; + public static final java.lang.String PROPNAME_FILEFORMATVERSION = "FileFormatVersion"; + public static final java.lang.String PROPNAME_FILTERSERVICE = "FilterService"; + public static final java.lang.String PROPNAME_FLAGS = "Flags"; + public static final java.lang.String PROPNAME_ORDER = "Order"; // -6.y + public static final java.lang.String PROPNAME_TEMPLATENAME = "TemplateName"; + public static final java.lang.String PROPNAME_TYPE = "Type"; + public static final java.lang.String PROPNAME_UICOMPONENT = "UIComponent"; + public static final java.lang.String PROPNAME_USERDATA = "UserData"; + + // frame loader / detect services / content handler + public static final java.lang.String PROPNAME_TYPES = "Types"; + + //___________________________________________ + // private const + + private static final java.lang.String FILTERSERVICE_NATIVEWARPPER = "com.sun.star.filter.NativeFilterWrapper"; + private static final java.lang.String GENERIC_DETECTSERVICE = "com.sun.star.comp.office.FrameLoader"; + + /** its the name of the cfg set, which contains all types. */ + private static final java.lang.String CFGNODE_TYPES = "Types"; + + /** its the name of the cfg set, which contains all filters. */ + private static final java.lang.String CFGNODE_FILTERS = "Filters"; + + /** its the name of the cfg set, which contains all detect services. */ + private static final java.lang.String CFGNODE_DETECTSERVICES = "DetectServices"; + + /** its the name of the cfg set, which contains all frame loaders. */ + private static final java.lang.String CFGNODE_FRAMELOADERS = "FrameLoaders"; + + /** its the name of the cfg set, which contains all content handlers. */ + private static final java.lang.String CFGNODE_CONTENTHANDLERS = "ContentHandlers"; + + // names for filter flags + private static final java.lang.String FLAGNAME_3RDPARTYFILTER = "3RDPARTYFILTER"; + private static final java.lang.String FLAGNAME_ALIEN = "ALIEN"; + private static final java.lang.String FLAGNAME_ASYNCHRON = "ASYNCHRON"; + private static final java.lang.String FLAGNAME_BROWSERPREFERRED = "BROWSERPREFERRED"; + private static final java.lang.String FLAGNAME_CONSULTSERVICE = "CONSULTSERVICE"; + private static final java.lang.String FLAGNAME_DEFAULT = "DEFAULT"; + private static final java.lang.String FLAGNAME_EXPORT = "EXPORT"; + private static final java.lang.String FLAGNAME_IMPORT = "IMPORT"; + private static final java.lang.String FLAGNAME_INTERNAL = "INTERNAL"; + private static final java.lang.String FLAGNAME_NOTINCHOOSER = "NOTINCHOOSER"; + private static final java.lang.String FLAGNAME_NOTINFILEDIALOG = "NOTINFILEDIALOG"; + private static final java.lang.String FLAGNAME_NOTINSTALLED = "NOTINSTALLED"; + private static final java.lang.String FLAGNAME_OWN = "OWN"; + private static final java.lang.String FLAGNAME_PACKED = "PACKED"; + private static final java.lang.String FLAGNAME_PREFERRED = "PREFERRED"; + private static final java.lang.String FLAGNAME_READONLY = "READONLY"; + private static final java.lang.String FLAGNAME_SILENTEXPORT = "SILENTEXPORT"; + private static final java.lang.String FLAGNAME_TEMPLATE = "TEMPLATE"; + private static final java.lang.String FLAGNAME_TEMPLATEPATH = "TEMPLATEPATH"; + private static final java.lang.String FLAGNAME_USESOPTIONS = "USESOPTIONS"; + + private static final java.lang.String FLAGNAME_COMBINED = "COMBINED"; + private static final java.lang.String FLAGNAME_SUPPORTSSELECTION= "SUPPORTSSELECTION"; + + // values for filter flags + private static final int FLAGVAL_3RDPARTYFILTER = 0x00080000; // 524288 + private static final int FLAGVAL_ALIEN = 0x00000040; // 64 + private static final int FLAGVAL_ALL = 0xffffffff; // 4294967295 + private static final int FLAGVAL_ASYNCHRON = 0x00004000; // 16384 + private static final int FLAGVAL_BROWSERPREFERRED = 0x00400000; // 4194304 + private static final int FLAGVAL_CONSULTSERVICE = 0x00040000; // 262144 + private static final int FLAGVAL_DEFAULT = 0x00000100; // 256 + private static final int FLAGVAL_EXPORT = 0x00000002; // 2 + private static final int FLAGVAL_IMPORT = 0x00000001; // 1 + private static final int FLAGVAL_INTERNAL = 0x00000008; // 8 + private static final int FLAGVAL_NOTINCHOOSER = 0x00002000; // 8192 + private static final int FLAGVAL_NOTINFILEDIALOG = 0x00001000; // 4096 + private static final int FLAGVAL_NOTINSTALLED = 0x00020000; // 131072 + private static final int FLAGVAL_OWN = 0x00000020; // 32 + private static final int FLAGVAL_PACKED = 0x00100000; // 1048576 + private static final int FLAGVAL_PREFERRED = 0x10000000; // 268435456 + private static final int FLAGVAL_READONLY = 0x00010000; // 65536 + private static final int FLAGVAL_SILENTEXPORT = 0x00200000; // 2097152 + private static final int FLAGVAL_TEMPLATE = 0x00000004; // 4 + private static final int FLAGVAL_TEMPLATEPATH = 0x00000010; // 16 + private static final int FLAGVAL_USESOPTIONS = 0x00000080; // 128 + + private static final int FLAGVAL_COMBINED = 0x00800000; // ... + private static final int FLAGVAL_SUPPORTSSELECTION = 0x00000400; // 1024 + + //___________________________________________ + // member + + /** list of all located types. + * Format: [string,HashMap] + */ + private java.util.HashMap m_lTypes; + + /** list of all located filters. + * Format: [string,HashMap] + */ + private java.util.HashMap m_lFilters; + + /** list of all located detect services. + * Format: [string,HashMap] + */ + private java.util.HashMap m_lDetectServices; + + /** list of all located frame loader. + * Format: [string,HashMap] + */ + private java.util.HashMap m_lFrameLoaders; + + /** list of all located content handler. + * Format: [string,HashMap] + */ + private java.util.HashMap m_lContentHandlers; + + /** contains all analyzed relations between + * filters and types. The key is an internal + * type name (can be used as reference into the + * list m_lTypes) and the value is a Vector of all + * internal filter names, which are registered for + * this type. + * Format: [string, Vector] + */ + private java.util.HashMap m_lFilterToTypeRegistrations; + + private int m_nDoubleRegisteredFilters; + private int m_nTypesForFilters; + private int m_nTypesForDetectServices; + private int m_nTypesForFrameLoaders; + private int m_nTypesForContentHandlers; + + /** can be used to log different informations. */ + private Logger m_aDebug; + + //___________________________________________ + // interface + + /** standard ctor. + * + * Initialize an empty cache instance. You have to use + * on of the fromXXX() methods to fill it from different + * sources with content. + */ + public Cache(Logger aDebug) + { + reset(); + m_aDebug = aDebug; + } + + //___________________________________________ + + /** free memory and set default values on all members. + */ + public synchronized void reset() + { + m_lTypes = new java.util.HashMap(); + m_lFilters = new java.util.HashMap(); + m_lFrameLoaders = new java.util.HashMap(); + m_lDetectServices = new java.util.HashMap(); + m_lContentHandlers = new java.util.HashMap(); + m_lFilterToTypeRegistrations = new java.util.HashMap(); + m_aDebug = new Logger(); + m_nDoubleRegisteredFilters = 0; + m_nTypesForFilters = 0; + m_nTypesForDetectServices = 0; + m_nTypesForFrameLoaders = 0; + m_nTypesForContentHandlers = 0; + } + + //___________________________________________ + + /** converts a string representation of an xml format + * to its int value, which must be used at some interface + * methods of this cache. + * + * If the given string does not match to any well known format, + * the return value will be FORMAT_UNSUPPORTED. The calli have to + * check that. Otherwhise a called interface method at this cache + * instance will be rejected by an exception! + * + * @param sFormat + * the string representation + * Must be one of our public const values from type CMDVAL_FORMAT_xxx. + * + * @return [int] + * the int representation. + * Will be one of our public const values from type FORMAT_xxx. + */ + public static int mapFormatString2Format(java.lang.String sFormat) + { + int nFormat = FORMAT_UNSUPPORTED; + if (sFormat.equalsIgnoreCase(CMDVAL_FORMAT_60)) + nFormat = FORMAT_60; + else + if (sFormat.equalsIgnoreCase(CMDVAL_FORMAT_6Y)) + nFormat = FORMAT_6Y; + else + if (sFormat.equalsIgnoreCase(CMDVAL_FORMAT_INTERNAL)) + nFormat = FORMAT_INTERNAL; + return nFormat; + } + + //___________________________________________ + + /** return some statistic values. + * + * Such values can be: - count of container items, + * - ... + * + * @return [java.lang.String] + * a formated string, which contains al statistic data. + */ + public synchronized java.lang.String getStatistics() + { + java.lang.StringBuffer sBuffer = new java.lang.StringBuffer(256); + + sBuffer.append("types = "+m_lTypes.size() +"\n"); + sBuffer.append("filters = "+m_lFilters.size() +"\n"); + sBuffer.append("detect services = "+m_lDetectServices.size() +"\n"); + sBuffer.append("frame loaders = "+m_lFrameLoaders.size() +"\n"); + sBuffer.append("content handler = "+m_lContentHandlers.size() +"\n"); + sBuffer.append("double registered filters = "+m_nDoubleRegisteredFilters+"\n"); + sBuffer.append("types used by filters = "+m_nTypesForFilters +"\n"); + sBuffer.append("types used by detect services = "+m_nTypesForDetectServices +"\n"); + sBuffer.append("types used by frame loaders = "+m_nTypesForFrameLoaders +"\n"); + sBuffer.append("types used by content handlers = "+m_nTypesForContentHandlers+"\n"); + + return sBuffer.toString(); + } + + //___________________________________________ + + /** reset this cache and fill it with new values using the given XML file. + * + * @param aXML + * must be a system file of a suitable XML file, which + * include all neccessary type/filter items. + * + * @param nFormat + * identifies the format of the specified xml file, + * which must be interpreted. + */ + public synchronized void fromXML(java.io.File aXML , + int nFormat) + throws java.lang.Exception + { + // clear this cache + reset(); + + // parse it + javax.xml.parsers.DocumentBuilderFactory aFactory = javax.xml.parsers.DocumentBuilderFactory.newInstance(); + /* Attention: + * This call is important. It force right handling of entities during parsing and(!) + * writing. It let all possible signs for entities or it's quoted representations + * untouched. So this class don't change the original signs of the original file. + * Means: + * <ul> + * <li>(') => (')</li> + * <li>(") => (")</li> + * <li>(>) => (>)</li> + * <li>(<) => (<)</li> + * <li>(>) => (>)</li> + * <li>(&) => (&)</li> + * <li>...</li> + * </ul> + */ + + System.out.println("TODO: must be adapted to java 1.3 :-("); + System.exit(-1); +//TODO_JAVA aFactory.setExpandEntityReferences(false); + + javax.xml.parsers.DocumentBuilder aBuilder = aFactory.newDocumentBuilder(); + org.w3c.dom.Document aDOM = aBuilder.parse(aXML); + org.w3c.dom.Element aRoot = aDOM.getDocumentElement(); + + // step over all sets + java.util.Vector lSetNodes = XMLHelper.extractChildNodesByTagName(aRoot, XMLHelper.XMLTAG_NODE); + java.util.Enumeration it1 = lSetNodes.elements(); + while (it1.hasMoreElements()) + { + // try to find out, which set should be read + org.w3c.dom.Node aSetNode = (org.w3c.dom.Node)it1.nextElement(); + java.lang.String sSetName = XMLHelper.extractNodeAttribByName(aSetNode, XMLHelper.XMLATTRIB_OOR_NAME); + if (sSetName == null) + throw new java.io.IOException("unsupported format: could not extract set name on node ...\n"+aSetNode); + + // map some generic interfaces to the right members! + int eType = -1 ; + java.util.HashMap rMap = null; + + if (sSetName.equals(CFGNODE_TYPES)) + { + eType = E_TYPE; + rMap = m_lTypes; + } + else + if (sSetName.equals(CFGNODE_FILTERS)) + { + eType = E_FILTER; + rMap = m_lFilters; + } + else + if (sSetName.equals(CFGNODE_FRAMELOADERS)) + { + eType = E_FRAMELOADER; + rMap = m_lFrameLoaders; + } + else + if (sSetName.equals(CFGNODE_DETECTSERVICES)) + { + eType = E_DETECTSERVICE; + rMap = m_lDetectServices; + } + else + if (sSetName.equals(CFGNODE_CONTENTHANDLERS)) + { + eType = E_CONTENTHANDLER; + rMap = m_lContentHandlers; + } + else + throw new java.io.IOException("unsupported format: unknown set name [\""+sSetName+"\"] detected on node ...\n"+aSetNode); + + // load all set entries + java.util.Vector lChildNodes = XMLHelper.extractChildNodesByTagName(aSetNode, XMLHelper.XMLTAG_NODE); + java.util.Enumeration it2 = lChildNodes.elements(); + while (it2.hasMoreElements()) + { + org.w3c.dom.Node aChildNode = (org.w3c.dom.Node)it2.nextElement(); + java.lang.String sChildName = XMLHelper.extractNodeAttribByName(aChildNode, XMLHelper.XMLATTRIB_OOR_NAME); + if (sChildName == null) + throw new java.io.IOException("unsupported format: could not extract child node name on node ...\n"+aChildNode); + java.util.HashMap aPropSet = null; + + // Note: Our internal format is different from the source format! + java.util.HashMap aTempSet = XMLHelper.convertNodeToPropSet(aChildNode); + switch(eType) + { + case E_TYPE : + { + aPropSet = Cache.convertTypePropsToInternal(aTempSet, nFormat); + m_aDebug.setDetailedInfo("type [\""+sChildName+"\"] converted to internal format"); + } + break; + + case E_FILTER : + { + aPropSet = Cache.convertFilterPropsToInternal(aTempSet, nFormat); + m_aDebug.setDetailedInfo("filter [\""+sChildName+"\"] converted to internal format"); + } + break; + + case E_DETECTSERVICE : + { + aPropSet = Cache.convertDetectServicePropsToInternal(aTempSet, nFormat); + m_aDebug.setDetailedInfo("detect service [\""+sChildName+"\"] converted to internal format"); + } + break; + + case E_FRAMELOADER : + { + aPropSet = Cache.convertFrameLoaderPropsToInternal(aTempSet, nFormat); + m_aDebug.setDetailedInfo("frame loader [\""+sChildName+"\"] converted to internal format"); + } + break; + + case E_CONTENTHANDLER : + { + aPropSet = Cache.convertContentHandlerPropsToInternal(aTempSet, nFormat); + m_aDebug.setDetailedInfo("content handler [\""+sChildName+"\"] converted to internal format"); + } + break; + } + m_aDebug.setDetailedInfo("props = "+aTempSet); + rMap.put(sChildName, aPropSet); + } + } + } + + //___________________________________________ + + /** create some hml views of the current content of this cache. + * + * The given directory is used to create different html files + * there. Every of them show another aspect of this cache. + * E.g.: - all type/filter properties + * - relation ships between types/filters/loaders etc. + * + * @param aDirectory + * points to a system directory, which + * can be used completely(!) to generate + * the results there. + * + * @param nFormat + * specify in which context the cache items should be + * interpreted. + */ + public synchronized void toHTML(java.io.File aDirectory, + int nFormat , + java.lang.String sEncoding ) + throws java.lang.Exception + { + if (nFormat != FORMAT_6Y) + throw new java.lang.Exception("HTML views are supported for the new 6.y format only yet."); + + java.lang.StringBuffer sRelationView = new java.lang.StringBuffer(1000); + sRelationView.append("<html><header><title>Relation View</title></header><body>"); + sRelationView.append("<table border=1>"); + sRelationView.append("<tr><td><b>type</b></td><td><b>detect service</b></td><td><b>preferred filter</b></td><td><b>frame loader</b></td><td><b>content handler</b></td></tr>"); + + java.util.Iterator aIt = m_lTypes.keySet().iterator(); + while (aIt.hasNext()) + { + java.lang.String sType = (java.lang.String)aIt.next(); + java.util.HashMap aType = (java.util.HashMap)m_lTypes.get(sType); + + sRelationView.append("<tr>"); + sRelationView.append("<td>"+sType+"</td>"); + + java.lang.String sVal = (java.lang.String)aType.get(PROPNAME_DETECTSERVICE); + if (sVal == null || sVal.length()<1) + sRelationView.append("<td> - </td>"); + else + sRelationView.append("<td>"+sVal+"</td>"); + + sVal = (java.lang.String)aType.get(PROPNAME_PREFERREDFILTER); + if (sVal == null || sVal.length()<1) + sRelationView.append("<td> - </td>"); + else + sRelationView.append("<td>"+sVal+"</td>"); + + sVal = (java.lang.String)aType.get(PROPNAME_FRAMELOADER); + if (sVal == null || sVal.length()<1) + sRelationView.append("<td> - </td>"); + else + sRelationView.append("<td>"+sVal+"</td>"); + + sVal = (java.lang.String)aType.get(PROPNAME_CONTENTHANDLER); + if (sVal == null || sVal.length()<1) + sRelationView.append("<td> - </td>"); + else + sRelationView.append("<td>"+sVal+"</td>"); + + sRelationView.append("</tr>"); + } + + sRelationView.append("</table>"); + sRelationView.append("</body>"); + + FileHelper.writeEncodedBufferToFile(new java.io.File(aDirectory, "relation_view.html"), sEncoding, false, sRelationView); + + java.util.HashMap lFilters2TypeRegistration = new java.util.HashMap(); + aIt = m_lFilters.keySet().iterator(); + while (aIt.hasNext()) + { + java.lang.String sFilter = (java.lang.String)aIt.next(); + java.util.HashMap aFilter = (java.util.HashMap)m_lFilters.get(sFilter); + java.lang.String sType = (java.lang.String)aFilter.get(PROPNAME_TYPE); + + java.util.Vector lFilters = (java.util.Vector)lFilters2TypeRegistration.get(sType); + if (lFilters == null) + lFilters = new java.util.Vector(); + lFilters.add(sFilter); + lFilters2TypeRegistration.put(sType, lFilters); + } + + java.lang.StringBuffer sType2FiltersView = new java.lang.StringBuffer(1000); + sType2FiltersView.append("<html><header><title>Type2Filters View</title></header><body>"); + sType2FiltersView.append("<table border=1>"); + sType2FiltersView.append("<tr><td><b>type</b></td><td><b>filters</b></td></tr>"); + + aIt = lFilters2TypeRegistration.keySet().iterator(); + while (aIt.hasNext()) + { + java.lang.String sType = (java.lang.String)aIt.next(); + java.util.Vector lFilters = (java.util.Vector)lFilters2TypeRegistration.get(sType); + + sType2FiltersView.append("<tr><td>"+sType+"</td><td>"); + java.util.Enumeration aEn = lFilters.elements(); + while(aEn.hasMoreElements()) + sType2FiltersView.append(aEn.nextElement()+"<br>"); + sType2FiltersView.append("</td></tr>"); + } + + sType2FiltersView.append("</table>"); + sType2FiltersView.append("</body>"); + + FileHelper.writeEncodedBufferToFile(new java.io.File(aDirectory, "type2filters_view.html"), sEncoding, false, sType2FiltersView); + } + + //___________________________________________ + + /** converts all items of this cache to its xml representation + * and write it to the given file. + * + * @param aXML + * the target file for output. + * + * @param nFormat + * the requested xml format. + * see const values FORMAT_xxx too. + * + * @param sEncoding + * specify the file encoding for the generated xml file. + * + * @throws [java.lang.Exception] + * if something fail during convertion. + */ + public synchronized void toXML(java.io.File aXML , + int nFormat , + java.lang.String sEncoding) + throws java.lang.Exception + { + java.lang.StringBuffer sXML = new java.lang.StringBuffer(500000); + + for (int i=0; i<5; ++i) + { + // define right sub container + java.lang.String sSetName = null; + java.util.HashMap rMap = null; + int eType = -1; + + switch(i) + { + case 0 : + { + sSetName = CFGNODE_TYPES; + rMap = m_lTypes; + eType = E_TYPE; + } + break; + + case 1 : + { + sSetName = CFGNODE_FILTERS; + rMap = m_lFilters; + eType = E_FILTER; + } + break; + + case 2 : + { + sSetName = CFGNODE_DETECTSERVICES; + rMap = m_lDetectServices; + eType = E_DETECTSERVICE; + } + break; + + case 3 : + { + sSetName = CFGNODE_FRAMELOADERS; + rMap = m_lFrameLoaders; + eType = E_FRAMELOADER; + } + break; + + case 4 : + { + sSetName = CFGNODE_CONTENTHANDLERS; + rMap = m_lContentHandlers; + eType = E_CONTENTHANDLER; + } + break; + } + + // generate set + sXML.append("<node oor:name=\""+sSetName+"\" oor:op=\"replace\">\n"); + java.util.Iterator it = rMap.keySet().iterator(); + while(it.hasNext()) + { + java.lang.String sItem = (java.lang.String)it.next(); + sXML.append("<node oor:name=\""+sItem+"\" oor:op=\"replace\">\n"); + sXML.append(getItemAsXML(eType, sItem, nFormat)); + sXML.append("</node>\n"); + } + sXML.append("</node>\n"); + } + + java.io.FileOutputStream aStream = new java.io.FileOutputStream(aXML.getAbsolutePath(), false); + java.io.OutputStreamWriter aWriter = new java.io.OutputStreamWriter(aStream, sEncoding); + java.lang.String sOut = sXML.toString(); + aWriter.write(sOut, 0, sOut.length()); + aWriter.flush(); + aWriter.close(); + } + + //___________________________________________ + + /** converts a type property set from internal format + * to an external one. + * + * @param aMap + * points to the item, which should be converted. + * + * @param nFormat + * specify the requested output format. + * + * @return [java.util.HashMap] + * contains the properties in the requested format. + * + * @throws [java.lang.Exception + * if something fail during convertion. + */ + private static java.util.HashMap convertTypePropsToExternal(java.util.HashMap aMap , + int nFormat) + throws java.lang.Exception + { + java.util.HashMap aResultMap = new java.util.HashMap(); + // copy Name property ... if it exists! + if (aMap.containsKey(PROPNAME_NAME)) + aResultMap.put(PROPNAME_NAME, aMap.get(PROPNAME_NAME)); + switch(nFormat) + { + //----------------------------------- + case FORMAT_60 : + { + // copy UIName property unchanged + aResultMap.put(PROPNAME_UINAME, aMap.get(PROPNAME_UINAME)); + + // ignore properties "UIOrder", "PreferredFilter", "DetectService" + // They are not supported for 6.0 types. + + // pack all other properties to one "Data" string value + java.lang.StringBuffer sData = new java.lang.StringBuffer(256); + + sData.append(aMap.get(PROPNAME_PREFERRED)); + sData.append(","); + sData.append(aMap.get(PROPNAME_MEDIATYPE)); + sData.append(","); + sData.append(aMap.get(PROPNAME_CLIPBOARDFORMAT)); + sData.append(","); + + java.util.Vector lList = (java.util.Vector)aMap.get(PROPNAME_URLPATTERN); + int c = lList.size(); + int i = 0; + for (i=0; i<c; ++i) + { + sData.append(lList.elementAt(i)); + if (i<(c-1)) + sData.append(";"); + } + + lList = (java.util.Vector)aMap.get(PROPNAME_EXTENSIONS); + c = lList.size(); + for (i=0; i<c; ++i) + { + sData.append(lList.elementAt(i)); + if (i<(c-1)) + sData.append(";"); + } + + sData.append(","); + sData.append(aMap.get(PROPNAME_DOCUMENTICONID)); + sData.append(","); + + aResultMap.put(PROPNAME_DATA, sData.toString()); + } + break; + + //----------------------------------- + case FORMAT_6Y : + { + // copy all supported properties directly + aResultMap.put(PROPNAME_PREFERRED , aMap.get(PROPNAME_PREFERRED )); + aResultMap.put(PROPNAME_MEDIATYPE , aMap.get(PROPNAME_MEDIATYPE )); + aResultMap.put(PROPNAME_URLPATTERN , aMap.get(PROPNAME_URLPATTERN )); + aResultMap.put(PROPNAME_EXTENSIONS , aMap.get(PROPNAME_EXTENSIONS )); + aResultMap.put(PROPNAME_UINAME , aMap.get(PROPNAME_UINAME )); + aResultMap.put(PROPNAME_PREFERREDFILTER, aMap.get(PROPNAME_PREFERREDFILTER)); + aResultMap.put(PROPNAME_DETECTSERVICE , aMap.get(PROPNAME_DETECTSERVICE )); + aResultMap.put(PROPNAME_CLIPBOARDFORMAT, aMap.get(PROPNAME_CLIPBOARDFORMAT)); + aResultMap.put(PROPNAME_UIORDER , aMap.get(PROPNAME_UIORDER )); + /* REMOVED! + aResultMap.put(PROPNAME_DOCUMENTICONID , aMap.get(PROPNAME_DOCUMENTICONID )); + */ + } + break; + + //----------------------------------- + default : + throw new java.lang.Exception("unknown format"); + } + + return aResultMap; + } + + //___________________________________________ + + /** converts a filter property set from internal format + * to an external one. + * + * @param aMap + * points to the item, which should be converted. + * + * @param nFormat + * specify the requested output format. + * + * @return [java.util.HashMap] + * contains the properties in the requested format. + * + * @throws [java.lang.Exception + * if something fail during convertion. + */ + private static java.util.HashMap convertFilterPropsToExternal(java.util.HashMap aMap , + int nFormat) + throws java.lang.Exception + { + java.util.HashMap aResultMap = new java.util.HashMap(); + // copy Name property ... if it exists! + if (aMap.containsKey(PROPNAME_NAME)) + aResultMap.put(PROPNAME_NAME, aMap.get(PROPNAME_NAME)); + switch(nFormat) + { + //----------------------------------- + case FORMAT_60 : + { + // copy UIName property unchanged! + aResultMap.put(PROPNAME_UINAME, aMap.get(PROPNAME_UINAME)); + + // but pack all other properties + java.lang.StringBuffer sData = new java.lang.StringBuffer(256); + + sData.append(aMap.get(PROPNAME_ORDER)); + sData.append(","); + sData.append(aMap.get(PROPNAME_TYPE)); + sData.append(","); + sData.append(aMap.get(PROPNAME_DOCUMENTSERVICE)); + sData.append(","); + sData.append(aMap.get(PROPNAME_FILTERSERVICE)); + sData.append(","); + sData.append(aMap.get(PROPNAME_FLAGS)); + sData.append(","); + java.util.Vector lList = (java.util.Vector)aMap.get(PROPNAME_USERDATA); + int c = lList.size(); + int i = 0; + for (i=0; i<c; ++i) + { + sData.append(lList.elementAt(i)); + if (i<(c-1)) + sData.append(";"); + } + sData.append(","); + sData.append(aMap.get(PROPNAME_FILEFORMATVERSION)); + sData.append(","); + sData.append(aMap.get(PROPNAME_TEMPLATENAME)); + sData.append(","); + sData.append(aMap.get(PROPNAME_UICOMPONENT)); + sData.append(","); + + aResultMap.put(PROPNAME_DATA, sData.toString()); + } + break; + + //----------------------------------- + case FORMAT_6Y : + { + // supress "Order" property. + // Will be moved to type entries in 6.y version! + + // supress "UIName" property. + // Only type entries will be localized in 6.y version! + /* TODO make it configurable :-) */ + aResultMap.put(PROPNAME_UINAME , aMap.get(PROPNAME_UINAME )); + + // copy all supported properties directly + aResultMap.put(PROPNAME_TYPE , aMap.get(PROPNAME_TYPE )); + aResultMap.put(PROPNAME_DOCUMENTSERVICE , aMap.get(PROPNAME_DOCUMENTSERVICE )); + aResultMap.put(PROPNAME_FILTERSERVICE , aMap.get(PROPNAME_FILTERSERVICE )); + aResultMap.put(PROPNAME_USERDATA , aMap.get(PROPNAME_USERDATA )); + aResultMap.put(PROPNAME_FILEFORMATVERSION, aMap.get(PROPNAME_FILEFORMATVERSION)); + aResultMap.put(PROPNAME_TEMPLATENAME , aMap.get(PROPNAME_TEMPLATENAME )); + aResultMap.put(PROPNAME_UICOMPONENT , aMap.get(PROPNAME_UICOMPONENT )); + + // "Flags" will be converted from internal format [int] to + // the 6.y format [string-list]! + java.lang.Integer nFlags = (java.lang.Integer)aMap.get(PROPNAME_FLAGS); + java.util.Vector lFlags = Cache.convertFilterFlagValues2Names(nFlags); + aResultMap.put(PROPNAME_FLAGS, lFlags); + } + break; + + //----------------------------------- + default : + throw new java.lang.Exception("unknown format"); + } + + return aResultMap; + } + + //___________________________________________ + + /** converts a detect service property set from internal format + * to an external one. + * + * @param aMap + * points to the item, which should be converted. + * + * @param nFormat + * specify the requested output format. + * + * @return [java.util.HashMap] + * contains the properties in the requested format. + * + * @throws [java.lang.Exception + * if something fail during convertion. + */ + private static java.util.HashMap convertDetectServicePropsToExternal(java.util.HashMap aMap , + int nFormat) + throws java.lang.Exception + { + java.util.HashMap aResultMap = null; + + switch(nFormat) + { + //----------------------------------- + case FORMAT_60 : + { + // no changes! + aResultMap = aMap; + } + break; + + //----------------------------------- + case FORMAT_6Y : + { + // remove localized name + aResultMap = aMap; + aResultMap.remove(PROPNAME_UINAME); + } + break; + + //----------------------------------- + default : + throw new java.lang.Exception("unknown format"); + } + + return aResultMap; + } + + private static java.util.HashMap convertFrameLoaderPropsToExternal(java.util.HashMap aMap , + int nFormat) + throws java.lang.Exception + { + java.util.HashMap aResultMap = null; + + switch(nFormat) + { + //----------------------------------- + case FORMAT_60 : + { + // no changes! + aResultMap = aMap; + } + break; + + //----------------------------------- + case FORMAT_6Y : + { + // remove localized name + aResultMap = aMap; + aResultMap.remove(PROPNAME_UINAME); + } + break; + + //----------------------------------- + default : + throw new java.lang.Exception("unknown format"); + } + + return aResultMap; + } + + private static java.util.HashMap convertContentHandlerPropsToExternal(java.util.HashMap aMap , + int nFormat) + throws java.lang.Exception + { + java.util.HashMap aResultMap = null; + + switch(nFormat) + { + //----------------------------------- + case FORMAT_60 : + { + // no changes! + aResultMap = aMap; + } + break; + + //----------------------------------- + case FORMAT_6Y : + { + // remove localized name + aResultMap = aMap; + aResultMap.remove(PROPNAME_UINAME); + } + break; + + //----------------------------------- + default : + throw new java.lang.Exception("unknown format"); + } + + return aResultMap; + } + + //___________________________________________ + + /** converts a type property set (using an external format) to + * our internal cache format. + * + * Especialy the data format string will be expanded + * to its real properties. + * + * Schema: + * aMap["UIName"] => aExpandedMap["UIName"] + * aMap["Data" ] => aExpandedMap["Preferred" ], aExpandedMap["MediaType"] etc. ... + * + * @param aMap + * points to the item, which should be converted. + + * @param nFormat + * specify the external format. + * + * @return [java.util.HashMap] + * The new map in internal format. + */ + private static java.util.HashMap convertTypePropsToInternal(java.util.HashMap aMap , + int nFormat) + throws java.lang.Exception + { + java.util.HashMap aResultMap = new java.util.HashMap(); + // copy Name property ... if it exists! + if (aMap.containsKey(PROPNAME_NAME)) + aResultMap.put(PROPNAME_NAME, aMap.get(PROPNAME_NAME)); + switch(nFormat) + { + //----------------------------------- + case FORMAT_60 : + { + // copy UIName property unchanged! + aResultMap.put(PROPNAME_UINAME, aMap.get(PROPNAME_UINAME)); + + // generate new property "UIOrder" + // Its the moved property "Order" of filters for versions >= 6.y! + aResultMap.put(PROPNAME_UIORDER, new java.lang.Integer(0)); + + // generate new property "PreferredFilter" + // Its a the moved filter flag "Preferred" for versions >= 6.y! + aResultMap.put(PROPNAME_PREFERREDFILTER, new java.lang.String()); + + // generate new property "DetectService" + // Every type know its detector diretcly from now. No search + // will be neccessary any longer. + aResultMap.put(PROPNAME_DETECTSERVICE, new java.lang.String()); + + // analyze the Data property of the original map + // and copy its results (means all expanded properties) + // to the result map. + java.lang.String sDataVal = (java.lang.String)aMap.get(PROPNAME_DATA); + java.util.Vector lTokens = Cache.splitTokenString(sDataVal, ","); + + int t = 0; + java.util.Enumeration it = lTokens.elements(); + while (it.hasMoreElements()) + { + java.lang.String sToken = (java.lang.String)it.nextElement(); + switch(t) + { + case 0 : + aResultMap.put(PROPNAME_PREFERRED, new java.lang.Boolean(sToken)); + break; + case 1 : + aResultMap.put(PROPNAME_MEDIATYPE, sToken); + break; + case 2 : + { + /*HACK ersetze %20 mit " " ...*/ + int ni = sToken.indexOf("%20"); + if (ni!=-1) + { + java.lang.String sPatch = sToken.substring(0,ni) + " " + sToken.substring(ni+3); + sToken = sPatch; + } + aResultMap.put(PROPNAME_CLIPBOARDFORMAT, sToken); + } + break; + case 3 : + aResultMap.put(PROPNAME_URLPATTERN, Cache.splitTokenString(sToken, ";")); + break; + case 4 : + aResultMap.put(PROPNAME_EXTENSIONS, Cache.splitTokenString(sToken, ";")); + break; + case 5 : + aResultMap.put(PROPNAME_DOCUMENTICONID, new java.lang.Integer(sToken)); + break; + default : + throw new java.lang.Exception("unsupported format for data value of a type \""+aMap.get(PROPNAME_NAME)+"\" detected."); + } + ++t; + } + } + break; + + //----------------------------------- + case FORMAT_6Y : + { + // copy all supported properties directly + aResultMap.put(PROPNAME_PREFERRED , aMap.get(PROPNAME_PREFERRED )); + aResultMap.put(PROPNAME_MEDIATYPE , aMap.get(PROPNAME_MEDIATYPE )); + aResultMap.put(PROPNAME_CLIPBOARDFORMAT, aMap.get(PROPNAME_CLIPBOARDFORMAT)); + aResultMap.put(PROPNAME_URLPATTERN , aMap.get(PROPNAME_URLPATTERN )); + aResultMap.put(PROPNAME_EXTENSIONS , aMap.get(PROPNAME_EXTENSIONS )); + aResultMap.put(PROPNAME_DOCUMENTICONID , aMap.get(PROPNAME_DOCUMENTICONID )); + aResultMap.put(PROPNAME_UINAME , aMap.get(PROPNAME_UINAME )); + aResultMap.put(PROPNAME_UIORDER , aMap.get(PROPNAME_UIORDER )); + aResultMap.put(PROPNAME_PREFERREDFILTER, aMap.get(PROPNAME_PREFERREDFILTER)); + aResultMap.put(PROPNAME_DETECTSERVICE , aMap.get(PROPNAME_DETECTSERVICE )); + } + break; + + //----------------------------------- + default : + throw new java.lang.Exception("unknown format"); + } + + return aResultMap; + } + + //___________________________________________ + + /** converts a filter property set (using an external format) to + * our internal cache format. + * + * Especialy the data format string will be expanded + * to its real properties. + * + * Schema: + * aMap["UIName"] => aExpandedMap["UIName"] + * aMap["Data" ] => aExpandedMap["Order" ], aExpandedMap["Flags"] etc. ... + * + * @param aMap + * points to the item, which should be converted. + * + * @param nFormat + * specify the external format. + * + * @return [java.util.HashMap] + * The new map in internal format. + */ + private static java.util.HashMap convertFilterPropsToInternal(java.util.HashMap aMap , + int nFormat) + throws java.lang.Exception + { + java.util.HashMap aResultMap = new java.util.HashMap(); + // copy Name property ... if it exists! + if (aMap.containsKey(PROPNAME_NAME)) + aResultMap.put(PROPNAME_NAME, aMap.get(PROPNAME_NAME)); + switch(nFormat) + { + //----------------------------------- + case FORMAT_60 : + { + // copy UIName property + aResultMap.put(PROPNAME_UINAME, aMap.get(PROPNAME_UINAME)); + + // analyze the Data property of the original map + // and copy its results (means all expanded properties) + // to the result map. + java.lang.String sDataVal = (java.lang.String)aMap.get(PROPNAME_DATA); + java.util.Vector lTokens = Cache.splitTokenString(sDataVal, ","); + + int t = 0; + java.util.Enumeration it = lTokens.elements(); + while (it.hasMoreElements()) + { + java.lang.String sToken = (java.lang.String)it.nextElement(); + switch(t) + { + case 0 : + aResultMap.put(PROPNAME_ORDER, new java.lang.Integer(sToken)); + break; + case 1 : + aResultMap.put(PROPNAME_TYPE, sToken); + break; + case 2 : + aResultMap.put(PROPNAME_DOCUMENTSERVICE, sToken); + break; + case 3 : + aResultMap.put(PROPNAME_FILTERSERVICE, sToken); + break; + case 4 : + aResultMap.put(PROPNAME_FLAGS, new java.lang.Integer(sToken)); + break; + case 5 : + aResultMap.put(PROPNAME_USERDATA, Cache.splitTokenString(sToken, ";")); + break; + case 6 : + aResultMap.put(PROPNAME_FILEFORMATVERSION, new java.lang.Integer(sToken)); + break; + case 7 : + aResultMap.put(PROPNAME_TEMPLATENAME, sToken); + break; + case 8 : + aResultMap.put(PROPNAME_UICOMPONENT, sToken); + break; + default : + throw new java.lang.Exception("unsupported format for data value of a filter detected."); + } + ++t; + } + + // its an optional property :-) + if (!aResultMap.containsKey(PROPNAME_TEMPLATENAME)) + aResultMap.put(PROPNAME_TEMPLATENAME, new java.lang.String("")); + + // its an optional property :-) + if (!aResultMap.containsKey(PROPNAME_UICOMPONENT)) + aResultMap.put(PROPNAME_UICOMPONENT, new java.lang.String("")); + } + break; + + //----------------------------------- + case FORMAT_6Y : + { + // "Order" does not exist for 6.y versions! Use default. + aResultMap.put(PROPNAME_ORDER, new java.lang.Integer(0)); + + // "UIName" property does not exist for 6.y versions! use default. + /* TODO make it configurable :-) */ + aResultMap.put(PROPNAME_UINAME, aMap.get(PROPNAME_UINAME)); + //aResultMap.put(PROPNAME_UINAME, new java.util.HashMap()); + + // "Flags" must be converted from names to its values + java.util.Vector lFlags = (java.util.Vector)aMap.get(PROPNAME_FLAGS); + java.lang.Integer nFlags = Cache.convertFilterFlagNames2Values(lFlags); + aResultMap.put(PROPNAME_FLAGS, nFlags); + + // copy all direct supported properties + aResultMap.put(PROPNAME_TYPE , aMap.get(PROPNAME_TYPE )); + aResultMap.put(PROPNAME_DOCUMENTSERVICE , aMap.get(PROPNAME_DOCUMENTSERVICE )); + aResultMap.put(PROPNAME_FILTERSERVICE , aMap.get(PROPNAME_ORDER )); + aResultMap.put(PROPNAME_USERDATA , aMap.get(PROPNAME_USERDATA )); + aResultMap.put(PROPNAME_FILEFORMATVERSION, aMap.get(PROPNAME_FILEFORMATVERSION)); + aResultMap.put(PROPNAME_TEMPLATENAME , aMap.get(PROPNAME_TEMPLATENAME )); + aResultMap.put(PROPNAME_UICOMPONENT , aMap.get(PROPNAME_UICOMPONENT )); + } + break; + + //----------------------------------- + default : + throw new java.lang.Exception("unknown format"); + } + + return aResultMap; + } + + private static java.util.HashMap convertDetectServicePropsToInternal(java.util.HashMap aMap , + int nFormat) + throws java.lang.Exception + { + /*FIXME*/ + java.util.HashMap aResultMap = aMap; + return aResultMap; + } + + private static java.util.HashMap convertFrameLoaderPropsToInternal(java.util.HashMap aMap , + int nFormat) + throws java.lang.Exception + { + /*FIXME*/ + java.util.HashMap aResultMap = aMap; + return aResultMap; + } + + private static java.util.HashMap convertContentHandlerPropsToInternal(java.util.HashMap aMap , + int nFormat) + throws java.lang.Exception + { + /*FIXME*/ + java.util.HashMap aResultMap = aMap; + return aResultMap; + } + + //___________________________________________ + + /** converts filter flag names to its int representation. + * + * @param lFlags + * a list of flag names. + * + * @return [java.lang.Integer] + * an integer field of all set flags. + * + * @throws [java.lang.Exception] + * for unsupported flags or empty flag fields! + */ + private static java.lang.Integer convertFilterFlagNames2Values(java.util.Vector lFlags) + throws java.lang.Exception + { + int nFlags = 0; + java.util.Enumeration it = lFlags.elements(); + while(it.hasMoreElements()) + { + java.lang.String sFlagName = (java.lang.String)it.nextElement(); + + if (sFlagName.equals(FLAGNAME_3RDPARTYFILTER)) + nFlags |= FLAGVAL_3RDPARTYFILTER; + else + if (sFlagName.equals(FLAGNAME_ALIEN)) + nFlags |= FLAGVAL_ALIEN; + else + if (sFlagName.equals(FLAGNAME_ASYNCHRON)) + nFlags |= FLAGVAL_ASYNCHRON; + else + if (sFlagName.equals(FLAGNAME_BROWSERPREFERRED)) + nFlags |= FLAGVAL_BROWSERPREFERRED; + else + if (sFlagName.equals(FLAGNAME_CONSULTSERVICE)) + nFlags |= FLAGVAL_CONSULTSERVICE; + else + if (sFlagName.equals(FLAGNAME_DEFAULT)) + nFlags |= FLAGVAL_DEFAULT; + else + if (sFlagName.equals(FLAGNAME_EXPORT)) + nFlags |= FLAGVAL_EXPORT; + else + if (sFlagName.equals(FLAGNAME_IMPORT)) + nFlags |= FLAGVAL_IMPORT; + else + if (sFlagName.equals(FLAGNAME_INTERNAL)) + nFlags |= FLAGVAL_INTERNAL; + else + if (sFlagName.equals(FLAGNAME_NOTINCHOOSER)) + nFlags |= FLAGVAL_NOTINCHOOSER; + else + if (sFlagName.equals(FLAGNAME_NOTINFILEDIALOG)) + nFlags |= FLAGVAL_NOTINFILEDIALOG; + else + if (sFlagName.equals(FLAGNAME_NOTINSTALLED)) + nFlags |= FLAGVAL_NOTINSTALLED; + else + if (sFlagName.equals(FLAGNAME_OWN)) + nFlags |= FLAGVAL_OWN; + else + if (sFlagName.equals(FLAGNAME_PACKED)) + nFlags |= FLAGVAL_PACKED; + else + if (sFlagName.equals(FLAGNAME_PREFERRED)) + nFlags |= FLAGVAL_PREFERRED; + else + if (sFlagName.equals(FLAGNAME_READONLY)) + nFlags |= FLAGVAL_READONLY; + else + if (sFlagName.equals(FLAGNAME_SILENTEXPORT)) + nFlags |= FLAGVAL_SILENTEXPORT; + else + if (sFlagName.equals(FLAGNAME_TEMPLATE)) + nFlags |= FLAGVAL_TEMPLATE; + else + if (sFlagName.equals(FLAGNAME_TEMPLATEPATH)) + nFlags |= FLAGVAL_TEMPLATEPATH; + else + if (sFlagName.equals(FLAGNAME_USESOPTIONS)) + nFlags |= FLAGVAL_USESOPTIONS; + else + if (sFlagName.equals(FLAGNAME_COMBINED)) + nFlags |= FLAGVAL_COMBINED; + else + throw new java.lang.Exception("unsupported filter flag detected: \""+sFlagName+"\""); + } + + if (nFlags == 0) + throw new java.lang.Exception("no filter flags?"); + + return new java.lang.Integer(nFlags); + } + + //___________________________________________ + + /** converts filter flag values to its string representation. + * + * @param nFlags + * the flag field as int value. + * + * @return [java.util.Vector] + * a list of flag names. + * + * @throws [java.lang.Exception] + * for unsupported flags or empty flag fields! + */ + private static java.util.Vector convertFilterFlagValues2Names(java.lang.Integer nFlags) + throws java.lang.Exception + { + java.util.Vector lFlags = new java.util.Vector(); + int field = nFlags.intValue(); + + if (field == 0) + throw new java.lang.Exception("no filter flags?"); + + if((field & FLAGVAL_IMPORT) == FLAGVAL_IMPORT) + lFlags.add(FLAGNAME_IMPORT); + + if((field & FLAGVAL_EXPORT) == FLAGVAL_EXPORT) + lFlags.add(FLAGNAME_EXPORT); + + if((field & FLAGVAL_TEMPLATE) == FLAGVAL_TEMPLATE) + lFlags.add(FLAGNAME_TEMPLATE); + + if((field & FLAGVAL_INTERNAL) == FLAGVAL_INTERNAL) + lFlags.add(FLAGNAME_INTERNAL); + + if((field & FLAGVAL_TEMPLATEPATH) == FLAGVAL_TEMPLATEPATH) + lFlags.add(FLAGNAME_TEMPLATEPATH); + + if((field & FLAGVAL_OWN) == FLAGVAL_OWN) + lFlags.add(FLAGNAME_OWN); + + if((field & FLAGVAL_ALIEN) == FLAGVAL_ALIEN) + lFlags.add(FLAGNAME_ALIEN); + + if((field & FLAGVAL_USESOPTIONS) == FLAGVAL_USESOPTIONS) + lFlags.add(FLAGNAME_USESOPTIONS); + + if((field & FLAGVAL_DEFAULT) == FLAGVAL_DEFAULT) + lFlags.add(FLAGNAME_DEFAULT); + + if((field & FLAGVAL_NOTINFILEDIALOG) == FLAGVAL_NOTINFILEDIALOG) + lFlags.add(FLAGNAME_NOTINFILEDIALOG); + + if((field & FLAGVAL_NOTINCHOOSER) == FLAGVAL_NOTINCHOOSER) + lFlags.add(FLAGNAME_NOTINCHOOSER); + + if((field & FLAGVAL_ASYNCHRON) == FLAGVAL_ASYNCHRON) + lFlags.add(FLAGNAME_ASYNCHRON); + + if((field & FLAGVAL_READONLY) == FLAGVAL_READONLY) + lFlags.add(FLAGNAME_READONLY); + + if((field & FLAGVAL_NOTINSTALLED) == FLAGVAL_NOTINSTALLED) + lFlags.add(FLAGNAME_NOTINSTALLED); + + if((field & FLAGVAL_CONSULTSERVICE) == FLAGVAL_CONSULTSERVICE) + lFlags.add(FLAGNAME_CONSULTSERVICE); + + if((field & FLAGVAL_3RDPARTYFILTER) == FLAGVAL_3RDPARTYFILTER) + lFlags.add(FLAGNAME_3RDPARTYFILTER); + + if((field & FLAGVAL_PACKED) == FLAGVAL_PACKED) + lFlags.add(FLAGNAME_PACKED); + + if((field & FLAGVAL_SILENTEXPORT) == FLAGVAL_SILENTEXPORT) + lFlags.add(FLAGNAME_SILENTEXPORT); + + if((field & FLAGVAL_BROWSERPREFERRED) == FLAGVAL_BROWSERPREFERRED) + lFlags.add(FLAGNAME_BROWSERPREFERRED); + + if((field & FLAGVAL_PREFERRED) == FLAGVAL_PREFERRED) + lFlags.add(FLAGNAME_PREFERRED); + + if((field & FLAGVAL_COMBINED) == FLAGVAL_COMBINED) + lFlags.add(FLAGNAME_COMBINED); + + if((field & FLAGVAL_COMBINED) == FLAGVAL_SUPPORTSSELECTION) + lFlags.add(FLAGNAME_SUPPORTSSELECTION); + + return lFlags; + } + + //___________________________________________ + + /** return a reference to one of our member + * lists for types/filters etc ... + * + * @param eItemType + * specify, which item map is required. + * + * @return [java.util.HashMap] + * a reference(!) to the right member. + * + * @throws [java.lang.Exception] + * if the specified map does not exist. + */ + private java.util.HashMap getItemMap(int eItemType) + throws java.lang.Exception + { + java.util.HashMap rMap = null; + switch(eItemType) + { + case E_TYPE : + rMap = m_lTypes; + break; + + case E_FILTER : + rMap = m_lFilters; + break; + + case E_DETECTSERVICE : + rMap = m_lDetectServices; + break; + + case E_FRAMELOADER : + rMap = m_lFrameLoaders; + break; + + case E_CONTENTHANDLER : + rMap = m_lContentHandlers; + break; + + default: + throw new java.lang.Exception("Invalid item map specified."); + } + return rMap; + } + + //___________________________________________ + + /** return the count of items inside a sub container + * of this cache. + * + * @param eItemType + * specify, which item map is required. + * + * @throws [java.lang.Exception] + * if the specified map does not exist. + */ + public synchronized int getItemCount(int eItemType) + throws java.lang.Exception + { + java.util.HashMap rMap = getItemMap(eItemType); + return rMap.size(); + } + + //___________________________________________ + + /** get a list of all item names of the specified + * sub container. + * + * @param eItemType + * specify, which item map is required. + * + * @throws [java.lang.Exception] + * if the specified map does not exist. + */ + public synchronized java.util.Vector getItemNames(int eItemType) + throws java.lang.Exception + { + java.util.Vector lNames = new java.util.Vector(); + java.util.HashMap rMap = getItemMap(eItemType); + java.util.Iterator it = rMap.keySet().iterator(); + while(it.hasNext()) + lNames.add(it.next()); + return lNames; + } + + //___________________________________________ + + /** get a list of all item names of the specified + * sub coontainer, where items match to given property set. + * + * Note: The given property set must exist at all + * returned items as minimum and every checked property + * value must be equals! Using of reg expressions or + * similar mechanism will not be supported here. + * + * @param eItemType + * specify, which item map is required. + * + * @param aPropSet + * the set of properties, which must + * exist at the returned item as minimum. + * + * @throws [java.lang.Exception] + * if the specified map does not exist. + */ + public synchronized java.util.Vector getMatchedItemNames(int eItemType, + java.util.HashMap aPropSet ) + throws java.lang.Exception + { + java.util.Vector lNames = new java.util.Vector(); + java.util.HashMap rMap = getItemMap(eItemType); + java.util.Iterator it = rMap.keySet().iterator(); + while(it.hasNext()) + { + java.lang.String sItemName = (java.lang.String)it.next(); + java.util.HashMap rItemProps = (java.util.HashMap)rMap.get(sItemName); + + boolean bMatch = Cache.matchPropSet(rItemProps, aPropSet); + if (bMatch) + lNames.add(sItemName); + else + { + java.lang.StringBuffer sBuffer = new java.lang.StringBuffer(1000); + sBuffer.append("entry ["+eItemType+"] \""+sItemName+"\" does not match.\n"); + sBuffer.append("\torg items = {"+rItemProps+"}\n"); + sBuffer.append("\treq items = {"+aPropSet+"}\n"); + + m_aDebug.setDetailedInfo(sBuffer.toString()); + } + } + return lNames; + } + + //___________________________________________ + + /** check if two property sets are equals in its + * shared properties. + * + * Note: Only set properties of the match set will be searched + * inside the original set. And its values must be equals. + * Using of reg expressions or similar mechanism will not + * be supported here. + * + * @param rOrgProps + * the original property set, which should be checked. + * + * @param rMatchProps + * contains the properties, which must be searched + * inside rOrgProps. + * + * @return TRUE if all properties of rMatchProps could be located + * inside rOrgProps. + */ + private static boolean matchPropSet(java.util.HashMap rOrgProps , + java.util.HashMap rMatchProps) + { + java.util.Iterator it = rMatchProps.keySet().iterator(); + while(it.hasNext()) + { + java.lang.String sMatchName = (java.lang.String)it.next(); + java.lang.Object aMatchValue = rMatchProps.get(sMatchName); + + if ( + (!rOrgProps.containsKey(sMatchName) ) || + (!rOrgProps.get(sMatchName).equals(aMatchValue)) + ) + { + return false; + } + } + return true; + } + + //___________________________________________ + + /** return a property set for the queried container item. + * + * @param eItemType + * specify, which item map is required. + * + * @param sItemName + * must be a valid item name of the specified item map. + * + * @return [java.util.HashMap] + * the property set of the queried item. + * Always different from null! + * + * @throws [java.lang.Exception] + * if the specified item does not exists or + * seems to be invalid in general (means null!). + */ + public synchronized java.util.HashMap getItem(int eItemType, + java.lang.String sItemName) + throws java.lang.Exception + { + java.util.HashMap rMap = getItemMap(eItemType); + java.util.HashMap rItem = (java.util.HashMap)rMap.get(sItemName); + if (rItem == null) + throw new java.lang.Exception("Queried item \""+sItemName+"\" does not exist inside this cache."); + return rItem; + } + + //___________________________________________ + + /** return a requested item in XML format. + * + * @param eItemType + * identify the right sub set of this cache + * inside which the requested item should exist. + * e.g. E_TYPE, E_FILTER, ... + * + * @param sItemName + * the name of the request item + * + * @param nXMLFormat + * means the format of the generated xml source. + * + * @return [java.lang.String] + * a xml formated string, which contains all properties + * for this container item. + */ + public synchronized java.lang.String getItemAsXML(int eItemType , + java.lang.String sItemName , + int nXMLFormat) + throws java.lang.Exception + { + // Note: Our internal format must be converted to the target format! + java.util.HashMap rItem = getItem(eItemType, sItemName); + java.util.HashMap rFormatedItem = null; + switch(eItemType) + { + case E_TYPE : + { + rFormatedItem = Cache.convertTypePropsToExternal(rItem, nXMLFormat); + m_aDebug.setGlobalInfo("type to external \""+sItemName+"\""); + } + break; + + case E_FILTER : + { + rFormatedItem = Cache.convertFilterPropsToExternal(rItem, nXMLFormat); + m_aDebug.setGlobalInfo("filter to external \""+sItemName+"\""); + } + break; + + case E_DETECTSERVICE : + { + rFormatedItem = Cache.convertDetectServicePropsToExternal(rItem, nXMLFormat); + m_aDebug.setGlobalInfo("detect service to external \""+sItemName+"\""); + } + break; + + case E_FRAMELOADER : + { + rFormatedItem = Cache.convertFrameLoaderPropsToExternal(rItem, nXMLFormat); + m_aDebug.setGlobalInfo("frame loader to external \""+sItemName+"\""); + } + break; + + case E_CONTENTHANDLER : + { + rFormatedItem = Cache.convertContentHandlerPropsToExternal(rItem, nXMLFormat); + m_aDebug.setGlobalInfo("content handler to external \""+sItemName+"\""); + } + break; + } + + java.lang.StringBuffer sXML = new java.lang.StringBuffer(1000); + int nPrettyTabs = 1; + for (int t=0; t<nPrettyTabs; ++t) + sXML.append("\t"); + sXML.append("<"+XMLHelper.XMLTAG_NODE+" "+XMLHelper.XMLATTRIB_OOR_NAME+"=\""+XMLHelper.encodeHTMLSigns(sItemName)+"\" "+XMLHelper.XMLATTRIB_OOR_OP+"=\""+XMLHelper.XMLATTRIB_OP_REPLACE+"\">\n"); + sXML.append(XMLHelper.convertPropSetToXML(rFormatedItem, nPrettyTabs+1)); + for (int t=0; t<nPrettyTabs; ++t) + sXML.append("\t"); + sXML.append("</"+XMLHelper.XMLTAG_NODE+">\n"); + + return sXML.toString(); + } + + //___________________________________________ + + /** split the given string (using the specified delimiter) + * and return alist of found string tokens. + * + * Note: Against the normal behaviour of the StringTokenizer class + * this method returns empty tokens too. + * E.g: "0,,1" will return "0" - "" - "1" + * + * @param sTokenString + * the string value, which should be analyzed. + * + * @param sDelim + * the delimiter, which will be used to differe between tokens. + * + * @return [java.util.Vector] + * a list of string tokens. Can be empty - but not null! + */ + private static java.util.Vector splitTokenString(java.lang.String sTokenString, + java.lang.String sDelim ) + { + java.util.Vector lTokens = new java.util.Vector(); + java.util.StringTokenizer aTokenizer = new java.util.StringTokenizer(sTokenString, sDelim, true); + boolean bLastWasDelim = false; + + while (aTokenizer.hasMoreTokens()) + { + java.lang.String sToken = aTokenizer.nextToken(); + if (sToken.equals(sDelim)) + { + if (bLastWasDelim) + { + // last token was a delimiter - new one too + // => an empty token must be placed between these + // two delimiters! Add this empty value to the return list. + lTokens.add(""); + } + else + { + // last token was not a delimiter - new one is such delim + // => ignore this delimiter - but save the information, that + // it occurred + bLastWasDelim = true; + } + } + else + { + // new token is no delim + // => Add it to the return list. + lTokens.add(sToken); + // Dont forget to reset this information - so next loop + // will do the right things! + bLastWasDelim = false; + } + } + + return lTokens; + } + + //___________________________________________ + + /** + */ + public synchronized void analyze() + { + m_nDoubleRegisteredFilters = 0; + m_nTypesForFilters = 0; + m_nTypesForDetectServices = 0; + m_nTypesForFrameLoaders = 0; + m_nTypesForContentHandlers = 0; + + // create table of types and all registered filters for such types + // By the way: count all double registrations, where a filter + // uses the same type then another filter. + m_lFilterToTypeRegistrations = new java.util.HashMap(); + java.util.Iterator aIt1 = m_lFilters.keySet().iterator(); + while (aIt1.hasNext()) + { + java.lang.String sFilter = (java.lang.String)aIt1.next(); + java.util.HashMap aFilter = (java.util.HashMap)m_lFilters.get(sFilter); + java.lang.String sType = (java.lang.String)aFilter.get(PROPNAME_TYPE); + + java.util.Vector lFilters = (java.util.Vector)m_lFilterToTypeRegistrations.get(sType); + if (lFilters == null) + lFilters = new java.util.Vector(); + else + ++m_nDoubleRegisteredFilters; + lFilters.add(sFilter); + m_lFilterToTypeRegistrations.put(sType, lFilters); + } + + // count, how many types are used by filters, frame loaders or content handlers + aIt1 = m_lTypes.keySet().iterator(); + while (aIt1.hasNext()) + { + java.lang.String sType = (java.lang.String)aIt1.next(); + + java.util.Iterator aIt2 = m_lFilters.keySet().iterator(); + while (aIt2.hasNext()) + { + java.lang.String sItem = (java.lang.String)aIt2.next(); + java.util.HashMap aItem = (java.util.HashMap)m_lFilters.get(sItem); + java.lang.String sTypeReg = (java.lang.String)aItem.get(PROPNAME_TYPE); + + if (sTypeReg.equals(sType)) + { + ++m_nTypesForFilters; + break; + } + } + + aIt2 = m_lDetectServices.keySet().iterator(); + while (aIt2.hasNext()) + { + java.lang.String sItem = (java.lang.String)aIt2.next(); + java.util.HashMap aItem = (java.util.HashMap)m_lDetectServices.get(sItem); + java.util.Vector lTypeReg = (java.util.Vector)aItem.get(PROPNAME_TYPES); + + if (lTypeReg.contains(sType)) + { + ++m_nTypesForDetectServices; + break; + } + } + + aIt2 = m_lFrameLoaders.keySet().iterator(); + while (aIt2.hasNext()) + { + java.lang.String sItem = (java.lang.String)aIt2.next(); + java.util.HashMap aItem = (java.util.HashMap)m_lFrameLoaders.get(sItem); + java.util.Vector lTypeReg = (java.util.Vector)aItem.get(PROPNAME_TYPES); + + if (lTypeReg.contains(sType)) + { + ++m_nTypesForFrameLoaders; + break; + } + } + + aIt2 = m_lContentHandlers.keySet().iterator(); + while (aIt2.hasNext()) + { + java.lang.String sItem = (java.lang.String)aIt2.next(); + java.util.HashMap aItem = (java.util.HashMap)m_lContentHandlers.get(sItem); + java.util.Vector lTypeReg = (java.util.Vector)aItem.get(PROPNAME_TYPES); + + if (lTypeReg.contains(sType)) + { + ++m_nTypesForContentHandlers; + break; + } + } + } + } + + //___________________________________________ + + /** validate all cache entries. + * + * It checks if all made registrations are valid; + * try to repair some simple problems; + * create missing informations on demand ... + * + * @param nFormat + * specify, which configuration format + * must be checked. + * + * @throws [java.lang.Exception] + * if an unrecoverable problem occure. + */ + public synchronized void validate(int nFormat) + throws java.lang.Exception + { + validateTypes(nFormat); + validateFilters(nFormat); + } + + //___________________________________________ + + /** validate all type entries of this cache. + * + * @param nFormat + * specify, which configuration format + * must be checked. + * + * @throws [java.lang.Exception] + * if an unrecoverable problem occure. + */ + private void validateTypes(int nFormat) + throws java.lang.Exception + { + java.util.Iterator aIt1 = m_lTypes.keySet().iterator(); + while(aIt1.hasNext()) + { + java.lang.String sType = (java.lang.String)aIt1.next(); + java.util.HashMap aType = (java.util.HashMap)m_lTypes.get(sType); + if (aType == null) + throw new java.lang.Exception("type ["+sType+"] dos not exist realy?!"); + + if ( + (!aType.containsKey(PROPNAME_MEDIATYPE )) || + (!aType.containsKey(PROPNAME_PREFERRED )) || + (!aType.containsKey(PROPNAME_CLIPBOARDFORMAT)) || + (!aType.containsKey(PROPNAME_DOCUMENTICONID )) || + (!aType.containsKey(PROPNAME_URLPATTERN )) || + (!aType.containsKey(PROPNAME_EXTENSIONS )) || + (!aType.containsKey(PROPNAME_UINAME )) + ) + { + throw new java.lang.Exception("Type \""+sType+"\" does not contain all neccessary properties for a 6.0/6.Y format."); + } + + if ( + (((java.util.Vector)aType.get(PROPNAME_EXTENSIONS)).isEmpty()) && + (((java.util.Vector)aType.get(PROPNAME_URLPATTERN)).isEmpty()) + ) + { + throw new java.lang.Exception("Type \""+sType+"\" does not contain any extension nor an url pattern."); + } + + if (((java.util.HashMap)aType.get(PROPNAME_UINAME)).isEmpty()) + throw new java.lang.Exception("Type \""+sType+"\" is not localized."); + + if (nFormat == FORMAT_6Y) + { + if ( + (!aType.containsKey(PROPNAME_UIORDER )) || + (!aType.containsKey(PROPNAME_PREFERREDFILTER)) || + (!aType.containsKey(PROPNAME_DETECTSERVICE )) + ) + { + throw new java.lang.Exception("Type \""+sType+"\" does not contain all neccessary properties for a 6.Y format."); + } + + if (((java.lang.Integer)aType.get(PROPNAME_UIORDER)).intValue() < 0) + throw new java.lang.Exception("Type \""+sType+"\" has invalid value for prop UIOrder."); + + if (((java.lang.String)aType.get(PROPNAME_DETECTSERVICE)).length() < 1) + m_aDebug.setWarning("Type \""+sType+"\" has no detect service registered."); + + java.lang.String sPreferredReg = (java.lang.String)aType.get(PROPNAME_PREFERREDFILTER); + if ( + (sPreferredReg == null) || + (sPreferredReg.length() < 1 ) + ) + { + m_aDebug.setWarning("Type \""+sType+"\" has no preferred filter ..."); + /*FIXME + * OK - not every type has a filter registered .. but the + * a frame loader MUST(!) exist! Check it. + */ + } + else + { + if (!m_lFilters.containsKey(sPreferredReg)) + throw new java.lang.Exception("Type \""+sType+"\" has no valid preferred filter registration [\""+sPreferredReg+"\"]."); + } + } + } + } + + //___________________________________________ + + /** validate all filter entries of this cache. + * + * @param nFormat + * specify, which configuration format + * must be checked. + * + * @throws [java.lang.Exception] + * if an unrecoverable problem occure. + */ + public synchronized void validateFilters(int nFormat) + throws java.lang.Exception + { + java.util.Iterator aIt1 = m_lFilters.keySet().iterator(); + while(aIt1.hasNext()) + { + java.lang.String sFilter = (java.lang.String)aIt1.next(); + java.util.HashMap aFilter = (java.util.HashMap)m_lFilters.get(sFilter); + if (aFilter == null) + throw new java.lang.Exception("filter ["+sFilter+"] dos not exist realy?!"); + + if ( + (!aFilter.containsKey(PROPNAME_DOCUMENTSERVICE )) || + (!aFilter.containsKey(PROPNAME_FILEFORMATVERSION)) || + (!aFilter.containsKey(PROPNAME_FILTERSERVICE )) || + (!aFilter.containsKey(PROPNAME_FLAGS )) || + (!aFilter.containsKey(PROPNAME_TEMPLATENAME )) || + (!aFilter.containsKey(PROPNAME_TYPE )) || + (!aFilter.containsKey(PROPNAME_UICOMPONENT )) || + (!aFilter.containsKey(PROPNAME_USERDATA )) + ) + { + throw new java.lang.Exception("Filter \""+sFilter+"\" does not contain all neccessary properties for a 6.0/6.Y format."); + } + + if (((java.lang.Integer)aFilter.get(PROPNAME_FLAGS)).intValue() < 1) + throw new java.lang.Exception("Filter \""+sFilter+"\" does not have a valid flag field."); + + if (!m_lTypes.containsKey(aFilter.get(PROPNAME_TYPE))) + throw new java.lang.Exception("Filter \""+sFilter+"\" is not registered for a well known type."); + + if (nFormat == FORMAT_60) + { + if ( + (!aFilter.containsKey(PROPNAME_ORDER )) || + (!aFilter.containsKey(PROPNAME_UINAME)) + ) + { + throw new java.lang.Exception("Filter \""+sFilter+"\" does not contain all neccessary properties for a 6.0 format."); + } + + if (((java.lang.Integer)aFilter.get(PROPNAME_ORDER)).intValue() < 0) + throw new java.lang.Exception("Filter \""+sFilter+"\" does not have a valid Order value."); + + if (((java.util.HashMap)aFilter.get(PROPNAME_UINAME)).isEmpty()) + throw new java.lang.Exception("Filter \""+sFilter+"\" is not localized."); + } +/*TODO + depends from the configuration item "remove_filter_flag_preferred" ... + + if (nFormat == FORMAT_6Y) + { + int flags = ((java.lang.Integer)aFilter.get(PROPNAME_FLAGS)).intValue(); + if ((flags & FLAGVAL_PREFERRED) == FLAGVAL_PREFERRED) + throw new java.lang.Exception("Filter \""+sFilter+"\" has superflous Preferred flag set. Please remove this flag. ["+flags+"]"); + } +*/ + } + } + + /*TODO + * - remove graphic filters! + * - move detect services to types + */ + + public synchronized void transform60to6Y(boolean bCreateCombineFilterFlag , + boolean bRemoveFilterFlagBrowserPreferred, + boolean bRemoveFilterFlagPreferred , + boolean bRemoveFilterFlag3rdparty , + boolean bRemoveFilterUINames , + boolean bRemoveGraphicFilters , + boolean bSetDefaultDetector ) + throws java.lang.Exception + { + // remove some superflous cache entries ... + // everything related to "load macros" + // Macros should be dispatched instead of loaded! + if (m_lTypes.containsKey("macro")) + { + m_lTypes.remove("macro"); + m_aDebug.setDetailedInfo("superflous type \"macro\" was removed"); + } + if (m_lFrameLoaders.containsKey("com.sun.star.comp.sfx2.SfxMacroLoader")) + { + m_lFrameLoaders.remove("com.sun.star.comp.sfx2.SfxMacroLoader"); + m_aDebug.setDetailedInfo("superflous frame loader \"com.sun.star.comp.sfx2.SfxMacroLoader\" was removed"); + } + + // step over all filters and check her properties and references + java.util.Vector lPreferredFilters = new java.util.Vector(); + java.util.Vector lNoRealFilters = new java.util.Vector(); + java.util.Iterator aIt1 = m_lFilters.keySet().iterator(); + while(aIt1.hasNext()) + { + java.lang.String sFilter = (java.lang.String)aIt1.next(); + java.util.HashMap aFilter = (java.util.HashMap)m_lFilters.get(sFilter); + + // remove the "graphic helper filters" used by draw and impress + // They dont have any valid document service name set and cant be handled + // by our generic FrameLoader! + // They must be moved to her own configuration ... + + if ( + (bRemoveGraphicFilters ) && + (((java.lang.String)aFilter.get(PROPNAME_DOCUMENTSERVICE)).length() < 1) + ) + { + lNoRealFilters.add(sFilter); + continue; + } + + java.lang.String sTypeReg = (java.lang.String)aFilter.get(PROPNAME_TYPE); + java.util.HashMap aType = (java.util.HashMap)m_lTypes.get(sTypeReg); + + // move UINames of filters to types + java.util.HashMap lFilterUINames = (java.util.HashMap)aFilter.get(PROPNAME_UINAME); + java.util.HashMap lTypeUINames = (java.util.HashMap)aType.get(PROPNAME_UINAME); + java.util.HashMap lPatchUINames = new java.util.HashMap(); + + java.util.Iterator pUINames = lTypeUINames.keySet().iterator(); + while(pUINames.hasNext()) + { + java.lang.String sLocale = (java.lang.String)pUINames.next(); + java.lang.String sValue = (java.lang.String)lTypeUINames.get(sLocale); + lPatchUINames.put(sLocale, sValue); + } + + pUINames = lFilterUINames.keySet().iterator(); + while(pUINames.hasNext()) + { + java.lang.String sLocale = (java.lang.String)pUINames.next(); + java.lang.String sValue = (java.lang.String)lFilterUINames.get(sLocale); + lPatchUINames.put(sFilter+":"+sLocale, sValue); + } + aType.put(PROPNAME_UINAME, lPatchUINames); + + // set generic filter service wrapper for our own native filters! + // By the way: The format types of such filters can be detected by our + // generic detector too. + if ( + (bSetDefaultDetector ) && + (((java.lang.String)aFilter.get(PROPNAME_FILTERSERVICE)).length() < 1) + ) + { + /*ME_THINKING aFilter.put(PROPNAME_FILTERSERVICE, FILTERSERVICE_NATIVEWARPPER);*/ + aType.put(PROPNAME_DETECTSERVICE, GENERIC_DETECTSERVICE); + } + + // move the preferred filter information to any type + // Set the filter name to the type for which the filter is registered. + // If this type already have a set PreferredFilter value, check if the current filter + // has the preferred flag set. If not ignore it - otherwhise overwrite the + // current information at the type. But look for multiple preferred filter relations ... + // means: look if more the one filter has set the preferred flag for the same type! + + /* Attention! + * + * Dont remove the preferred flag from any filter! ... not here. + * Otherwhise next loop can't detect ambigous preferred registrations! + * Add filter to a temp. list, which can be used later to remove the preferred + * flag ... + */ + + int flags1 = ((java.lang.Integer)aFilter.get(PROPNAME_FLAGS)).intValue(); + java.lang.String sDocSrv = (java.lang.String)aFilter.get(PROPNAME_DOCUMENTSERVICE); + if (sDocSrv.length()>0)// without a doc service its not a real filter - its a graphic filter! + { + boolean preferred1 = ((flags1 & FLAGVAL_PREFERRED) == FLAGVAL_PREFERRED); + if (preferred1) + lPreferredFilters.add(aFilter); + + java.lang.String sAlreadyRegisteredFilter = (java.lang.String)aType.get(PROPNAME_PREFERREDFILTER); + // no registration => set this filter as "any possible one"! + if (sAlreadyRegisteredFilter.length() < 1) + aType.put(PROPNAME_PREFERREDFILTER, sFilter); + else + { + java.util.HashMap aAlreadyRegisteredFilter = (java.util.HashMap)m_lFilters.get(sAlreadyRegisteredFilter); + int flags2 = ((java.lang.Integer)aAlreadyRegisteredFilter.get(PROPNAME_FLAGS)).intValue(); + boolean preferred2 = ((flags2 & FLAGVAL_PREFERRED) == FLAGVAL_PREFERRED); + + // two preferred filters for the same type! => error + if (preferred1 && preferred2) + { + java.lang.StringBuffer sMsg = new java.lang.StringBuffer(256); + sMsg.append("More the one preferred filter detected for the same type.\n"); + sMsg.append("\ttype = \""+sTypeReg+"\"\n"); + sMsg.append("\tfilter[1] = \""+sAlreadyRegisteredFilter+"\"\n"); + sMsg.append("\tfilter[2] = \""+sFilter+"\"\n"); + throw new java.lang.Exception(sMsg.toString()); + } + else + // overwrite the "any possible" filter with a real preferred one + if (preferred1 && !preferred2) + aType.put(PROPNAME_PREFERREDFILTER, sFilter); + } + } + + // create the new combined filter flag if required + if (bCreateCombineFilterFlag) + { + if ( + ((flags1 & FLAGVAL_IMPORT) == FLAGVAL_IMPORT) && + ((flags1 & FLAGVAL_EXPORT) == FLAGVAL_EXPORT) + ) + { + flags1 |= FLAGVAL_COMBINED; + flags1 &= ~FLAGVAL_IMPORT ; + flags1 &= ~FLAGVAL_EXPORT ; + aFilter.put(PROPNAME_FLAGS, new java.lang.Integer(flags1)); + } + } + + // remove some obsolete filter flags + if (bRemoveFilterFlagBrowserPreferred) + { + flags1 &= ~FLAGVAL_BROWSERPREFERRED; + aFilter.put(PROPNAME_FLAGS, new java.lang.Integer(flags1)); + } + + if (bRemoveFilterFlag3rdparty) + { + flags1 &= ~FLAGVAL_3RDPARTYFILTER; + aFilter.put(PROPNAME_FLAGS, new java.lang.Integer(flags1)); + } + + // if its a filter with an UI order ... + // move this information to the registered type. + // Note: Because more then one filter can be registered for the same type. + // Handle it as an error ... till we find a better transformation! + java.lang.Integer nOrder = (java.lang.Integer)aFilter.get(PROPNAME_ORDER); + java.lang.Integer nUIOrder = (java.lang.Integer)aType.get(PROPNAME_UIORDER); + int order = nOrder.intValue(); + int uiorder = nUIOrder.intValue(); + + if (order > 0) + { + if ( + (uiorder < 1 ) || + (uiorder > order) + ) + { + aType.put(PROPNAME_UIORDER, nOrder); + m_aDebug.setDetailedInfo("moved order value "+nOrder+" from filter \""+sFilter+"\" to type \""+sTypeReg+"\""); + } + else + m_aDebug.setDetailedInfo("ignore order value [order="+nOrder+",uiorder="+nUIOrder+"] for filter \""+sFilter+"\" and type \""+sTypeReg+"\""); + } + } + + // NOW ... remove the preferred flags from every filter, which it has set. + java.util.Enumeration aIt2 = null; + if (bRemoveFilterFlagPreferred) + { + aIt2 = lPreferredFilters.elements(); + while (aIt2.hasMoreElements()) + { + java.util.HashMap aFilter = (java.util.HashMap)aIt2.nextElement(); + int flags = ((java.lang.Integer)aFilter.get(PROPNAME_FLAGS)).intValue(); + flags &= ~FLAGVAL_PREFERRED; + aFilter.put(PROPNAME_FLAGS, new java.lang.Integer(flags)); + } + } + + // NOW ... remove all "no real filters" like the graphich helper filters of + // draw and impress! + aIt2 = lNoRealFilters.elements(); + while (aIt2.hasMoreElements()) + m_lFilters.remove(aIt2.nextElement()); + + // step over all detect services and move this information directly to + // the corresponding types + // Overwrite possibel default registrations with a real existing one! + aIt1 = m_lDetectServices.keySet().iterator(); + while(aIt1.hasNext()) + { + java.lang.String sDetector = (java.lang.String)aIt1.next(); + java.util.HashMap aDetector = (java.util.HashMap)m_lDetectServices.get(sDetector); + java.util.Vector lTypeReg = (java.util.Vector)aDetector.get(PROPNAME_TYPES); + aIt2 = lTypeReg.elements(); + while(aIt2.hasMoreElements()) + { + java.lang.String sTypeReg = (java.lang.String)aIt2.nextElement(); + java.util.HashMap aType = (java.util.HashMap)m_lTypes.get(sTypeReg); + + if (aType == null) + { + m_aDebug.setWarning("Detector \""+sDetector+"\" seem to be registered for unknown type \""+sTypeReg+"\""); + continue; + } + + java.lang.Object aAlreadyRegisteredDetector = aType.get(PROPNAME_DETECTSERVICE); + if (aAlreadyRegisteredDetector != null && ((java.lang.String)aAlreadyRegisteredDetector).length() > 0) + { + java.lang.StringBuffer sMsg = new java.lang.StringBuffer(256); + sMsg.append("type \""+sTypeReg+"\" has ambigous registrations of a detect service\n"); + sMsg.append("\tdetect service[1] = \""+(java.lang.String)aAlreadyRegisteredDetector+"\"\n"); + sMsg.append("\tdetect service[2] = \""+sDetector+"\"\n"); + m_aDebug.setWarning(sMsg.toString()); + } + aType.put(PROPNAME_DETECTSERVICE, sDetector); + m_aDebug.setGlobalInfo("move detector \""+sDetector+"\" to type \""+sTypeReg+"\""); + } + } + + // because all detect service was registered as type properties directly ... + // remove all detect service objects of this cache! + m_lDetectServices.clear(); + + // step over all frame loader and move this information directly to + // the corresponding types + // Overwrite possibel default registrations with a real existing one! + aIt1 = m_lFrameLoaders.keySet().iterator(); + while(aIt1.hasNext()) + { + java.lang.String sLoader = (java.lang.String)aIt1.next(); + java.util.HashMap aLoader = (java.util.HashMap)m_lFrameLoaders.get(sLoader); + java.util.Vector lTypeReg = (java.util.Vector)aLoader.get(PROPNAME_TYPES); + aIt2 = lTypeReg.elements(); + while(aIt2.hasMoreElements()) + { + java.lang.String sTypeReg = (java.lang.String)aIt2.nextElement(); + java.util.HashMap aType = (java.util.HashMap)m_lTypes.get(sTypeReg); + java.lang.String sAlreadyRegisteredLoader = (java.lang.String)aType.get(PROPNAME_FRAMELOADER); + if (sAlreadyRegisteredLoader != null && sAlreadyRegisteredLoader.length() > 0) + { + java.lang.StringBuffer sMsg = new java.lang.StringBuffer(256); + sMsg.append("type \""+sTypeReg+"\" has ambigous registrations of a frame loader\n"); + sMsg.append("\tframe loader[1] = \""+sAlreadyRegisteredLoader+"\"\n"); + sMsg.append("\tframe loader[2] = \""+sLoader+"\"\n"); + m_aDebug.setWarning(sMsg.toString()); + } + aType.put(PROPNAME_FRAMELOADER, sLoader); + System.out.println("move loader \""+sLoader+"\" to type \""+sTypeReg+"\""); + } + } + + m_lFrameLoaders.clear(); + + // step over all content handler and move this information directly to + // the corresponding types + // Overwrite possibel default registrations with a real existing one! + aIt1 = m_lContentHandlers.keySet().iterator(); + while(aIt1.hasNext()) + { + java.lang.String sHandler = (java.lang.String)aIt1.next(); + java.util.HashMap aHandler = (java.util.HashMap)m_lContentHandlers.get(sHandler); + java.util.Vector lTypeReg = (java.util.Vector)aHandler.get(PROPNAME_TYPES); + aIt2 = lTypeReg.elements(); + while(aIt2.hasMoreElements()) + { + java.lang.String sTypeReg = (java.lang.String)aIt2.nextElement(); + java.util.HashMap aType = (java.util.HashMap)m_lTypes.get(sTypeReg); + java.lang.String sAlreadyRegisteredHandler = (java.lang.String)aType.get(PROPNAME_CONTENTHANDLER); + if (sAlreadyRegisteredHandler != null && sAlreadyRegisteredHandler.length() > 0) + { + java.lang.StringBuffer sMsg = new java.lang.StringBuffer(256); + sMsg.append("type \""+sTypeReg+"\" has ambigous registrations of a content handler\n"); + sMsg.append("\tcontent handler[1] = \""+sAlreadyRegisteredHandler+"\"\n"); + sMsg.append("\tcontent handler[2] = \""+sHandler+"\"\n"); + m_aDebug.setWarning(sMsg.toString()); + } + aType.put(PROPNAME_CONTENTHANDLER, sHandler); + System.out.println("move handler \""+sHandler+"\" to type \""+sTypeReg+"\""); + } + } + + m_lContentHandlers.clear(); + +/* + int c = m_lTypes.size(); + java.lang.String[] lT1 = new java.lang.String[c]; + java.lang.String[] lT2 = new java.lang.String[c]; + long nUPS = 0; + + int i = 0; + aIt1 = m_lTypes.keySet().iterator(); + while(aIt1.hasNext()) + { + lT1[i] = (java.lang.String)aIt1.next(); + lT2[i] = lT1[i]; + ++i; + } + + for (int i1=0; i1<c; ++i1) + { + java.lang.String sT1 = lT1[i1]; + java.util.HashMap aT1 = (java.util.HashMap)m_lTypes.get(sT1); + + for (int i2=i1; i2<c; ++i2) + { + java.lang.String sT2 = lT1[i2]; + java.util.HashMap aT2 = (java.util.HashMap)m_lTypes.get(sT2); + + if (!sT1.equals(sT2)) + { + if ( + aT1.get(PROPNAME_MEDIATYPE).equals(aT2.get(PROPNAME_MEDIATYPE)) && + aT1.get(PROPNAME_CLIPBOARDFORMAT).equals(aT2.get(PROPNAME_CLIPBOARDFORMAT)) && + aT1.get(PROPNAME_URLPATTERN).equals(aT2.get(PROPNAME_URLPATTERN)) && + aT1.get(PROPNAME_EXTENSIONS).equals(aT2.get(PROPNAME_EXTENSIONS)) + ) + { + System.err.println("UUPPSS----------------------------------------------------------------------------"); + System.err.println("[1]\""+sT1+"\" equals [2]\""+sT2+"\""); + System.err.println("\tprops 1: "+aT1); + System.err.println("\tprops 2: "+aT2); + System.err.println("----------------------------------------------------------------------------------\n"); + ++nUPS; +// throw new java.lang.Exception("UUPPS :-)"); + } + } + } + } + System.err.println("count of UPS = "+nUPS); +*/ + } +} diff --git a/l10ntools/source/filter/utils/ConfigHelper.java b/l10ntools/source/filter/utils/ConfigHelper.java new file mode 100644 index 000000000000..a357b36fc5d1 --- /dev/null +++ b/l10ntools/source/filter/utils/ConfigHelper.java @@ -0,0 +1,300 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + **********************************************************************_*/ + +package com.sun.star.filter.config.tools.utils; + +//_______________________________________________ +// imports + +import java.lang.*; +import java.util.*; +import java.io.*; + +//_______________________________________________ +// definition + +/** can be used to analyze command line parameters + * and merge it together with might existing config + * files. That provides the possibility to overwrite + * config values via command line parameter. + * + * + */ +public class ConfigHelper extends java.util.Properties +{ + //___________________________________________ + // member + + /** indicates an empty command line. */ + private boolean m_bEmpty = true; + + //___________________________________________ + // ctor + + //------------------------------------------- + /** initialize a new helper with the list of + * command line parameters and bind this new instance + * to a property file on disk. + * + * @param sPropFile + * name of the property file. + * If its set to null or an empty value + * it will be ignored. + * + * @param lCommandLineArgs + * the list of original command line arguments. + * + * @throws [Exception] + * in case the command line contains an unknown + * schema for specifiying parameters or the + * specified property file does not exists + * or seem to be corrupted. + */ + public ConfigHelper(java.lang.String sPropFile , + java.lang.String[] lCommandLineArgs) + throws java.lang.Exception + { + // first load prop file, so its values can be overwritten + // by command line args later + // Do it only, if a valid file name was given. + // But in case this file name is wrong, throw an exception. + // So the outside code can react! + if ( + (sPropFile != null) && + (sPropFile.length() > 0 ) + ) + { + java.lang.ClassLoader aLoader = getClass().getClassLoader(); + java.io.InputStream aStream = aLoader.getResourceAsStream(sPropFile); + if (aStream == null) + aStream = new java.io.FileInputStream(sPropFile); + load(aStream); + } + + int count = 0; + if (lCommandLineArgs != null) + count = lCommandLineArgs.length; + m_bEmpty = (count < 1); + + for (int arg=0; arg<count; ++arg) + { + // is it a named-value argument? + // Note: We ignores double "=" signs! => search from left to right + int len = lCommandLineArgs[arg].length(); + int pos = lCommandLineArgs[arg].indexOf('='); + if (pos != -1) + { + java.lang.String sArg = lCommandLineArgs[arg].substring(0,pos); + java.lang.String sValue = lCommandLineArgs[arg].substring(pos+1); + setProperty(sArg, sValue); + continue; + } + + // is it a boolean argument? + // Note: Because "--" and "-" will be interpreted as the same + // we search from right to left! + pos = lCommandLineArgs[arg].lastIndexOf('-'); + if (pos == -1) + pos = lCommandLineArgs[arg].lastIndexOf('/'); + if (pos != -1) + { + java.lang.String sArg = lCommandLineArgs[arg].substring(pos+1); + setProperty(sArg, java.lang.String.valueOf(true)); + continue; + } + + // There is an unknown format used by this argument ... + throw new MalformedCommandLineException("Invalid command line detected. The argument \""+lCommandLineArgs[arg]+"\" use an unsupported format."); + } + } + + //------------------------------------------- + /** indicates if the given command line includes + * a help request. + * + * @return True if there was an explicit help request. + */ + public synchronized boolean isHelp() + { + return ( + (containsKey("help")) || + (containsKey("?") ) || + (containsKey("h") ) + ); + } + + //------------------------------------------- + /** indicates if the gioven command line was empty. + * + * @return True if there was an empty command line. + */ + public synchronized boolean isEmpty() + { + return m_bEmpty; + } + + //------------------------------------------- + /** returns the value of sProp as boolean value. + * + * @param sProp + * the name of the parameter. + * + * @return The boolean value of the requested property. + * + * @throw [NoSuchElementException] + * if the requested property does not exists. + */ + public synchronized boolean getBoolean(java.lang.String sProp) + throws java.util.NoSuchElementException + { + java.lang.String sValue = getProperty(sProp); + if (sValue == null) + throw new java.util.NoSuchElementException("The requested config value \""+sProp+"\" does not exists!"); + return new java.lang.Boolean(sValue).booleanValue(); + } + + public synchronized boolean getBoolean(java.lang.String sProp , + boolean bDefault) + { + java.lang.String sDefault = java.lang.String.valueOf(bDefault); + java.lang.String sValue = getProperty(sProp, sDefault); + return new java.lang.Boolean(sValue).booleanValue(); + } + + //------------------------------------------- + /** returns the value of sProp as int value. + * + * @param sProp + * the name of the parameter. + * + * @return The int value of the requested property. + * + * @throw [NoSuchElementException] + * if the requested property does not exists. + */ + public synchronized int getInt(java.lang.String sProp) + throws java.util.NoSuchElementException + { + java.lang.String sValue = getProperty(sProp); + if (sValue == null) + throw new java.util.NoSuchElementException("The requested config value \""+sProp+"\" does not exists!"); + return new java.lang.Integer(sValue).intValue(); + } + + public synchronized int getInt(java.lang.String sProp , + int nDefault) + { + java.lang.String sDefault = java.lang.String.valueOf(nDefault); + java.lang.String sValue = getProperty(sProp, sDefault); + return new java.lang.Integer(sValue).intValue(); + } + + //------------------------------------------- + /** returns the value of sProp as string value. + * + * @param sProp + * the name of the parameter. + * + * @return The string value of the requested property. + * + * @throw [NoSuchElementException] + * if the requested property does not exists. + */ + public synchronized java.lang.String getString(java.lang.String sProp) + throws java.util.NoSuchElementException + { + java.lang.String sValue = getProperty(sProp); + if (sValue == null) + throw new java.util.NoSuchElementException("The requested config value \""+sProp+"\" does not exists!"); + return sValue; + } + + //------------------------------------------- + /** returns the value of sProp as string list value! + * + * @descr The delimiter must be well known and + * it must be clear if trailing/leading + * whitespaces must be ignored or not. + * + * @param sProp + * the name of the parameter. + * + * @param sDelim + * the delimiter, which must be used to split + * the config string value into an array. + * + * @param bTrim + * if its set to true, trailing and leading whitespace + * characters will be ommited. + * + * @param bDecode + * if its set to TRUE all liste items will be + * interpreted as "<xxx>" and converted to <xxx>! + * + * @return The string list value of the requested property. + * + * @throw [NoSuchElementException] + * if the requested property does not exists. + */ + public synchronized java.util.Vector getStringList(java.lang.String sProp , + java.lang.String sDelimiter, + boolean bTrim , + boolean bDecode ) + throws java.util.NoSuchElementException + { + java.lang.String sValue = getProperty(sProp); + if (sValue == null) + throw new java.util.NoSuchElementException("The requested config value \""+sProp+"\" does not exists!"); + + java.util.Vector lValue = new java.util.Vector(); + try + { + java.util.StringTokenizer lTokens = new java.util.StringTokenizer(sValue, sDelimiter); + while(lTokens.hasMoreTokens()) + { + java.lang.String sToken = lTokens.nextToken(); + // remove trailing/leading whitespaces + if (bTrim) + sToken = sToken.trim(); + // remove "" + if ( + (bDecode ) && + (sToken.indexOf("\"") == 0 ) && + (sToken.lastIndexOf("\"") == sToken.length()-1) + ) + { + sToken = sToken.substring(1, sToken.length()-1); + } + lValue.add(sToken); + } + } + catch(java.lang.Throwable ex) + { lValue.clear(); } + + return lValue; + } +} diff --git a/l10ntools/source/filter/utils/FileHelper.java b/l10ntools/source/filter/utils/FileHelper.java new file mode 100644 index 000000000000..38019cf628df --- /dev/null +++ b/l10ntools/source/filter/utils/FileHelper.java @@ -0,0 +1,763 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +package com.sun.star.filter.config.tools.utils; + +// __________ Imports __________ + +import java.io.*; +import java.lang.*; +import java.net.*; +import java.util.*; + +// __________ Implementation __________ + +/** + * It collects some static helper functons to handle file system specific problems. + * Sometimes it's neccessary to convert URL from/to system pathes; + * or from string notation to structural versions (e.g. com.sun.star.util.URL). + * And sometimes java had another notation then the office it has. + * Further it provides functionality to work easiear with the java.io.File class of java. + * + * + */ +public class FileHelper +{ + // ____________________ + + /** + * Because the office need URLs for loading/saving documents + * we must convert used system pathes. + * And java use another notation for file URLs ... correct it. + * + * @param aSystemPath + * represent the file in system notation + * + * @return [String] + * a file url which represent the given system path + */ + public static java.lang.String getFileURLFromSystemPath(java.io.File aSystemPath) + { + System.out.println("TODO: must be adapted to java 1.3 :-("); + System.exit(-1); +/*TODO_JAVA + try + { + sFileURL = aSystemPath.toURI().toURL().toString(); + } + catch( MalformedURLException exWrong ) + { + sFileURL = null; + } +*/ + java.lang.String sFileURL = null; + + // problem of java: file URL's are coded with 1 slash instead of 2 or 3 ones! + // => correct this problem first, otherwise office can't use these URL's + if( + (sFileURL != null ) && + (sFileURL.startsWith("file:/") == true ) && + (sFileURL.startsWith("file://") == false) + ) + { + java.lang.StringBuffer sWorkBuffer = new java.lang.StringBuffer(sFileURL); + sWorkBuffer.insert(6,"//"); + sFileURL = sWorkBuffer.toString(); + } + + return sFileURL; + } + + // ____________________ + + /** + * The same as getFileURLFromSystemPath() before but uses string parameter instead + * of a java.io.File type. It exist to supress converting of neccessary parameters in the + * outside code. But of course getFileURLFromSystemPath(File) will be a little bit faster + * then this method ... + * + * @param sSystemPath + * represent the file in system notation + * + * @return [String] + * a file url which represent the given system path + */ + public static java.lang.String getFileURLFromSystemPath(java.lang.String sSystemPath) + { + return getFileURLFromSystemPath(new java.io.File(sSystemPath)); + } + + // ____________________ + + /** + * Does the same as getFileURLFromSystemPath() before ... but uses + * the given protocol string (e.g."http://") insted of "file:///". + * + * @param aSystemPath + * represent the file in system notation + * + * @param aBasePath + * define the base path of the aSystemPath value, + * which must be replaced with the value of "sServerPath". + * + * @param sServerURL + * Will be used to replace sBasePath. + * + * @example + * System Path = "d:\test\file.txt" + * Base Path = "d:\test" + * Server Path = "http://alaska:8000" + * => "http://alaska:8000/file.txt" + * + * @return [String] + * an url which represent the given system path + * and uses the given protocol + */ + public static java.lang.String getURLWithProtocolFromSystemPath(java.io.File aSystemPath, + java.io.File aBasePath , + java.lang.String sServerURL ) + { + System.out.println("TODO: must be adapted to java 1.3 :-("); + System.exit(-1); + + java.lang.String sFileURL = FileHelper.getFileURLFromSystemPath(aSystemPath); + java.lang.String sBaseURL = FileHelper.getFileURLFromSystemPath(aBasePath ); + + // cut last '/'! + if (sBaseURL.lastIndexOf('/')==(sBaseURL.length()-1)) + sBaseURL = sBaseURL.substring(0,sBaseURL.length()-1); + + // cut last '/'! + if (sServerURL.lastIndexOf('/')==(sServerURL.length()-1)) + sServerURL = sServerURL.substring(0,sServerURL.length()-1); + +//TODO_JAVA java.lang.String sURL = sFileURL.replaceFirst(sBaseURL,sServerURL); + java.lang.String sURL = null; + return sURL; + } + + // ____________________ + + /** + * The same as getURLWithProtocolFromSystemPath() before but uses string parameter instead + * of a java.io.File types. It exist to supress converting of neccessary parameters in the + * outside code. But of course getURLWithProtocolFromSystemPath(File,File,String) will be + * a little bit faster then this method ... + * + * @param sSystemPath + * represent the file in system notation + * + * @param sBasePath + * define the base path of the aSystemPath value, + * which must be replaced with the value of "sServerPath". + * + * @param sServerPath + * Will be used to replace sBasePath. + * + * @example + * System Path = "d:\test\file.txt" + * Base Path = "d:\test" + * Server Path = "http://alaska:8000" + * => "http://alaska:8000/file.txt" + * + * @return [String] + * an url which represent the given system path + * and uses the given protocol + */ + public static java.lang.String getURLWithProtocolFromSystemPath(java.lang.String sSystemPath, + java.lang.String sBasePath , + java.lang.String sServerPath) + { + return getURLWithProtocolFromSystemPath(new java.io.File(sSystemPath), new java.io.File(sBasePath), sServerPath); + } + + //_________________________________ + + /** + * Return a list of all available files of a directory. + * We filter sub directories. All other files + * are returned. So they can be used for further purposes. + * One parameter define the start directory, + * another one enable/disable recursive search into sub directories. + * + * @param aRoot + * the start directory, which should be analyzed. + * + * @param bRecursive + * enable/disable search in sub directories. + * + * @return [Vector] + * a filtered list of java java.io.File objects of all available files + * of the start dir (and may of its sub directories). + */ + public static java.util.Vector getSystemFilesFromDir(java.io.File aRoot , + boolean bRecursive) + { + java.io.File[] lAllFiles = aRoot.listFiles(); + if (lAllFiles == null) + return null; + + int c = lAllFiles.length; + java.util.Vector lFilteredFiles = new java.util.Vector(c); + for (int i=0; i<c; ++i) + { + // simple files! + if (lAllFiles[i].isFile()) + lFilteredFiles.add(lAllFiles[i]); + else + // recursion? + if (bRecursive && lAllFiles[i].isDirectory()) + { + java.util.Vector lSubFiles = FileHelper.getSystemFilesFromDir(lAllFiles[i],bRecursive); + if (lSubFiles != null) + { + java.util.Enumeration aSnapshot = lSubFiles.elements(); + while (aSnapshot.hasMoreElements()) + lFilteredFiles.add(aSnapshot.nextElement()); + } + } + } + + return lFilteredFiles; + } + + //_________________________________ + /** it converts the given name (e.g. an internal type name) to + * an usable system file name. + * + * Do so some special characters (e.g. "/") must be replaced with other ones. + * + * @param sName + * the name, which should be analyzed and converted. + * + * @return A valid system file name, which should be similar to the + * given name, but does not contain special characters any longer. + */ + public static java.lang.String convertName2FileName(String sName) + { + int i = 0; + int nLength = sName.length(); + char[] lBuffer = sName.toCharArray(); + + java.lang.StringBuffer sNewName = new java.lang.StringBuffer(nLength); + for (i=0; i<nLength; ++i) + { + char c = lBuffer[i]; + if ( + c>=48 && c<=57 // 0-9 + && + c>=97 && c<=122 // a-z + && + c>=65 && c<=90 // A-Z + ) + { + sNewName.append(c); + } + else + { + sNewName.append("_"); + } + } + + return sNewName.toString(); + } + + //___________________________________________ + + /** it removes all child nodes of a file system directory. + * + * @param aDirectory + * points to the directory, which should be made empty. + * + * @param bFilesOnly + * force deletion of files only. If its set to TRUE, + * no subdirectory will be removed. + * + * @throw [java.io.IOException] + * if some of the child nodes couldn't be removed. + */ + public static void makeDirectoryEmpty(java.io.File aDirectory, + boolean bFilesOnly) + throws java.io.IOException + { + if (!aDirectory.isDirectory()) + throw new java.io.FileNotFoundException("\""+aDirectory.toString()+"\" is not a directory."); + + java.io.File[] lChilds = aDirectory.listFiles(); + for (int f=0; f<lChilds.length; ++f) + { + if (lChilds[f].isDirectory()) + { + FileHelper.makeDirectoryEmpty(lChilds[f], bFilesOnly); + if (!bFilesOnly) + { + if (!lChilds[f].delete()) + throw new java.io.IOException("\""+lChilds[f].toString()+"\" could not be deleted."); + } + } + else + { + if (!lChilds[f].delete()) + throw new java.io.IOException("\""+lChilds[f].toString()+"\" could not be deleted."); + } + } + } + + //___________________________________________ + + /** it try to generate a new file with a unique ID + * inside given directory. + * + * Call this method with a directory and a base name for + * a file. It will be used to generate a new files inside + * the directory. Existing files will be checked and new file + * name will be tested till a non existing file name would be found. + * + * @param aBaseDir + * must be a system path + * e.g.: "c:\temp" + * + * @param sBaseName + * must be a system file name without extensions. + * e.g.: "myfile_" + * + * @param sExtension + * the whished extension. + * e.g.: "dat" + * + * @return A valid file object, if an unique file could be created - + * Null otherwhise. + * e.g.: "c:\temp\myfile_1.dat" + */ + public static java.io.File createUniqueFile(java.io.File aBaseDir , + java.lang.String sBaseName , + java.lang.String sExtension) + { + java.io.File aBaseFile = new java.io.File(aBaseDir, sBaseName); + java.io.File aFile = null; + long nr = 0; + while (aFile == null && nr < java.lang.Long.MAX_VALUE) + { + java.lang.String sFileName = aBaseFile.getPath() + java.lang.String.valueOf(nr) + "." + sExtension; + aFile = new java.io.File(sFileName); + if (aFile.exists()) + aFile=null; + ++nr; + } + return aFile; + } + + //___________________________________________ + + /** reads the complete file, using the right encoding, + * into the given string buffer. + * + * @param aFile + * must point to a system file, which must exist. + * e.g.: "c:\temp\test.txt" + * "/tmp/test.txt" + * + * @param sEncoding + * will be used to encode the string content + * inside the file. + * e.g.: "UTF8" + * + * @param sBuffer + * used to return the file content. + * + * @throw [IOException] + * - if the file couldnt be opened + * - if the file does not use the right encoding + */ + public static void readEncodedBufferFromFile(java.io.File aFile , + java.lang.String sEncoding, + java.lang.StringBuffer sBuffer ) + throws java.io.IOException + { + if (sEncoding.equals("UTF-8Special")) + { + FileHelper.readAndCheckUTF8File(aFile,sBuffer); + return; + } + + java.io.FileInputStream aByteStream = new java.io.FileInputStream(aFile.getAbsolutePath()); + java.io.InputStreamReader aEncodedReader = new java.io.InputStreamReader(aByteStream, sEncoding); + char[] aEncodedBuffer = new char[4096]; + int nReadCount = 0; + + while((nReadCount=aEncodedReader.read(aEncodedBuffer))>0) + sBuffer.append(aEncodedBuffer, 0, nReadCount); + + aEncodedReader.close(); + } + + //___________________________________________ + private static void logEncodingData(java.lang.StringBuffer sLog , + int nUTF8 , + int nByteOrg1 , + int nByteOrg2 , + int nByteOrg3 , + int nByteOrg4 , + int nByte1 , + int nByte2 , + int nByte3 , + int nByte4 , + int nEncodingType) + { + sLog.append("["+nEncodingType+"]\t"); + sLog.append((int)nUTF8+"\t="); + sLog.append("\t"+nByteOrg1+"/"+nByte1); + sLog.append("\t"+nByteOrg2+"/"+nByte2); + sLog.append("\t"+nByteOrg3+"/"+nByte3); + sLog.append("\t"+nByteOrg4+"/"+nByte4); + sLog.append("\n"); + } + + //___________________________________________ + private static char impl_convertBytesToChar(int nByte1, int nByte2, int nByte3, int nByte4) + { + return (char)((nByte1*0x40000)+(nByte2*0x1000)+(nByte3*0x40)+nByte4); + } + + //___________________________________________ + private static int impl_readAndCheckNextByte(byte[] aBuffer , + int nBufPos , + int nBufLength , + int nMinRange , + int nMaxRange ) + throws java.lang.Exception + { + if (nBufPos>=nBufLength) + throw new java.lang.Exception("impl_readAndCheckNextByte()\nEnd of buffer reached."); + + int nByte = aBuffer[nBufPos] & 0xFF; + if ( + (nByte < nMinRange) || + (nByte > nMaxRange) + ) + { + throw new java.lang.Exception("impl_readAndCheckNextByte()\nByte does not fit the specified range."); + } + + return nByte; + } + + //___________________________________________ + public static void readAndCheckUTF8File(java.io.File aFile , + java.lang.StringBuffer sBuffer) + throws java.io.IOException + { + java.io.FileInputStream aByteStream = new java.io.FileInputStream(aFile.getAbsolutePath()); + byte[] aBuffer = new byte[4096]; + int nReadCount = 0; + int nByteOrg_1 = 0; + int nByteOrg_2 = 0; + int nByteOrg_3 = 0; + int nByteOrg_4 = 0; + int nByte_1 = 0; + int nByte_2 = 0; + int nByte_3 = 0; + int nByte_4 = 0; + char nUTF8 = 0; + int i = 0; + int nEncodingType = 0; + java.lang.StringBuffer sLog = new java.lang.StringBuffer(); + + try + { + + while((nReadCount=aByteStream.read(aBuffer))>0) + { + i=0; + while (i<nReadCount) + { + nByteOrg_1 = 0; + nByteOrg_2 = 0; + nByteOrg_3 = 0; + nByteOrg_4 = 0; + nByte_1 = 0; + nByte_2 = 0; + nByte_3 = 0; + nByte_4 = 0; + nUTF8 = 0; + nEncodingType = 0; + + nByteOrg_1 = aBuffer[i++] & 0xFF; + nByte_1 = nByteOrg_1; + /* + Table 3-6. Well-Formed UTF-8 Byte Sequences + + ============================================================================ + Nr. Code Points 1st Byte 2nd Byte 3rd Byte 4th Byte + ============================================================================ + 01 U+ 0..U+ 7F 00..7F + 02 U+ 80..U+ 7FF C2..DF 80..BF + 03 U+ 800..U+ FFF E0 A0..BF 80..BF + 04 U+ 1000..U+ CFFF E1..EC 80..BF 80..BF + 05 U+ D000..U+ D7FF ED 80..9F 80..BF + 06 U+ E000..U+ FFFF EE..EF 80..BF 80..BF + 07 U+ 10000..U+ 3FFFF F0 90..BF 80..BF 80..BF + 08 U+ 40000..U+ FFFFF F1..F3 80..BF 80..BF 80..BF + 09 U+100000..U+10FFFF F4 80..8F 80..BF 80..BF + */ + // ------------------------------------------------------------ + // 01 + // 1 byte: 0xxxxxxx + // ------------------------------------------------------------ + if ( + (nByteOrg_1 >= 0x00) && + (nByteOrg_1 <= 0x7F) + ) + { + nEncodingType = 1; + nUTF8 = (char)nByte_1; + } + // ------------------------------------------------------------ + // 02 + // 1 byte: 110xxxxx + // 2 byte: 101xxxxx + // ------------------------------------------------------------ + else + if ( + (nByteOrg_1 >= 0xC2) && + (nByteOrg_1 <= 0xDF) + ) + { + nEncodingType = 2; + nByteOrg_2 = FileHelper.impl_readAndCheckNextByte(aBuffer, i++, nReadCount, 0x80, 0xBF); + nByte_1 = nByteOrg_1-0xC2; + nByte_2 = nByteOrg_2-0x80; + nUTF8 = FileHelper.impl_convertBytesToChar(0,0,nByte_1, nByte_2); + } + // ------------------------------------------------------------ + // 03 + // 1 byte: 11100000 + // 2 byte: 101xxxxx + // 3 byte: 10xxxxxx + // ------------------------------------------------------------ + else + if (nByteOrg_1 == 0xE0) + { + nEncodingType = 3; + nByteOrg_2 = FileHelper.impl_readAndCheckNextByte(aBuffer, i++, nReadCount, 0xA0, 0xBF); + nByteOrg_3 = FileHelper.impl_readAndCheckNextByte(aBuffer, i++, nReadCount, 0x80, 0xBF); + nByte_2 = nByteOrg_2-0xA0; + nByte_3 = nByteOrg_3-0x80; + nUTF8 = FileHelper.impl_convertBytesToChar(0,0,nByte_2, nByte_3); + } + // ------------------------------------------------------------ + // 04 + // 1 byte: 111xxxxx + // 2 byte: 10xxxxxx + // 3 byte: 10xxxxxx + // ------------------------------------------------------------ + else + if ( + (nByteOrg_1 >= 0xE1) && + (nByteOrg_1 <= 0xEC) + ) + { + nEncodingType = 4; + nByteOrg_2 = FileHelper.impl_readAndCheckNextByte(aBuffer, i++, nReadCount, 0x80, 0xBF); + nByteOrg_3 = FileHelper.impl_readAndCheckNextByte(aBuffer, i++, nReadCount, 0x80, 0xBF); + nByte_1 = nByteOrg_1-0xE1; + nByte_2 = nByteOrg_2-0x80; + nByte_3 = nByteOrg_3-0x80; + nUTF8 = FileHelper.impl_convertBytesToChar(0,nByte_1, nByte_2, nByte_3); + } + // ------------------------------------------------------------ + // 05 + // 1 byte: 11101101 + // 2 byte: 10xxxxxx + // 3 byte: 10xxxxxx + // ------------------------------------------------------------ + else + if (nByteOrg_1 == 0xED) + { + nEncodingType = 5; + nByteOrg_2 = FileHelper.impl_readAndCheckNextByte(aBuffer, i++, nReadCount, 0x80, 0x9F); + nByteOrg_3 = FileHelper.impl_readAndCheckNextByte(aBuffer, i++, nReadCount, 0x80, 0xBF); + nByte_2 = nByteOrg_2-0x80; + nByte_3 = nByteOrg_3-0x80; + nUTF8 = FileHelper.impl_convertBytesToChar(0,0, nByte_2, nByte_3); + } + // ------------------------------------------------------------ + // 06 + // 1 byte: 1110111x + // 2 byte: 10xxxxxx + // 3 byte: 10xxxxxx + // ------------------------------------------------------------ + else + if ( + (nByteOrg_1 >= 0xEE) && + (nByteOrg_1 <= 0xEF) + ) + { + nEncodingType = 6; + nByteOrg_2 = FileHelper.impl_readAndCheckNextByte(aBuffer, i++, nReadCount, 0x80, 0xBF); + nByteOrg_3 = FileHelper.impl_readAndCheckNextByte(aBuffer, i++, nReadCount, 0x80, 0xBF); + nByte_1 = nByteOrg_1-0xEE; + nByte_2 = nByteOrg_2-0x80; + nByte_3 = nByteOrg_3-0x80; + nUTF8 = FileHelper.impl_convertBytesToChar(0,nByte_1, nByte_2, nByte_3); + } + // ------------------------------------------------------------ + // 07 + // 1 byte: 11110000 + // 2 byte: 1001xxxx + // 3 byte: 10xxxxxx + // 4 byte: 10xxxxxx + // ------------------------------------------------------------ + else + if (nByteOrg_1 == 0xF0) + { + nEncodingType = 7; + nByteOrg_2 = FileHelper.impl_readAndCheckNextByte(aBuffer, i++, nReadCount, 0x90, 0xBF); + nByteOrg_3 = FileHelper.impl_readAndCheckNextByte(aBuffer, i++, nReadCount, 0x80, 0xBF); + nByteOrg_4 = FileHelper.impl_readAndCheckNextByte(aBuffer, i++, nReadCount, 0x80, 0xBF); + nByte_2 = nByteOrg_2-0x90; + nByte_3 = nByteOrg_3-0x80; + nByte_4 = nByteOrg_4-0x80; + nUTF8 = FileHelper.impl_convertBytesToChar(0, nByte_2, nByte_3, nByte_4); + } + // ------------------------------------------------------------ + // 08 + // 1 byte: 111100xx + // 2 byte: 10xxxxxx + // 3 byte: 10xxxxxx + // 3 byte: 10xxxxxx + // ------------------------------------------------------------ + else + if ( + (nByteOrg_1 >= 0xF1) && + (nByteOrg_1 <= 0xF3) + ) + { + nEncodingType = 8; + nByteOrg_2 = FileHelper.impl_readAndCheckNextByte(aBuffer, i++, nReadCount, 0x80, 0xBF); + nByteOrg_3 = FileHelper.impl_readAndCheckNextByte(aBuffer, i++, nReadCount, 0x80, 0xBF); + nByteOrg_4 = FileHelper.impl_readAndCheckNextByte(aBuffer, i++, nReadCount, 0x80, 0xBF); + nByte_1 = nByteOrg_1-0xF1; + nByte_2 = nByteOrg_2-0x80; + nByte_3 = nByteOrg_3-0x80; + nByte_4 = nByteOrg_4-0x80; + nUTF8 = FileHelper.impl_convertBytesToChar(nByte_1, nByte_2, nByte_3, nByte_4); + } + // ------------------------------------------------------------ + // 09 + // 1 byte: 11110100 + // 2 byte: 10xxxxxx + // 3 byte: 10xxxxxx + // 4 byte: 10xxxxxx + // ------------------------------------------------------------ + else + if (nByteOrg_1 == 0xF0) + { + nEncodingType = 9; + nByteOrg_2 = FileHelper.impl_readAndCheckNextByte(aBuffer, i++, nReadCount, 0x80, 0xBF); + nByteOrg_3 = FileHelper.impl_readAndCheckNextByte(aBuffer, i++, nReadCount, 0x80, 0xBF); + nByteOrg_4 = FileHelper.impl_readAndCheckNextByte(aBuffer, i++, nReadCount, 0x80, 0xBF); + nByte_2 = nByteOrg_2-0x80; + nByte_3 = nByteOrg_3-0x80; + nByte_4 = nByteOrg_4-0x80; + nUTF8 = FileHelper.impl_convertBytesToChar(0, nByte_2, nByte_3, nByte_4); + } + // wrong encoding ? + else + { + throw new java.lang.Exception("Non well formed UTF-8 encoding."); + } + + sBuffer.append(nUTF8); + // -> DEBUG ! + FileHelper.logEncodingData(sLog, nUTF8, nByteOrg_1, nByteOrg_2, nByteOrg_3, nByteOrg_4, nByte_1, nByte_2, nByte_3, nByte_4, nEncodingType); + // <- DEBUG ! + } + } + + } + catch(java.lang.Throwable ex) + { + // -> DEBUG ! + FileHelper.logEncodingData(sLog, nUTF8, nByteOrg_1, nByteOrg_2, nByteOrg_3, nByteOrg_4, nByte_1, nByte_2, nByte_3, nByte_4, nEncodingType); + + java.io.File aDir = new java.io.File(aFile.getParent()); + java.lang.String sDump = aFile.getName(); + java.io.File aDump = FileHelper.createUniqueFile(aDir, sDump, "dump"); + FileHelper.writeEncodedBufferToFile(aDump, "UTF-8", false, sLog); + // <- DEBUG ! + + java.lang.String sMsg = "File '"+aFile.getPath()+"' is not encoded right as UTF-8."; + throw new java.io.IOException(sMsg); + } + + aByteStream.close(); + } + + //___________________________________________ + + /** writes the given string buffer into the specified file + * using the specified encoding. + * + * Further it can be set, if the file should be expanded + * or replaced by this new string buffer. + * + * @param aFile + * must point to a system file. It can already exist! + * e.g.: "c:\temp\test.txt" + * "/tmp/test.txt" + * + * @param sEncoding + * will be used to encode the string content inside the file. + * e.g.: "UTF8" + * + * @param bAppend + * specify if an already existing file will be + * expanded or replaced. + * + * @param sBuffer + * the new string content for this file. + */ + public static void writeEncodedBufferToFile(java.io.File aFile , + java.lang.String sEncoding, + boolean bAppend , + java.lang.StringBuffer sBuffer ) + throws java.io.IOException + { + java.io.FileOutputStream aByteStream = new java.io.FileOutputStream(aFile.getAbsolutePath(), bAppend); + java.io.OutputStreamWriter aEncodedWriter = new java.io.OutputStreamWriter(aByteStream, sEncoding); + + java.lang.String sTemp = sBuffer.toString(); + aEncodedWriter.write(sTemp, 0, sTemp.length()); + + aEncodedWriter.flush(); + aEncodedWriter.close(); + + if (!aFile.exists()) + throw new java.io.IOException("File \""+aFile.getAbsolutePath()+"\" not written correctly."); + } +} diff --git a/l10ntools/source/filter/utils/Logger.java b/l10ntools/source/filter/utils/Logger.java new file mode 100644 index 000000000000..2d5ed631cd69 --- /dev/null +++ b/l10ntools/source/filter/utils/Logger.java @@ -0,0 +1,174 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +package com.sun.star.filter.config.tools.utils; + +//_______________________________________________ +// imports + +import java.lang.*; +import java.util.*; + +//_______________________________________________ +// definition + +/** can be used to print out some debug messages + * and group it into warnings/errors or info statements. + * + * + */ +public class Logger +{ + //___________________________________________ + // const + + /** only error message will be shown. */ + public static final int LEVEL_ERRORS = 1; + + /** only errors and warnings will be shown. */ + public static final int LEVEL_WARNINGS = 2; + + /** enable errors/warnings and some global info + * message. */ + public static final int LEVEL_GLOBALINFOS = 3; + + /** enable anything! */ + public static final int LEVEL_DETAILEDINFOS = 4; + + //___________________________________________ + // member + + /** enable/disable different output level. + * e.g. warnings/errors/infos */ + private int m_nLevel; + + //___________________________________________ + // ctor + + /** initialize new debug object with the specified + * debug level. + * + * @param nLevel + * the new debug level. + * See const values LEVEL_xxx too. + */ + public Logger(int nLevel) + { + m_nLevel = nLevel; + } + + //___________________________________________ + // interface + + /** initialize new debug object with a default + * debug level. + */ + public Logger() + { + m_nLevel = LEVEL_DETAILEDINFOS; + } + + //___________________________________________ + // interface + + /** prints out an exception ... if the right level is set. + * + * @param ex + * the exception object + */ + public synchronized void setException(java.lang.Throwable ex) + { + if (m_nLevel >= LEVEL_ERRORS) + { + System.err.println("Exception:\n"); + ex.printStackTrace(); + } + } + + //___________________________________________ + // interface + + /** prints out an error ... if the right level is set. + * + * @param sError + * the error message. + */ + public synchronized void setError(java.lang.String sError) + { + if (m_nLevel >= LEVEL_ERRORS) + System.err.println("Error :\t\""+sError+"\""); + } + + //___________________________________________ + // interface + + /** prints out a warning ... if the right level is set. + * + * @param sWarning + * the warning message. + */ + public synchronized void setWarning(java.lang.String sWarning) + { + if (m_nLevel >= LEVEL_WARNINGS) + System.err.println("Warning :\t\""+sWarning+"\""); + } + + //___________________________________________ + // interface + + /** prints out a global info message ... if the right level is set. + * + * Global infos should be used to describe a complex operation. + * E.g.: loading of a document. + * But not for every sub operation like e.g. analyzing lines + * during loading the document! + * + * @param sInfo + * the info message. + */ + public synchronized void setGlobalInfo(java.lang.String sInfo) + { + if (m_nLevel >= LEVEL_GLOBALINFOS) + System.out.println("Info :\t\""+sInfo+"\""); + } + + //___________________________________________ + // interface + + /** prints out a mode detailed info message ... if the right level is set. + * + * Such detailed message are e.g. "analyze line [n] of file ...". + * + * @param sInfo + * the info message. + */ + public synchronized void setDetailedInfo(java.lang.String sInfo) + { + if (m_nLevel >= LEVEL_DETAILEDINFOS) + System.out.println("Detail :\t\""+sInfo+"\""); + } +} diff --git a/l10ntools/source/filter/utils/MalformedCommandLineException.java b/l10ntools/source/filter/utils/MalformedCommandLineException.java new file mode 100644 index 000000000000..e4ea0f95d99c --- /dev/null +++ b/l10ntools/source/filter/utils/MalformedCommandLineException.java @@ -0,0 +1,47 @@ +/*_*********************************************************************** + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + **********************************************************************_*/ + +package com.sun.star.filter.config.tools.utils; + +//_______________________________________________ +// imports + +import java.lang.*; + +//___________________________________________ +// types + +/** indicates a malformed command line. + * + * E.g. it must be thrown if the command line contains one item more then once, + * or use unsupported format. + */ +public class MalformedCommandLineException extends java.lang.Exception +{ + public MalformedCommandLineException() {} + public MalformedCommandLineException(java.lang.String sMsg) { super(sMsg); } +} diff --git a/l10ntools/source/filter/utils/XMLHelper.java b/l10ntools/source/filter/utils/XMLHelper.java new file mode 100644 index 000000000000..175d04ebacef --- /dev/null +++ b/l10ntools/source/filter/utils/XMLHelper.java @@ -0,0 +1,822 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +package com.sun.star.filter.config.tools.utils; + +//_______________________________________________ + +import java.lang.*; +import java.util.*; +import java.io.*; + +//_______________________________________________ + +/** + * It provides some constant values and some static helper routines + * which are neccessary to work with a xml file - especialy + * the filter configuration. + * + * + */ +public class XMLHelper +{ + //___________________________________________ + // public const + + /** its a possible value of the xml attribute "oor:type" and identify an integer type. */ + public static final java.lang.String XMLTYPE_INTEGER = "xs:int"; + + /** its a possible value of the xml attribute "oor:type" and identify an boolean type. */ + public static final java.lang.String XMLTYPE_BOOLEAN = "xs:boolean"; + + /** its a possible value of the xml attribute "oor:type" and identify an string type. */ + public static final java.lang.String XMLTYPE_STRING = "xs:string"; + + /** its a possible value of the xml attribute "oor:type" and identify an string list type. */ + public static final java.lang.String XMLTYPE_STRINGLIST = "oor:string-list"; + + /** its a xml attribute, which specify a property name. */ + public static final java.lang.String XMLATTRIB_OOR_NAME = "oor:name"; + + /** its a xml attribute, which specify a property type. */ + public static final java.lang.String XMLATTRIB_OOR_TYPE = "oor:type"; + + /** its a xml attribute, which specify a list separator. */ + public static final java.lang.String XMLATTRIB_OOR_SEPARATOR = "oor:separator"; + + /** its a xml attribute, which specify a localized value. */ + public static final java.lang.String XMLATTRIB_OOR_LOCALIZED = "oor:localized"; + + /** its a xml attribute, which specify a merge operation for cfg layering. */ + public static final java.lang.String XMLATTRIB_OOR_OP = "oor:op"; + + /** can be used as value for XMLATTRIB_OOR_OP. */ + public static final java.lang.String XMLATTRIB_OP_REPLACE = "replace"; + + /** its a xml attribute, which specify a locale value. */ + public static final java.lang.String XMLATTRIB_XML_LANG = "xml:lang"; + + /** its the tag name of a <value ...> entry. */ + public static final java.lang.String XMLTAG_VALUE = "value"; + + /** its the tag name of a <prop ...> entry. */ + public static final java.lang.String XMLTAG_PROP = "prop"; + + /** its the tag name of a <node ...> entry. */ + public static final java.lang.String XMLTAG_NODE = "node"; + + //___________________________________________ + // private const + + /** a static list of all possible separators, which can be used for configuration type string-list. */ + private static final java.lang.String[] DELIMS = {" ", ",", ";", ".", ":", "-", "_", "#", "'", "+", "*", "~", "=", "?"}; + + /** index of the default separator inside list DELIMS. + * Its neccessary to know such default separator; because it can + * be supressed as xml attribute of the corresponding value tag. */ + private static final int DEFAULT_SEPARATOR = 0; + + //___________________________________________ + + /** analyze the structures of the given XML node and + * return a property set of all found sub nodes. + * + * Such properties are organized as [name, value] pairs. + * The type of a xml node will be detected automaticly. + * Following types are supported: + * xs:int => java.lang.Integer + * xs:bool => java.lang.Boolean + * xs:string => java.lang.String + * oor:string-list => java.util.LinkedList[java.lang.String] + * oor:set => java.util.Vector[java.lang.Object] + * oor:localized => java.util.HashMap[java.lang.Object] + * + * @param aNode + * points directly to the xml node, where we should analyze + * the children nodes. + * + * @return [java.util.HashMap] + * contains every node name as key and its string(!) as value. + */ + public static java.util.HashMap convertNodeToPropSet(org.w3c.dom.Node aNode) + throws java.lang.Exception + { + java.util.HashMap aPropSet = new java.util.HashMap(); + + // get all child nodes, which seems to be properties + java.util.Vector lChildNodes = XMLHelper.extractChildNodesByTagName(aNode, XMLTAG_PROP); + java.util.Enumeration en1 = lChildNodes.elements(); + while(en1.hasMoreElements()) + { + org.w3c.dom.Node aChildNode = (org.w3c.dom.Node)en1.nextElement(); + + // read its name + java.lang.String sChildName = XMLHelper.extractNodeAttribByName(aChildNode, XMLATTRIB_OOR_NAME); + if (sChildName == null) + throw new java.io.IOException("unsupported format: could not extract child node name"); + + // read its type info + java.lang.String sChildType = XMLHelper.extractNodeAttribByName(aChildNode, XMLATTRIB_OOR_TYPE); + if (sChildType == null) + { + /** Special patch: + * If an xml tag has no type information set ... we can restore it + * by analyzing the already readed tag name :-) + * Not very nice - but it can help to read stripped xml files too. */ + sChildType = XMLHelper.getTypeForTag(sChildName); + if (sChildType == null) + throw new java.io.IOException("unsupported format: could not extract child node type"); + } + + // read its value(s?) + java.util.Vector lChildValues = XMLHelper.extractChildNodesByTagName(aChildNode, XMLTAG_VALUE); + java.util.Enumeration en2 = lChildValues.elements(); + int nValue = 0; + java.lang.Object aValue = null; + while(en2.hasMoreElements()) + { + org.w3c.dom.Node aValueNode = (org.w3c.dom.Node)en2.nextElement(); + java.lang.String sChildLocale = XMLHelper.extractNodeAttribByName(aValueNode, XMLATTRIB_XML_LANG); + boolean bLocalized = (sChildLocale != null); + + ++nValue; + + if (sChildType.equals(XMLTYPE_INTEGER)) + { + if (!bLocalized && nValue > 1) + throw new java.io.IOException("unsupported format: more then one value for non localized but atomic type detected"); + java.lang.String sData = ((org.w3c.dom.CharacterData)aValueNode.getFirstChild()).getData(); + aValue = new java.lang.Integer(sData); + } + else + if (sChildType.equals(XMLTYPE_BOOLEAN)) + { + if (!bLocalized && nValue > 1) + throw new java.io.IOException("unsupported format: more then one value for non localized but atomic type detected"); + java.lang.String sData = ((org.w3c.dom.CharacterData)aValueNode.getFirstChild()).getData(); + aValue = new java.lang.Boolean(sData); + } + else + if (sChildType.equals(XMLTYPE_STRING)) + { + if (!bLocalized && nValue > 1) + throw new java.io.IOException("unsupported format: more then one value for non localized but atomic type detected"); + + java.lang.String sData = ((org.w3c.dom.CharacterData)aValueNode.getFirstChild()).getData(); + + java.util.HashMap lLocalized = null; + if (bLocalized) + { + if (aValue == null) + aValue = new java.util.HashMap(); + lLocalized = (java.util.HashMap)aValue; + lLocalized.put(sChildLocale, sData); + } + else + aValue = sData; + } + else + if (sChildType.equals(XMLTYPE_STRINGLIST)) + { + if (!bLocalized && nValue > 1) + throw new java.io.IOException("unsupported format: more then one value for non localized but atomic type detected"); + + java.lang.String sSeparator = XMLHelper.extractNodeAttribByName(aChildNode, XMLATTRIB_OOR_SEPARATOR); + if (sSeparator == null) + sSeparator = " "; + + java.lang.String sData = ((org.w3c.dom.CharacterData)aValueNode.getFirstChild()).getData(); + sData = sData.replace('\t', ' '); + sData = sData.replace('\n', ' '); + java.util.StringTokenizer aTokenizer = new java.util.StringTokenizer(sData, sSeparator); + java.util.Vector lList = new java.util.Vector(); + while(aTokenizer.hasMoreTokens()) + { + java.lang.String sToken = (java.lang.String)aTokenizer.nextToken(); + sToken.trim(); + if (sToken.length() < 1) + continue; + lList.add(sToken); + } + aValue = lList; + } + + aPropSet.put(sChildName, aValue); + } + } + + return aPropSet; + } + + //___________________________________________ + + private static java.lang.String getTypeForTag(java.lang.String sTag) + { + java.lang.String sType = null; + + if ( + (sTag.equals(Cache.PROPNAME_DATA )) || + (sTag.equals(Cache.PROPNAME_NAME )) || + (sTag.equals(Cache.PROPNAME_UINAME )) || + (sTag.equals(Cache.PROPNAME_MEDIATYPE )) || + (sTag.equals(Cache.PROPNAME_CLIPBOARDFORMAT )) || + (sTag.equals(Cache.PROPNAME_PREFERREDFILTER )) || + (sTag.equals(Cache.PROPNAME_DETECTSERVICE )) || + (sTag.equals(Cache.PROPNAME_FRAMELOADER )) || + (sTag.equals(Cache.PROPNAME_CONTENTHANDLER )) || + (sTag.equals(Cache.PROPNAME_DOCUMENTSERVICE )) || + (sTag.equals(Cache.PROPNAME_FILTERSERVICE )) || + (sTag.equals(Cache.PROPNAME_TEMPLATENAME )) || + (sTag.equals(Cache.PROPNAME_TYPE )) || + (sTag.equals(Cache.PROPNAME_UICOMPONENT )) + ) + sType = XMLTYPE_STRING; + else + if ( + (sTag.equals(Cache.PROPNAME_PREFERRED )) || + (sTag.equals("Installed" )) + ) + sType = XMLTYPE_BOOLEAN; + else + if ( + (sTag.equals(Cache.PROPNAME_UIORDER )) || + (sTag.equals(Cache.PROPNAME_DOCUMENTICONID )) || + (sTag.equals(Cache.PROPNAME_FILEFORMATVERSION)) + ) + sType = XMLTYPE_INTEGER; + else + if ( + (sTag.equals(Cache.PROPNAME_URLPATTERN )) || + (sTag.equals(Cache.PROPNAME_EXTENSIONS )) || + (sTag.equals(Cache.PROPNAME_USERDATA )) || + (sTag.equals(Cache.PROPNAME_FLAGS )) || + (sTag.equals(Cache.PROPNAME_TYPES )) + ) + sType = XMLTYPE_STRINGLIST; + + if (sType == null) + System.err.println("getTypeForTag("+sTag+") = "+sType); + + return sType; + } + + //___________________________________________ + + /** return a xml representation of the given property set. + * + * @param aPropSet + * a set of <name,value> pairs, which should be translated to xml + * + * @return [java.lang.String] + * the xml string representation. + * + * @throws [java.lang.Exception] + * if anything during convertion fill fail. + */ + public static java.lang.String convertPropSetToXML(java.util.HashMap aPropSet , + int nPrettyTabs) + throws java.lang.Exception + { + java.lang.StringBuffer sXML = new java.lang.StringBuffer(256); + + java.util.Iterator it1 = aPropSet.keySet().iterator(); + while(it1.hasNext()) + { + java.lang.String sProp = (java.lang.String)it1.next(); + java.lang.Object aVal = aPropSet.get(sProp); + + sProp = encodeHTMLSigns(sProp); + + // is it a simple type? + if ( + (aVal instanceof java.lang.Integer) || + (aVal instanceof java.lang.Boolean) || + (aVal instanceof java.lang.String ) + ) + { + sXML.append(XMLHelper.convertSimpleObjectToXML(sProp, aVal, nPrettyTabs)); + continue; + } + + // no! + // is it a list value? + if (aVal instanceof java.util.Vector) + { + java.util.Vector lVal = (java.util.Vector)aVal; + sXML.append(XMLHelper.convertListToXML(sProp, lVal, nPrettyTabs)); + continue; + } + + // its a localized value? + if (aVal instanceof java.util.HashMap) + { + java.util.HashMap lVal = (java.util.HashMap)aVal; + sXML.append(XMLHelper.convertLocalizedValueToXML(sProp, lVal, nPrettyTabs)); + continue; + } + + // unknown type! + java.lang.StringBuffer sMsg = new java.lang.StringBuffer(256); + sMsg.append("unsupported object type detected."); + sMsg.append("\ttype ? : \""+sProp+"\" = "+aVal); + sMsg.append("\tprop set: \""+aPropSet ); + throw new java.lang.Exception(sMsg.toString()); + } + + return sXML.toString(); + } + + public static java.lang.String encodeHTMLSigns(java.lang.String sValue) + { + java.lang.StringBuffer sSource = new java.lang.StringBuffer(sValue); + java.lang.StringBuffer sDestination = new java.lang.StringBuffer(1000 ); + + for (int i=0; i<sSource.length(); ++i) + { + char c = sSource.charAt(i); + if (c == '&') + sDestination.append("&"); + else + sDestination.append(c); + } + + java.lang.String sReturn = sDestination.toString(); + if (!sReturn.equals(sValue)) + System.out.println("encode \""+sValue+"\" => \""+sReturn+"\""); + + return sReturn; + } + + //___________________________________________ + + /** return a xml representation of an atomic property. + * + * Atomic property types are e.g. Integer, Boolean, String. + * + * @param sName + * the name of the property. + + * @param aValue + * the value of the property. + * + * @param nPrettyTabs + * count of tab signs for pretty format the xml code :-) + * + * @return [java.lang.String] + * the xml string representation. + * + * @throws [java.lang.Exception] + * if anything during convertion fill fail. + */ + private static java.lang.String convertSimpleObjectToXML(java.lang.String sName , + java.lang.Object aValue , + int nPrettyTabs) + throws java.lang.Exception + { + java.lang.StringBuffer sXML = new java.lang.StringBuffer(256); + for (int t=0; t<nPrettyTabs; ++t) + sXML.append("\t"); + + if (aValue instanceof java.lang.Integer) + { + sXML.append("<prop "+XMLATTRIB_OOR_NAME+"=\""+sName+"\">"); + sXML.append("<value>"+aValue.toString()+"</value>"); + sXML.append("</prop>\n"); + } + else + if (aValue instanceof java.lang.Boolean) + { + sXML.append("<prop "+XMLATTRIB_OOR_NAME+"=\""+sName+"\">"); + sXML.append("<value>"+aValue.toString()+"</value>"); + sXML.append("</prop>\n"); + } + else + if (aValue instanceof java.lang.String) + { + sXML.append("<prop "+XMLATTRIB_OOR_NAME+"=\""+sName+"\""); + java.lang.String sValue = (java.lang.String)aValue; + + sValue = encodeHTMLSigns(sValue); + + if (sValue.length() < 1) + sXML.append("/>\n"); + else + { + sXML.append("><value>"+sValue+"</value>"); + sXML.append("</prop>\n"); + } + } + else + { + System.err.println("name = "+sName); + System.err.println("value = "+aValue); + // ! can be used outside to detect - that it was not a simple type :-) + throw new java.lang.Exception("not an atomic type."); + } + + return sXML.toString(); + } + + //___________________________________________ + + /** return a xml representation of a string-list property. + * + * @param sName + * the name of the property. + + * @param aValue + * the value of the property. + * + * @param nPrettyTabs + * count of tab signs for pretty format the xml code :-) + * + * @return [java.lang.String] + * the xml string representation. + * + * @throws [java.lang.Exception] + * if anything during convertion fill fail. + */ + private static java.lang.String convertListToXML(java.lang.String sName , + java.util.Vector aValue , + int nPrettyTabs) + throws java.lang.Exception + { + java.lang.StringBuffer sXML = new java.lang.StringBuffer(256); + + for (int t=0; t<nPrettyTabs; ++t) + sXML.append("\t"); + + int c = aValue.size(); + if (c < 1) + { + sXML.append("<prop "+XMLATTRIB_OOR_NAME+"=\""+sName+"\"/>\n"); + return sXML.toString(); + } + + // step over all list items and add it to a string buffer + // Every item will be separated by a default separator "\n" first. + // Because "\n" is not a valid separator at all and can`t occure inside + // our list items. During we step over all items, we check if our current separator + // (we use a list of possible ones!) clash with an item. + // If it clash - we step to the next possible separator. + // If our list of possible separator values runs out of range we throw + // an exception :-) Its better then generating of wrong values + // If we found a valid seperator - we use it to replace our "\n" place holder + // at the end of the following loop ... + + int d = 0; + java.lang.StringBuffer sValBuff = new java.lang.StringBuffer(256); + for (int i=0; i<c; ++i) + { + // get the next list item + java.lang.Object aItem = aValue.get(i); + if (!(aItem instanceof java.lang.String)) + throw new java.lang.Exception("Current implementation supports string-list only!"); + + java.lang.String sValue = (java.lang.String)aItem; + + sValue = encodeHTMLSigns(sValue); + + // append item with default separator, which isn a valid separator at all + // But supress adding of the separator if last element is reached. + sValBuff.append(sValue); + if (i<(c-1)) + sValBuff.append("\n"); + + // check for delim clash + // Attention: An empty (means default) element forbid using + // of a whitespace character as separator! + while(true) + { + if (d >= DELIMS.length) + throw new java.lang.Exception("No valid separator found for a string list item."); + if (sValue.length() < 1 && DELIMS[d].equals(" ")) + { + ++d; + continue; + } + if (sValue.indexOf(DELIMS[d]) != -1) + { + ++d; + continue; + } + break; + } + } + + // replace default separator with right one + System.out.println("TODO: must be adapted to java 1.3 :-("); + System.exit(-1); +//TODO_JAVA java.lang.String sListVal = sValBuff.toString().replaceAll("\n", DELIMS[d]); + java.lang.String sListVal = null; + + sXML.append("<prop "+XMLATTRIB_OOR_NAME+"=\""+sName+"\">"); + if (d == DEFAULT_SEPARATOR) + sXML.append("<value>"); + else + sXML.append("<value "+XMLATTRIB_OOR_SEPARATOR+"=\""+DELIMS[d]+"\">"); + sXML.append(sListVal); + sXML.append("</value>"); + sXML.append("</prop>\n"); + + return sXML.toString(); + } + + //___________________________________________ + + /** return a xml representation of a localized property. + * + * @param sName + * the name of the property. + + * @param aValue + * the value of the property. + * + * @param nPrettyTabs + * count of tab signs for pretty format the xml code :-) + * + * @return [java.lang.String] + * the xml string representation. + * + * @throws [java.lang.Exception] + * if anything during convertion fill fail. + */ + private static java.lang.String convertLocalizedValueToXML(java.lang.String sName , + java.util.HashMap aValue , + int nPrettyTabs) + throws java.lang.Exception + { + java.lang.StringBuffer sXML = new java.lang.StringBuffer(256); + + int c = aValue.size(); + if (c < 1) + throw new java.lang.Exception("Cant detect type of localized values. Because the given list is empty."); + + for (int t=0; t<nPrettyTabs; ++t) + sXML.append("\t"); + // !Our localized values must be formated at a deeper coloum + // then its property name! + ++nPrettyTabs; + + sXML.append("<prop "+XMLATTRIB_OOR_NAME+"=\""+sName+"\">\n"); + java.util.Iterator it = aValue.keySet().iterator(); +// boolean bTypeKnown = false; + while(it.hasNext()) + { + java.lang.String sLocale = (java.lang.String)it.next(); + java.lang.Object aLocalizedValue = aValue.get(sLocale); +/* + if (!bTypeKnown) + { + bTypeKnown = true; + if (aLocalizedValue instanceof java.lang.Integer) + sXML.append(" "+XMLATTRIB_OOR_TYPE+"=\""+XMLTYPE_INTEGER+"\">\n"); + else + if (aLocalizedValue instanceof java.lang.Boolean) + sXML.append(" "+XMLATTRIB_OOR_TYPE+"=\""+XMLTYPE_BOOLEAN+"\">\n"); + else + if (aLocalizedValue instanceof java.lang.String) + sXML.append(" "+XMLATTRIB_OOR_TYPE+"=\""+XMLTYPE_STRING+"\">\n"); + else + throw new java.lang.Exception("Unsupported type for localized value detected."); + } +*/ + java.lang.String sLocValue = aLocalizedValue.toString(); + java.lang.String sValue = encodeHTMLSigns(sLocValue); + + for (int t=0; t<nPrettyTabs; ++t) + sXML.append("\t"); + sXML.append("<value "+XMLATTRIB_XML_LANG+"=\""+sLocale+"\">"+sValue+"</value>\n"); + } + --nPrettyTabs; + for (int t=0; t<nPrettyTabs; ++t) + sXML.append("\t"); + sXML.append("</prop>\n"); + + return sXML.toString(); + } + + //___________________________________________ + + /** returns the value of an attribute of the given node. + * + * If the given node represent an lement node, may it supports some attributes. + * Then this method search for an attribute with the specified name and return it's value. + * If nothing could be found ... or the given node isn't a suitable node ... it returns null. + * + * @param aNode + * the node, which should be analyzed. + * + * @param sAttrib + * name of the attribute, which should be searched. + * + * @return The value of the specified attribute if it could be found at the given node. + * Can be null if node doesn't support attributes or the searched one does not exist there. + */ + public static java.lang.String extractNodeAttribByName(org.w3c.dom.Node aNode , + java.lang.String sAttrib) + throws java.lang.Exception + { + // We can get valid attributes for element nodes only! + if (aNode.getNodeType() != org.w3c.dom.Node.ELEMENT_NODE) + { +// System.err.println("not an element node"); + return null; + } + + // may it supports attributes in general ... but doesn't have anyone realy. + org.w3c.dom.NamedNodeMap lAttribs = aNode.getAttributes(); + if (lAttribs==null) + { +// System.err.println("no attributes at all"); + return null; + } + + // step over the attribute list and search for the requested one + for (int i=0; i<lAttribs.getLength(); ++i) + { + org.w3c.dom.Attr aAttrib = (org.w3c.dom.Attr)lAttribs.item(i); + if (aAttrib.getName().equals(sAttrib)) + { + java.lang.String sValue = aAttrib.getValue(); + return sValue; + } + } + + // the searched attribute was not found! +// System.err.println("required attribute \""+sAttrib+"\" does not exist for node ["+aNode.toString()+"]"); + return null; + } + + //___________________________________________ + + /** returns a list of childs, which are ELEMENT_NODES and have the right tag name. + * + * It analyze the list of all possible child nodes. Only ELEMENT_NODES are candidates. + * All other ones will be ignored. Further these element nodes are compared by it's tag + * names. If it match with the specified value it's added to the return list. + * So the return list includes references to the DOM tree nodes only, which are child + * element nodes with the right tag name. + * + * @param aNode + * provides access to the child nodes, which should be analyzed + * + * @param sTag + * the searched tag name. + * + * @return A list of child nodes, which are element nodes and have the right tag name. + */ + public static java.util.Vector extractChildNodesByTagName(org.w3c.dom.Node aNode, + java.lang.String sTag ) + { + // extract first all ELEMENT_NODES of he given parent + // Such nodes only provide tag names. + java.util.Vector lChilds = XMLHelper.extractChildNodesByType(aNode,org.w3c.dom.Node.ELEMENT_NODE); + java.util.Vector lExtractedChilds = new java.util.Vector(lChilds.size()); + + // step over the list and search for the right tags using the specified name + java.util.Enumeration en = lChilds.elements(); + while (en.hasMoreElements()) + { + org.w3c.dom.Node aChild = (org.w3c.dom.Node)en.nextElement(); + if (aChild.getNodeName().equals(sTag)) + lExtractedChilds.add(aChild); + } + + // pack(!) and return the list + lExtractedChilds.trimToSize(); + return lExtractedChilds; + } + + //___________________________________________ + + /** returns a list of childs, which supports the right node type. + * + * It analyze the list of all possible child nodes. If a node represent the right node type + * it is added to the return list. Otherwhise it will be ignored. + * + * @param aNode + * provides access to the list of possible children nodes. + * + * @param nType + * represent the searched node type. + * Possible values are constant fields of a org.w3c.dom.Node - e.g. org.w3c.dom.Node.ELEMENT_NODE. + * + * @return A list of child nodes, which provides the right node type. + */ + public static java.util.Vector extractChildNodesByType(org.w3c.dom.Node aNode, + short nType) + { + // get list of all possibe childs and reserve enough space for our return list + // Attention: A null pointer is not allowed for return! (means lExtractedChilds) + org.w3c.dom.NodeList lChilds = aNode.getChildNodes(); + int c = lChilds.getLength(); + java.util.Vector lExtractedChilds = new java.util.Vector(c); + + // step of these childs and select only needed ones + for (int i=0; i<c; ++i) + { + org.w3c.dom.Node aChild = lChilds.item(i); + if (aChild.getNodeType() == nType) + lExtractedChilds.add(aChild); + } + + // pack(!) and return the list + lExtractedChilds.trimToSize(); + return lExtractedChilds; + } + + //___________________________________________ + + /** generates an xml header, using parameters. + * + * @param sVersion + * number of the xml version. + * + * @param sEncoding + * used file encoding. + * + * @param sPath + * name of the configuration root. + * + * @param sPackage + * name of the configuration package. + * + * @param bLanguagepack + * force creation of a special header, + * which is needed for language packs only. + * + * @return [java.lang.String] + * the generated xml header. + +*/ + public static java.lang.String generateHeader(java.lang.String sVersion , + java.lang.String sEncoding , + java.lang.String sPath , + java.lang.String sPackage , + boolean bLanguagePack) + { + java.lang.StringBuffer sHeader = new java.lang.StringBuffer(256); + + if (bLanguagePack) + { + sHeader.append("<?xml version=\""); + sHeader.append(sVersion); + sHeader.append("\" encoding=\""); + sHeader.append(sEncoding); + sHeader.append("\"?>\n"); + sHeader.append("<oor:component-data oor:package=\""); + sHeader.append(sPath); + sHeader.append("\" oor:name=\""); + sHeader.append(sPackage); + sHeader.append("\" xmlns:install=\"http://openoffice.org/2004/installation\""); + sHeader.append(" xmlns:oor=\"http://openoffice.org/2001/registry\""); + sHeader.append(" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""); + sHeader.append(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n"); + } + else + { + sHeader.append("<?xml version=\""); + sHeader.append(sVersion); + sHeader.append("\" encoding=\""); + sHeader.append(sEncoding); + sHeader.append("\"?>\n"); + sHeader.append("<oor:component-data xmlns:oor=\"http://openoffice.org/2001/registry\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" oor:package=\""); + sHeader.append(sPath); + sHeader.append("\" oor:name=\""); + sHeader.append(sPackage); + sHeader.append("\">\n"); + } + + return sHeader.toString(); + } + + public static java.lang.String generateFooter() + { + return "</oor:component-data>\n"; + } +} diff --git a/l10ntools/source/filter/utils/makefile.mk b/l10ntools/source/filter/utils/makefile.mk new file mode 100644 index 000000000000..43a28d57ee9e --- /dev/null +++ b/l10ntools/source/filter/utils/makefile.mk @@ -0,0 +1,53 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/.. +TARGET = FCFGUtils +PRJNAME = l10ntools +PACKAGE = com$/sun$/star$/filter$/config$/tools$/utils + +# --- Settings ----------------------------------------------------- + +.INCLUDE: settings.mk + +#----- compile .java files ----------------------------------------- + + +JAVACLASSFILES = \ + $(CLASSDIR)$/$(PACKAGE)$/AnalyzeStartupLog.class \ + $(CLASSDIR)$/$(PACKAGE)$/ConfigHelper.class \ + $(CLASSDIR)$/$(PACKAGE)$/Logger.class \ + $(CLASSDIR)$/$(PACKAGE)$/FileHelper.class \ + $(CLASSDIR)$/$(PACKAGE)$/MalformedCommandLineException.class \ + $(CLASSDIR)$/$(PACKAGE)$/Cache.class \ + $(CLASSDIR)$/$(PACKAGE)$/XMLHelper.class + +MAXLINELENGTH = 100000 + +# --- targets ----------------------------------------------------- + +.INCLUDE : target.mk diff --git a/l10ntools/source/gsicheck.cxx b/l10ntools/source/gsicheck.cxx new file mode 100644 index 000000000000..510ccce21c3a --- /dev/null +++ b/l10ntools/source/gsicheck.cxx @@ -0,0 +1,1173 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_l10ntools.hxx" +#include <stdio.h> +#include <tools/fsys.hxx> +#include <tools/stream.hxx> +#include <tools/list.hxx> + +// local includes +#include "tagtest.hxx" +#include "gsicheck.hxx" + +#define MAX_GID_LID_LEN 250 + +/*****************************************************************************/ +void PrintMessage( ByteString aType, ByteString aMsg, ByteString aPrefix, + ByteString aContext, BOOL bPrintContext, ULONG nLine, ByteString aUniqueId = ByteString() ) +/*****************************************************************************/ +{ + fprintf( stdout, "%s %s, Line %lu", aType.GetBuffer(), aPrefix.GetBuffer(), nLine ); + if ( aUniqueId.Len() ) + fprintf( stdout, ", UniqueID %s", aUniqueId.GetBuffer() ); + fprintf( stdout, ": %s", aMsg.GetBuffer() ); + + if ( bPrintContext ) + fprintf( stdout, " \"%s\"", aContext.GetBuffer() ); + fprintf( stdout, "\n" ); +} + +/*****************************************************************************/ +void PrintError( ByteString aMsg, ByteString aPrefix, + ByteString aContext, BOOL bPrintContext, ULONG nLine, ByteString aUniqueId = ByteString() ) +/*****************************************************************************/ +{ + PrintMessage( "Error:", aMsg, aPrefix, aContext, bPrintContext, nLine, aUniqueId ); +} + +BOOL LanguageOK( ByteString aLang ) +{ + if ( !aLang.Len() ) + return FALSE; + + if ( aLang.IsNumericAscii() ) + return TRUE; + + if ( aLang.GetTokenCount( '-' ) == 1 ) + return aLang.IsAlphaAscii() && aLang.IsLowerAscii(); + else if ( aLang.GetTokenCount( '-' ) == 2 ) + { + ByteString aTok0( aLang.GetToken( 0, '-' ) ); + ByteString aTok1( aLang.GetToken( 1, '-' ) ); + return aTok0.Len() && aTok0.IsAlphaAscii() && aTok0.IsLowerAscii() + && aTok1.Len() && aTok1.IsAlphaAscii() && aTok1.IsUpperAscii() + && !aTok1.EqualsIgnoreCaseAscii( aTok0 ); + } + + return FALSE; +} + + +// +// class LazySvFileStream +// + + +class LazySvFileStream : public SvFileStream +{ + +private: + String aFileName; + BOOL bOpened; + StreamMode eOpenMode; + +public: + LazySvFileStream() + : aFileName() + , bOpened( FALSE ) + , eOpenMode( 0 ) + {}; + + void SetOpenParams( const String& rFileName, StreamMode eOpenModeP ) + { + aFileName = rFileName; + eOpenMode = eOpenModeP; + }; + + void LazyOpen(); +}; + +void LazySvFileStream::LazyOpen() +{ + if ( !bOpened ) + { + Open( aFileName, eOpenMode ); + if ( !IsOpen()) + { + fprintf( stderr, "\nERROR: Could not open Output-File %s!\n\n", ByteString( aFileName, RTL_TEXTENCODING_ASCII_US ).GetBuffer() ); + exit ( 4 ); + } + bOpened = TRUE; + } +} + + +// +// class GSILine +// + +/*****************************************************************************/ +GSILine::GSILine( const ByteString &rLine, ULONG nLine ) +/*****************************************************************************/ + : ByteString( rLine ) + , nLineNumber( nLine ) + , bOK( TRUE ) + , bFixed ( FALSE ) +{ + if ( rLine.GetTokenCount( '\t' ) == 15 ) + { + aFormat = FORMAT_SDF; + aUniqId = rLine.GetToken( 0, '\t' ); + aUniqId.Append("/").Append( rLine.GetToken( 1, '\t' ) ).Append("/").Append( rLine.GetToken( 3, '\t' ) ).Append("/").Append( rLine.GetToken( 4, '\t' ) ).Append("/").Append( rLine.GetToken( 5, '\t' ) ).Append("/").Append( rLine.GetToken( 6, '\t' ) ).Append("/").Append( rLine.GetToken( 7, '\t' ) ); + aLineType = ""; + aLangId = rLine.GetToken( 9, '\t' ); + aText = rLine.GetToken( 10, '\t' ); + aQuickHelpText = rLine.GetToken( 12, '\t' ); + aTitle = rLine.GetToken( 13, '\t' ); + + // do some more format checks here + if ( !rLine.GetToken( 8, '\t' ).IsNumericAscii() ) + { + PrintError( "The length field does not contain a number!", "Line format", rLine.GetToken( 8, '\t' ), TRUE, GetLineNumber(), GetUniqId() ); + NotOK(); + } + if ( !LanguageOK( aLangId ) ) + { + PrintError( "The Language is invalid!", "Line format", aLangId, TRUE, GetLineNumber(), GetUniqId() ); + NotOK(); + } + // limit GID and LID to MAX_GID_LID_LEN chars each for database conformity, see #137575# + if ( rLine.GetToken( 4, '\t' ).Len() > MAX_GID_LID_LEN || rLine.GetToken( 5, '\t' ).Len() > MAX_GID_LID_LEN ) + { + PrintError( ByteString("GID and LID may only be ").Append( ByteString::CreateFromInt32(MAX_GID_LID_LEN) ).Append( " chars long each!" ), "Line format", aLangId, TRUE, GetLineNumber(), GetUniqId() ); + NotOK(); + } + } + else // allow tabs in gsi files + { + aFormat = FORMAT_GSI; + ByteString sTmp( rLine ); + USHORT nPos = sTmp.Search( "($$)" ); + USHORT nStart = 0; + if ( nPos != STRING_NOTFOUND ) + { + aUniqId = sTmp.Copy( nStart, nPos - nStart ); + nStart = nPos + 4; // + length of the delemiter + nPos = sTmp.Search( "($$)", nStart ); + } + if ( nPos != STRING_NOTFOUND ) + { + aLineType = sTmp.Copy( nStart, nPos - nStart ); + nStart = nPos + 4; // + length of the delemiter + nPos = sTmp.Search( "($$)", nStart ); + aUniqId.Append( "/" ); + aUniqId.Append( aLineType ); + } + if ( nPos != STRING_NOTFOUND ) + { + aLangId = sTmp.Copy( nStart, nPos - nStart ); + nStart = nPos + 4; // + length of the delemiter + nPos = sTmp.Search( "($$)", nStart ); + } + if ( nPos != STRING_NOTFOUND ) + { + nStart = nPos + 4; // + length of the delemiter + } + if ( nPos != STRING_NOTFOUND ) + aText = sTmp.Copy( nStart ); + else + aFormat = FORMAT_UNKNOWN; + } + + if ( FORMAT_UNKNOWN == GetLineFormat() ) + NotOK(); +} + +/*****************************************************************************/ +void GSILine::NotOK() +/*****************************************************************************/ +{ + bOK = FALSE; +} + +/*****************************************************************************/ +void GSILine::ReassembleLine() +/*****************************************************************************/ +{ + ByteString aReassemble; + if ( GetLineFormat() == FORMAT_SDF ) + { + USHORT i; + for ( i = 0 ; i < 10 ; i++ ) + { + aReassemble.Append( GetToken( i, '\t' ) ); + aReassemble.Append( "\t" ); + } + aReassemble.Append( aText ); + aReassemble.Append( "\t" ); + aReassemble.Append( GetToken( 11, '\t' ) ); // should be empty but there are some places in sc. Not reflected to sources!! + aReassemble.Append( "\t" ); + aReassemble.Append( aQuickHelpText ); + aReassemble.Append( "\t" ); + aReassemble.Append( aTitle ); + for ( i = 14 ; i < 15 ; i++ ) + { + aReassemble.Append( "\t" ); + aReassemble.Append( GetToken( i, '\t' ) ); + } + *(ByteString*)this = aReassemble; + } + else if ( GetLineFormat() == FORMAT_GSI ) + { + USHORT nPos = Search( "($$)" ); + USHORT nStart = 0; + if ( nPos != STRING_NOTFOUND ) + { + nStart = nPos + 4; // + length of the delemiter + nPos = Search( "($$)", nStart ); + } + if ( nPos != STRING_NOTFOUND ) + { + nStart = nPos + 4; // + length of the delemiter + nPos = Search( "($$)", nStart ); + } + if ( nPos != STRING_NOTFOUND ) + { + nStart = nPos + 4; // + length of the delemiter + nPos = Search( "($$)", nStart ); + } + if ( nPos != STRING_NOTFOUND ) + { + nStart = nPos + 4; // + length of the delemiter + } + if ( nPos != STRING_NOTFOUND ) + { + aReassemble = Copy( 0, nStart ); + aReassemble += aText; + *(ByteString*)this = aReassemble; + } + else + PrintError( "Cannot reassemble GSI line (internal Error).", "Line format", "", FALSE, GetLineNumber(), GetUniqId() ); + } + else + PrintError( "Cannot reassemble line of unknown type (internal Error).", "Line format", "", FALSE, GetLineNumber(), GetUniqId() ); +} + +// +// class GSIBlock +// +/*****************************************************************************/ +GSIBlock::GSIBlock( BOOL PbPrintContext, BOOL bSource, BOOL bTrans, BOOL bRef, BOOL bAllowKID, BOOL bAllowSusp ) +/*****************************************************************************/ + : pSourceLine( NULL ) + , pReferenceLine( NULL ) + , bPrintContext( PbPrintContext ) + , bCheckSourceLang( bSource ) + , bCheckTranslationLang( bTrans ) + , bReference( bRef ) + , bAllowKeyIDs( bAllowKID ) + , bAllowSuspicious( bAllowSusp ) + , bHasBlockError( FALSE ) +{ +} + +/*****************************************************************************/ +GSIBlock::~GSIBlock() +/*****************************************************************************/ +{ + delete pSourceLine; + delete pReferenceLine; + + for ( size_t i = 0, n = maList.size(); i < n; ++i ) + delete maList[ i ]; + maList.clear(); +} + +/*****************************************************************************/ +void GSIBlock::InsertLine( GSILine* pLine, ByteString aSourceLang) +/*****************************************************************************/ +{ + if ( pLine->GetLanguageId().Equals( aSourceLang ) ) + { + if ( pSourceLine ) + { + PrintError( "Source Language entry double. Treating as Translation.", "File format", "", pLine->GetLineNumber(), pLine->GetUniqId() ); + bHasBlockError = TRUE; + pSourceLine->NotOK(); + pLine->NotOK(); + } + else + { + pSourceLine = pLine; + return; + } + } + + if ( aSourceLang.Len() ) // only check blockstructure if source lang is given + { + for ( size_t nPos = 0, n = maList.size(); nPos < n; ++nPos ) + { + if ( maList[ nPos ]->GetLanguageId().Equals( pLine->GetLanguageId() ) ) + { + PrintError( "Translation Language entry double. Checking both.", "File format", "", pLine->GetLineNumber(), pLine->GetUniqId() ); + bHasBlockError = TRUE; + maList[ nPos ]->NotOK(); + pLine->NotOK(); + } + nPos++; + } + } + maList.push_back( pLine ); +} + +/*****************************************************************************/ +void GSIBlock::SetReferenceLine( GSILine* pLine ) +/*****************************************************************************/ +{ + pReferenceLine = pLine; +} + +/*****************************************************************************/ +void GSIBlock::PrintMessage( ByteString aType, ByteString aMsg, ByteString aPrefix, + ByteString aContext, ULONG nLine, ByteString aUniqueId ) +/*****************************************************************************/ +{ + ::PrintMessage( aType, aMsg, aPrefix, aContext, bPrintContext, nLine, aUniqueId ); +} + +/*****************************************************************************/ +void GSIBlock::PrintError( ByteString aMsg, ByteString aPrefix, + ByteString aContext, ULONG nLine, ByteString aUniqueId ) +/*****************************************************************************/ +{ + PrintMessage( "Error:", aMsg, aPrefix, aContext, nLine, aUniqueId ); +} + +/*****************************************************************************/ +void GSIBlock::PrintList( ParserMessageList *pList, ByteString aPrefix, + GSILine *pLine ) +/*****************************************************************************/ +{ + for ( size_t i = 0 ; i < pList->size() ; i++ ) + { + ParserMessage *pMsg = (*pList)[ i ]; + ByteString aContext; + if ( bPrintContext ) + { + if ( pMsg->GetTagBegin() == STRING_NOTFOUND ) + aContext = pLine->GetText().Copy( 0, 300 ); + else + aContext = pLine->Copy( pMsg->GetTagBegin()-150, 300 ); + aContext.EraseTrailingChars(' '); + aContext.EraseLeadingChars(' '); + } + + PrintMessage( pMsg->Prefix(), pMsg->GetErrorText(), aPrefix, aContext, pLine->GetLineNumber(), pLine->GetUniqId() ); + } +} + +/*****************************************************************************/ +BOOL GSIBlock::IsUTF8( const ByteString &aTestee, BOOL bFixTags, USHORT &nErrorPos, ByteString &aErrorMsg, BOOL &bHasBeenFixed, ByteString &aFixed ) const +/*****************************************************************************/ +{ + String aUTF8Tester( aTestee, RTL_TEXTENCODING_UTF8 ); + if ( STRING_MATCH != (nErrorPos = ByteString( aUTF8Tester, RTL_TEXTENCODING_UTF8 ).Match( aTestee )) ) + { + aUTF8Tester = String( aTestee.GetBuffer(), nErrorPos, RTL_TEXTENCODING_UTF8 ); + nErrorPos = aUTF8Tester.Len(); + aErrorMsg = ByteString( "UTF8 Encoding seems to be broken" ); + return FALSE; + } + + nErrorPos = aUTF8Tester.SearchChar( String::CreateFromAscii( "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0b\x0c\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x7f" ).GetBuffer() ); + if ( nErrorPos != STRING_NOTFOUND ) + { + aErrorMsg = ByteString( "String contains illegal character" ); + return FALSE; + } + + if ( bFixTags ) + { + bHasBeenFixed = FALSE; + aFixed.Erase(); + } + + if ( !bAllowKeyIDs ) + { + BOOL bIsKeyID = FALSE; + BOOL bNewId = FALSE; + ByteString aID( aTestee ); + USHORT nAfterID = 0; + + if ( aTestee.Equals( "{&", 0, 2 ) ) + { // check for strings from instset_native like "{&Tahoma8}335795.Installation Wiza ..." + USHORT nTagEnd = aTestee.Search( '}' ); + if ( nTagEnd != STRING_NOTFOUND ) + { + if ( bFixTags ) + aFixed = aTestee.Copy( 0, nTagEnd+1 ); + nErrorPos = nTagEnd+1; + aID = aTestee.Copy( nTagEnd+1 ); + nAfterID = nTagEnd+1; + } + } + + ByteString aDelimiter( (String)String( sal_Unicode(0x2016) ), RTL_TEXTENCODING_UTF8 ); + + if ( aID.Equals( aDelimiter, 6, aDelimiter.Len() ) ) + { // New KeyId 6 Letters, digits and spechial chars followed by delimiter + bNewId = TRUE; + nErrorPos = 1; + aID = aID.Copy( 0, 6 ); + nAfterID += 6; + nAfterID = nAfterID + aDelimiter.Len(); + } + else if ( ( aID.GetChar(6) == '*' ) && aID.Equals( aDelimiter, 7, aDelimiter.Len() ) ) + { // New KeyId 6 Letters, digits and spechial chars followed by '*delimiter' to indicate translation in progress + bNewId = TRUE; + nErrorPos = 1; + aID = aID.Copy( 0, 6 ); + nAfterID += 7; + nAfterID = nAfterID + aDelimiter.Len(); + } + else if ( aID.GetTokenCount( '.' ) > 1 ) + { // test for old KeyIDs 5 to 6 digits followed by a dot '44373.' + bNewId = FALSE; + nErrorPos = 1; + aID = aID.GetToken( 0, '.' ); + nAfterID = nAfterID + aID.Len(); + } + else + { + aID.Erase(); + } + + if ( bNewId ) + { + if ( aID.Len() == 6 ) + { + bIsKeyID = TRUE; + ByteString aDigits("0123456789abcdefghijklmnopqrstuvwxyz+-<=>"); + for ( USHORT i=0 ; i < aID.Len() ;i++ ) + { + if ( aDigits.Search( aID.GetChar(i) ) == STRING_NOTFOUND ) + bIsKeyID = FALSE; + } + } + } + else + { + if ( aID.Len() > 0 && aID.GetChar(aID.Len()-1) == '*' ) + aID.Erase( aID.Len()-1 ); + + if ( aID.IsNumericAscii() && aID.Len() >= 5 ) + bIsKeyID = TRUE; + } + + if ( bIsKeyID ) + { + aErrorMsg = ByteString( "String contains KeyID" ); + if ( bFixTags ) + { + aFixed += aTestee.Copy( nAfterID ); + bHasBeenFixed = TRUE; + aErrorMsg = ByteString( "FIXED String containing KeyID" ); + } + else + aErrorMsg = ByteString( "String contains KeyID" ); + return FALSE; + } + } + + return TRUE; +} + +/*****************************************************************************/ +BOOL GSIBlock::TestUTF8( GSILine* pTestee, BOOL bFixTags ) +/*****************************************************************************/ +{ + USHORT nErrorPos = 0; + ByteString aErrorMsg; + BOOL bError = FALSE; + ByteString aFixed; + BOOL bHasBeenFixed = FALSE; + if ( !IsUTF8( pTestee->GetText(), bFixTags, nErrorPos, aErrorMsg, bHasBeenFixed, aFixed ) ) + { + ByteString aContext( pTestee->GetText().Copy( nErrorPos, 20 ) ); + PrintError( aErrorMsg.Append(" in Text at Position " ).Append( ByteString::CreateFromInt32( nErrorPos ) ), "Text format", aContext, pTestee->GetLineNumber(), pTestee->GetUniqId() ); + bError = TRUE; + if ( bHasBeenFixed ) + { + pTestee->SetText( aFixed ); + pTestee->SetFixed(); + } + } + if ( !IsUTF8( pTestee->GetQuickHelpText(), bFixTags, nErrorPos, aErrorMsg, bHasBeenFixed, aFixed ) ) + { + ByteString aContext( pTestee->GetQuickHelpText().Copy( nErrorPos, 20 ) ); + PrintError( aErrorMsg.Append(" in QuickHelpText at Position " ).Append( ByteString::CreateFromInt32( nErrorPos ) ), "Text format", aContext, pTestee->GetLineNumber(), pTestee->GetUniqId() ); + bError = TRUE; + if ( bHasBeenFixed ) + { + pTestee->SetQuickHelpText( aFixed ); + pTestee->SetFixed(); + } + } + if ( !IsUTF8( pTestee->GetTitle(), bFixTags, nErrorPos, aErrorMsg, bHasBeenFixed, aFixed ) ) + { + ByteString aContext( pTestee->GetTitle().Copy( nErrorPos, 20 ) ); + PrintError( aErrorMsg.Append(" in Title at Position " ).Append( ByteString::CreateFromInt32( nErrorPos ) ), "Text format", aContext, pTestee->GetLineNumber(), pTestee->GetUniqId() ); + bError = TRUE; + if ( bHasBeenFixed ) + { + pTestee->SetTitle( aFixed ); + pTestee->SetFixed(); + } + } + if ( bError ) + pTestee->NotOK(); + return !bError; +} + + +/*****************************************************************************/ +BOOL GSIBlock::HasSuspiciousChars( GSILine* pTestee, GSILine* pSource ) +/*****************************************************************************/ +{ + USHORT nPos = 0; + if ( !bAllowSuspicious && ( nPos = pTestee->GetText().Search("??")) != STRING_NOTFOUND ) + if ( pSource->GetText().Search("??") == STRING_NOTFOUND ) + { + String aUTF8Tester = String( pTestee->GetText(), 0, nPos, RTL_TEXTENCODING_UTF8 ); + USHORT nErrorPos = aUTF8Tester.Len(); + ByteString aContext( pTestee->GetText().Copy( nPos, 20 ) ); + PrintError( ByteString("Found double questionmark in translation only. Looks like an encoding problem at Position " ).Append( ByteString::CreateFromInt32( nErrorPos ) ), "Text format", aContext, pTestee->GetLineNumber(), pTestee->GetUniqId() ); + pTestee->NotOK(); + return TRUE; + } + + return FALSE; +} + + +/*****************************************************************************/ +BOOL GSIBlock::CheckSyntax( ULONG nLine, BOOL bRequireSourceLine, BOOL bFixTags ) +/*****************************************************************************/ +{ + static LingTest aTester; + BOOL bHasError = FALSE; + + if ( !pSourceLine ) + { + if ( bRequireSourceLine ) + { + PrintError( "No source language entry defined!", "File format", "", nLine ); + bHasBlockError = TRUE; + } + } + else + { + aTester.CheckReference( pSourceLine ); + if ( pSourceLine->HasMessages() ) + { + PrintList( pSourceLine->GetMessageList(), "ReferenceString", pSourceLine ); + pSourceLine->NotOK(); + bHasError = TRUE; + } + } + if ( bReference ) + { + if ( !pReferenceLine ) + { + GSILine *pSource; + if ( pSourceLine ) + pSource = pSourceLine; + else + pSource = maList.empty() ? NULL : maList[ 0 ]; // get some other line + if ( pSource ) + PrintError( "No reference line found. Entry is new in source file", "File format", "", pSource->GetLineNumber(), pSource->GetUniqId() ); + else + PrintError( "No reference line found. Entry is new in source file", "File format", "", nLine ); + bHasBlockError = TRUE; + } + else + { + if ( pSourceLine && !pSourceLine->Equals( *pReferenceLine ) ) + { + xub_StrLen nPos = pSourceLine->Match( *pReferenceLine ); + ByteString aContext( pReferenceLine->Copy( nPos - 5, 15) ); + aContext.Append( "\" --> \"" ).Append( pSourceLine->Copy( nPos - 5, 15) ); + PrintError( "Source Language Entry has changed.", "File format", aContext, pSourceLine->GetLineNumber(), pSourceLine->GetUniqId() ); + pSourceLine->NotOK(); + bHasError = TRUE; + } + } + } + + if ( pSourceLine ) + bHasError |= !TestUTF8( pSourceLine, bFixTags ); + + for ( size_t i = 0, n = maList.size(); i < n; ++i ) + { + GSILine* pItem = maList[ i ]; + aTester.CheckTestee( pItem, pSourceLine != NULL, bFixTags ); + if ( pItem->HasMessages() || aTester.HasCompareWarnings() ) + { + if ( pItem->HasMessages() || aTester.GetCompareWarnings().HasErrors() ) + pItem->NotOK(); + bHasError = TRUE; + PrintList( pItem->GetMessageList(), "Translation", pItem ); + PrintList( &(aTester.GetCompareWarnings()), "Translation Tag Mismatch", pItem ); + } + bHasError |= !TestUTF8( pItem, bFixTags ); + if ( pSourceLine ) + bHasError |= HasSuspiciousChars( pItem, pSourceLine ); + } + + return bHasError || bHasBlockError; +} + +void GSIBlock::WriteError( LazySvFileStream &aErrOut, BOOL bRequireSourceLine ) +{ + if ( pSourceLine && pSourceLine->IsOK() && bCheckSourceLang && !bHasBlockError ) + return; + + BOOL bHasError = FALSE; + BOOL bCopyAll = ( !pSourceLine && bRequireSourceLine ) || ( pSourceLine && !pSourceLine->IsOK() && !bCheckTranslationLang ) || bHasBlockError; + for ( size_t i = 0, n = maList.size(); i < n; ++i ) + { + GSILine* pItem = maList[ i ]; + if ( !pItem->IsOK() || bCopyAll ) + { + bHasError = TRUE; + aErrOut.LazyOpen(); + aErrOut.WriteLine( *pItem ); + } + } + + if ( pSourceLine && ( bHasError || !pSourceLine->IsOK() ) && !( !bHasError && bCheckTranslationLang ) ) + { + aErrOut.LazyOpen(); + aErrOut.WriteLine( *pSourceLine ); + } +} + +void GSIBlock::WriteCorrect( LazySvFileStream &aOkOut, BOOL bRequireSourceLine ) +{ + if ( ( !pSourceLine && bRequireSourceLine ) || ( pSourceLine && !pSourceLine->IsOK() && !bCheckTranslationLang ) ) + return; + + BOOL bHasOK = FALSE; + for ( size_t i = 0, n = maList.size(); i < n; ++i ) + { + GSILine* pItem = maList[ i ]; + if ( ( pItem->IsOK() || bCheckSourceLang ) && !bHasBlockError ) + { + bHasOK = TRUE; + aOkOut.LazyOpen(); + aOkOut.WriteLine( *pItem ); + } + } + + if ( ( pSourceLine && pSourceLine->IsOK() && ( !maList.empty() || !bCheckTranslationLang ) ) || ( bHasOK && bCheckTranslationLang ) ) + { + aOkOut.LazyOpen(); + aOkOut.WriteLine( *pSourceLine ); + } +} + +void GSIBlock::WriteFixed( LazySvFileStream &aFixOut, BOOL /*bRequireSourceLine*/ ) +{ + if ( pSourceLine && !pSourceLine->IsFixed() && bCheckSourceLang ) + return; + + BOOL bHasFixes = FALSE; + for ( size_t i = 0, n = maList.size(); i < n; ++i ) + { + GSILine* pItem = maList[ i ]; + if ( pItem->IsFixed() ) + { + bHasFixes = TRUE; + aFixOut.LazyOpen(); + aFixOut.WriteLine( *pItem ); + } + } + + if ( pSourceLine && ( bHasFixes || pSourceLine->IsFixed() ) ) + { + aFixOut.LazyOpen(); + aFixOut.WriteLine( *pSourceLine ); + } +} + + +/*****************************************************************************/ +/*****************************************************************************/ +/*****************************************************************************/ +/*****************************************************************************/ +/*****************************************************************************/ +/*****************************************************************************/ +/*****************************************************************************/ + +/*****************************************************************************/ +void Help() +/*****************************************************************************/ +{ + fprintf( stdout, "\n" ); + fprintf( stdout, "gsicheck Version 1.9.0 (c)1999 - 2006 by SUN Microsystems\n" ); + fprintf( stdout, "=========================================================\n" ); + fprintf( stdout, "\n" ); + fprintf( stdout, "gsicheck checks the syntax of tags in GSI-Files and SDF-Files\n" ); + fprintf( stdout, " checks for inconsistencies and malicious UTF8 encoding\n" ); + fprintf( stdout, " checks tags in Online Help\n" ); + fprintf( stdout, " checks for *new* KeyIDs and relax GID/LID length to %s\n", ByteString::CreateFromInt32(MAX_GID_LID_LEN).GetBuffer() ); + fprintf( stdout, "\n" ); + fprintf( stdout, "Syntax: gsicheck [ -c ] [-f] [ -we ] [ -wef ErrorFilename ] [ -wc ]\n" ); + fprintf( stdout, " [ -wcf CorrectFilename ] [ -s | -t ] [ -l LanguageID ]\n" ); + fprintf( stdout, " [ -r ReferenceFile ] filename\n" ); + fprintf( stdout, "\n" ); + fprintf( stdout, "-c Add context to error message (Print the line containing the error)\n" ); + fprintf( stdout, "-f try to fix errors. See also -wf -wff \n" ); + fprintf( stdout, "-wf Write File containing all fixed parts\n" ); + fprintf( stdout, "-wff Same as above but give own filename\n" ); + fprintf( stdout, "-we Write File containing all errors\n" ); + fprintf( stdout, "-wef Same as above but give own filename\n" ); + fprintf( stdout, "-wc Write File containing all correct parts\n" ); + fprintf( stdout, "-wcf Same as above but give own filename\n" ); + fprintf( stdout, "-s Check only source language. Should be used before handing out to vendor.\n" ); + fprintf( stdout, "-t Check only Translation language(s). Should be used before merging.\n" ); + fprintf( stdout, "-k Allow KeyIDs to be present in strings\n" ); + fprintf( stdout, "-e disable encoding checks. E.g.: double questionmark \'??\' which may be the\n" ); + fprintf( stdout, " result of false conversions\n" ); + fprintf( stdout, "-l ISO Languagecode or numerical 2 digits Identifier of the source language.\n" ); + fprintf( stdout, " Default is en-US. Use \"\" (empty string) or 'none'\n" ); + fprintf( stdout, " to disable source language dependent checks\n" ); + fprintf( stdout, "-r Reference filename to check that source language entries\n" ); + fprintf( stdout, " have not been changed\n" ); + fprintf( stdout, "\n" ); +} + +/*****************************************************************************/ +#if defined(UNX) || defined(OS2) +int main( int argc, char *argv[] ) +#else +int _cdecl main( int argc, char *argv[] ) +#endif +/*****************************************************************************/ +{ + + BOOL bError = FALSE; + BOOL bPrintContext = FALSE; + BOOL bCheckSourceLang = FALSE; + BOOL bCheckTranslationLang = FALSE; + BOOL bWriteError = FALSE; + BOOL bWriteCorrect = FALSE; + BOOL bWriteFixed = FALSE; + BOOL bFixTags = FALSE; + BOOL bAllowKID = FALSE; + BOOL bAllowSuspicious = FALSE; + String aErrorFilename; + String aCorrectFilename; + String aFixedFilename; + BOOL bFileHasError = FALSE; + ByteString aSourceLang( "en-US" ); // English is default + ByteString aFilename; + ByteString aReferenceFilename; + BOOL bReferenceFile = FALSE; + for ( USHORT i = 1 ; i < argc ; i++ ) + { + if ( *argv[ i ] == '-' ) + { + switch (*(argv[ i ]+1)) + { + case 'c':bPrintContext = TRUE; + break; + case 'w': + { + if ( (*(argv[ i ]+2)) == 'e' ) + { + if ( (*(argv[ i ]+3)) == 'f' ) + if ( (i+1) < argc ) + { + aErrorFilename = String( argv[ i+1 ], RTL_TEXTENCODING_ASCII_US ); + bWriteError = TRUE; + i++; + } + else + { + fprintf( stderr, "\nERROR: Switch %s requires parameter!\n\n", argv[ i ] ); + bError = TRUE; + } + else + bWriteError = TRUE; + } + else if ( (*(argv[ i ]+2)) == 'c' ) + if ( (*(argv[ i ]+3)) == 'f' ) + if ( (i+1) < argc ) + { + aCorrectFilename = String( argv[ i+1 ], RTL_TEXTENCODING_ASCII_US ); + bWriteCorrect = TRUE; + i++; + } + else + { + fprintf( stderr, "\nERROR: Switch %s requires parameter!\n\n", argv[ i ] ); + bError = TRUE; + } + else + bWriteCorrect = TRUE; + else if ( (*(argv[ i ]+2)) == 'f' ) + if ( (*(argv[ i ]+3)) == 'f' ) + if ( (i+1) < argc ) + { + aFixedFilename = String( argv[ i+1 ], RTL_TEXTENCODING_ASCII_US ); + bWriteFixed = TRUE; + bFixTags = TRUE; + i++; + } + else + { + fprintf( stderr, "\nERROR: Switch %s requires parameter!\n\n", argv[ i ] ); + bError = TRUE; + } + else + { + bWriteFixed = TRUE; + bFixTags = TRUE; + } + else + { + fprintf( stderr, "\nERROR: Unknown Switch %s!\n\n", argv[ i ] ); + bError = TRUE; + } + } + break; + case 's':bCheckSourceLang = TRUE; + break; + case 't':bCheckTranslationLang = TRUE; + break; + case 'l': + { + if ( (i+1) < argc ) + { + aSourceLang = ByteString( argv[ i+1 ] ); + if ( aSourceLang.EqualsIgnoreCaseAscii( "none" ) ) + aSourceLang.Erase(); + i++; + } + else + { + fprintf( stderr, "\nERROR: Switch %s requires parameter!\n\n", argv[ i ] ); + bError = TRUE; + } + } + break; + case 'r': + { + if ( (i+1) < argc ) + { + aReferenceFilename = argv[ i+1 ]; + bReferenceFile = TRUE; + i++; + } + else + { + fprintf( stderr, "\nERROR: Switch %s requires parameter!\n\n", argv[ i ] ); + bError = TRUE; + } + } + break; + case 'f': + { + bFixTags = TRUE; + } + break; + case 'k': + { + bAllowKID = TRUE; + } + break; + case 'e': + { + bAllowSuspicious = TRUE; + } + break; + default: + fprintf( stderr, "\nERROR: Unknown Switch %s!\n\n", argv[ i ] ); + bError = TRUE; + } + } + else + { + if ( !aFilename.Len()) + aFilename = ByteString( argv[ i ] ); + else + { + fprintf( stderr, "\nERROR: Only one filename may be specified!\n\n"); + bError = TRUE; + } + } + } + + + if ( !aFilename.Len() || bError ) + { + Help(); + exit ( 0 ); + } + + if ( aSourceLang.Len() && !LanguageOK( aSourceLang ) ) + { + fprintf( stderr, "\nERROR: The Language '%s' is invalid!\n\n", aSourceLang.GetBuffer() ); + Help(); + exit ( 1 ); + } + + if ( bCheckSourceLang && bCheckTranslationLang ) + { + fprintf( stderr, "\nERROR: The Options -s and -t are mutually exclusive.\nUse only one of them.\n\n" ); + Help(); + exit ( 1 ); + } + + + + DirEntry aSource = DirEntry( String( aFilename, RTL_TEXTENCODING_ASCII_US )); + if ( !aSource.Exists()) { + fprintf( stderr, "\nERROR: GSI-File %s not found!\n\n", aFilename.GetBuffer() ); + exit ( 2 ); + } + + SvFileStream aGSI( String( aFilename, RTL_TEXTENCODING_ASCII_US ), STREAM_STD_READ ); + if ( !aGSI.IsOpen()) { + fprintf( stderr, "\nERROR: Could not open GSI-File %s!\n\n", aFilename.GetBuffer() ); + exit ( 3 ); + } + + SvFileStream aReferenceGSI; + if ( bReferenceFile ) + { + DirEntry aReferenceSource = DirEntry( String( aReferenceFilename, RTL_TEXTENCODING_ASCII_US )); + if ( !aReferenceSource.Exists()) { + fprintf( stderr, "\nERROR: GSI-File %s not found!\n\n", aFilename.GetBuffer() ); + exit ( 2 ); + } + + aReferenceGSI.Open( String( aReferenceFilename, RTL_TEXTENCODING_ASCII_US ), STREAM_STD_READ ); + if ( !aReferenceGSI.IsOpen()) { + fprintf( stderr, "\nERROR: Could not open Input-File %s!\n\n", aFilename.GetBuffer() ); + exit ( 3 ); + } + } + + LazySvFileStream aOkOut; + String aBaseName = aSource.GetBase(); + if ( bWriteCorrect ) + { + if ( !aCorrectFilename.Len() ) + { + String sTmpBase( aBaseName ); + sTmpBase += String( "_ok", RTL_TEXTENCODING_ASCII_US ); + aSource.SetBase( sTmpBase ); + aCorrectFilename = aSource.GetFull(); + } + aOkOut.SetOpenParams( aCorrectFilename , STREAM_STD_WRITE | STREAM_TRUNC ); + } + + LazySvFileStream aErrOut; + if ( bWriteError ) + { + if ( !aErrorFilename.Len() ) + { + String sTmpBase( aBaseName ); + sTmpBase += String( "_err", RTL_TEXTENCODING_ASCII_US ); + aSource.SetBase( sTmpBase ); + aErrorFilename = aSource.GetFull(); + } + aErrOut.SetOpenParams( aErrorFilename , STREAM_STD_WRITE | STREAM_TRUNC ); + } + + LazySvFileStream aFixOut; + if ( bWriteFixed ) + { + if ( !aFixedFilename.Len() ) + { + String sTmpBase( aBaseName ); + sTmpBase += String( "_fix", RTL_TEXTENCODING_ASCII_US ); + aSource.SetBase( sTmpBase ); + aFixedFilename = aSource.GetFull(); + } + aFixOut.SetOpenParams( aFixedFilename , STREAM_STD_WRITE | STREAM_TRUNC ); + } + + + ByteString sReferenceLine; + GSILine* pReferenceLine = NULL; + ByteString aOldReferenceId("No Valid ID"); // just set to something which can never be an ID + ULONG nReferenceLine = 0; + + ByteString sGSILine; + GSILine* pGSILine = NULL; + ByteString aOldId("No Valid ID"); // just set to something which can never be an ID + GSIBlock *pBlock = NULL; + ULONG nLine = 0; + + while ( !aGSI.IsEof() ) + { + aGSI.ReadLine( sGSILine ); + nLine++; + pGSILine = new GSILine( sGSILine, nLine ); + BOOL bDelete = TRUE; + + + if ( pGSILine->Len() ) + { + if ( FORMAT_UNKNOWN == pGSILine->GetLineFormat() ) + { + PrintError( "Format of line is unknown. Ignoring!", "Line format", pGSILine->Copy( 0,40 ), bPrintContext, pGSILine->GetLineNumber() ); + pGSILine->NotOK(); + if ( bWriteError ) + { + bFileHasError = TRUE; + aErrOut.LazyOpen(); + aErrOut.WriteLine( *pGSILine ); + } + } + else if ( pGSILine->GetLineType().EqualsIgnoreCaseAscii("res-comment") ) + { // ignore comment lines, but write them to Correct Items File + if ( bWriteCorrect ) + { + aOkOut.LazyOpen(); + aOkOut.WriteLine( *pGSILine ); + } + } + else + { + ByteString aId = pGSILine->GetUniqId(); + if ( aId != aOldId ) + { + if ( pBlock ) + { + bFileHasError |= pBlock->CheckSyntax( nLine, aSourceLang.Len() != 0, bFixTags ); + + if ( bWriteError ) + pBlock->WriteError( aErrOut, aSourceLang.Len() != 0 ); + if ( bWriteCorrect ) + pBlock->WriteCorrect( aOkOut, aSourceLang.Len() != 0 ); + if ( bWriteFixed ) + pBlock->WriteFixed( aFixOut, aSourceLang.Len() != 0 ); + + delete pBlock; + } + pBlock = new GSIBlock( bPrintContext, bCheckSourceLang, bCheckTranslationLang, bReferenceFile, bAllowKID, bAllowSuspicious ); + + aOldId = aId; + + + // find corresponding line in reference file + if ( bReferenceFile ) + { + BOOL bContinueSearching = TRUE; + while ( ( !aReferenceGSI.IsEof() || pReferenceLine ) && bContinueSearching ) + { + if ( !pReferenceLine ) + { + aReferenceGSI.ReadLine( sReferenceLine ); + nReferenceLine++; + pReferenceLine = new GSILine( sReferenceLine, nReferenceLine ); + } + if ( pReferenceLine->GetLineFormat() != FORMAT_UNKNOWN ) + { + if ( pReferenceLine->GetUniqId() == aId && pReferenceLine->GetLanguageId().Equals( aSourceLang ) ) + { + pBlock->SetReferenceLine( pReferenceLine ); + pReferenceLine = NULL; + } + else if ( pReferenceLine->GetUniqId() > aId ) + { + bContinueSearching = FALSE; + } + else + { + if ( pReferenceLine->GetUniqId() < aId && pReferenceLine->GetLanguageId().Equals( aSourceLang ) ) + PrintError( "No Entry in source file found. Entry has been removed from source file", "File format", "", bPrintContext, pGSILine->GetLineNumber(), pReferenceLine->GetUniqId() ); + delete pReferenceLine; + pReferenceLine = NULL; + } + } + else + { + delete pReferenceLine; + pReferenceLine = NULL; + } + + } + } + + } + + pBlock->InsertLine( pGSILine, aSourceLang ); + bDelete = FALSE; + } + } + if ( bDelete ) + delete pGSILine; + + } + if ( pBlock ) + { + bFileHasError |= pBlock->CheckSyntax( nLine, aSourceLang.Len() != 0, bFixTags ); + + if ( bWriteError ) + pBlock->WriteError( aErrOut, aSourceLang.Len() != 0 ); + if ( bWriteCorrect ) + pBlock->WriteCorrect( aOkOut, aSourceLang.Len() != 0 ); + if ( bWriteFixed ) + pBlock->WriteFixed( aFixOut, aSourceLang.Len() != 0 ); + + delete pBlock; + } + aGSI.Close(); + + if ( bWriteError ) + aErrOut.Close(); + if ( bWriteCorrect ) + aOkOut.Close(); + if ( bWriteFixed ) + aFixOut.Close(); + + if ( bFileHasError ) + return 55; + else + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/gsiconv.cxx b/l10ntools/source/gsiconv.cxx new file mode 100644 index 000000000000..f06104175c0d --- /dev/null +++ b/l10ntools/source/gsiconv.cxx @@ -0,0 +1,372 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_l10ntools.hxx" +#include <stdio.h> +#include <tools/fsys.hxx> +#include <tools/stream.hxx> + +// local includes +#include "utf8conv.hxx" + +#define GSI_FILE_UNKNOWN 0x0000 +#define GSI_FILE_OLDSTYLE 0x0001 +#define GSI_FILE_L10NFRAMEWORK 0x0002 + +/*****************************************************************************/ +USHORT GetGSIFileType( SvStream &rStream ) +/*****************************************************************************/ +{ + USHORT nFileType = GSI_FILE_UNKNOWN; + + ULONG nPos( rStream.Tell()); + rStream.Seek( STREAM_SEEK_TO_BEGIN ); + + ByteString sLine; + while( !rStream.IsEof() && !sLine.Len()) + rStream.ReadLine( sLine ); + + if( sLine.Len()) { + if( sLine.Search( "($$)" ) != STRING_NOTFOUND ) + nFileType = GSI_FILE_OLDSTYLE; + else + nFileType = GSI_FILE_L10NFRAMEWORK; + } + + rStream.Seek( nPos ); + + return nFileType; +} + +/*****************************************************************************/ +ByteString GetGSILineId( const ByteString &rLine, USHORT nFileType ) +/*****************************************************************************/ +{ + ByteString sId; + switch ( nFileType ) { + case GSI_FILE_OLDSTYLE: + sId = rLine; + sId.SearchAndReplaceAll( "($$)", "\t" ); + sId = sId.GetToken( 0, '\t' ); + break; + + case GSI_FILE_L10NFRAMEWORK: + sId = rLine.GetToken( 0, '\t' ); + sId += "\t"; + sId += rLine.GetToken( 1, '\t' ); + sId += "\t"; + sId += rLine.GetToken( 4, '\t' ); + sId += "\t"; + sId += rLine.GetToken( 5, '\t' ); + break; + } + return sId; +} + +/*****************************************************************************/ +ByteString GetGSILineLangId( const ByteString &rLine, USHORT nFileType ) +/*****************************************************************************/ +{ + ByteString sLangId; + switch ( nFileType ) { + case GSI_FILE_OLDSTYLE: + sLangId = rLine; + sLangId.SearchAndReplaceAll( "($$)", "\t" ); + sLangId = sLangId.GetToken( 2, '\t' ); + break; + + case GSI_FILE_L10NFRAMEWORK: + sLangId = rLine.GetToken( 9, '\t' ); + break; + } + return sLangId; +} + +/*****************************************************************************/ +void ConvertGSILine( BOOL bToUTF8, ByteString &rLine, + rtl_TextEncoding nEncoding, USHORT nFileType ) +/*****************************************************************************/ +{ + switch ( nFileType ) { + case GSI_FILE_OLDSTYLE: + if ( bToUTF8 ) + rLine = UTF8Converter::ConvertToUTF8( rLine, nEncoding ); + else + rLine = UTF8Converter::ConvertFromUTF8( rLine, nEncoding ); + break; + + case GSI_FILE_L10NFRAMEWORK: { + ByteString sConverted; + for ( USHORT i = 0; i < rLine.GetTokenCount( '\t' ); i++ ) { + ByteString sToken = rLine.GetToken( i, '\t' ); + if (( i > 9 ) && ( i < 14 )) { + if( bToUTF8 ) + sToken = UTF8Converter::ConvertToUTF8( sToken, nEncoding ); + else + sToken = UTF8Converter::ConvertFromUTF8( sToken, nEncoding ); + } + if ( i ) + sConverted += "\t"; + sConverted += sToken; + } + rLine = sConverted; + } + break; + } +} + +/*****************************************************************************/ +void Help() +/*****************************************************************************/ +{ + fprintf( stdout, "\n" ); + fprintf( stdout, "gsiconv (c)1999 by StarOffice Entwicklungs GmbH\n" ); + fprintf( stdout, "===============================================\n" ); + fprintf( stdout, "\n" ); + fprintf( stdout, "gsiconv converts strings in GSI-Files (Gutschmitt Interface) from or to UTF-8\n" ); + fprintf( stdout, "\n" ); + fprintf( stdout, "Syntax: gsiconv (-t|-f langid charset)|(-p n) filename\n" ); + fprintf( stdout, "Switches: -t => conversion from charset to UTF-8\n" ); + fprintf( stdout, " -f => conversion from UTF-8 to charset\n" ); + fprintf( stdout, " -p n => creates several files with ca. n lines\n" ); + fprintf( stdout, "\n" ); + fprintf( stdout, "Allowed charsets:\n" ); + fprintf( stdout, " MS_932 => Japanese\n" ); + fprintf( stdout, " MS_936 => Chinese Simplified\n" ); + fprintf( stdout, " MS_949 => Korean\n" ); + fprintf( stdout, " MS_950 => Chinese Traditional\n" ); + fprintf( stdout, " MS_1250 => East Europe\n" ); + fprintf( stdout, " MS_1251 => Cyrillic\n" ); + fprintf( stdout, " MS_1252 => West Europe\n" ); + fprintf( stdout, " MS_1253 => Greek\n" ); + fprintf( stdout, " MS_1254 => Turkish\n" ); + fprintf( stdout, " MS_1255 => Hebrew\n" ); + fprintf( stdout, " MS_1256 => Arabic\n" ); + fprintf( stdout, "\n" ); + fprintf( stdout, "Allowed langids:\n" ); + fprintf( stdout, " 1 => ENGLISH_US\n" ); + fprintf( stdout, " 3 => PORTUGUESE \n" ); + fprintf( stdout, " 4 => GERMAN_DE (new german style)\n" ); + fprintf( stdout, " 7 => RUSSIAN\n" ); + fprintf( stdout, " 30 => GREEK\n" ); + fprintf( stdout, " 31 => DUTCH\n" ); + fprintf( stdout, " 33 => FRENCH\n" ); + fprintf( stdout, " 34 => SPANISH\n" ); + fprintf( stdout, " 35 => FINNISH\n" ); + fprintf( stdout, " 36 => HUNGARIAN\n" ); + fprintf( stdout, " 39 => ITALIAN\n" ); + fprintf( stdout, " 42 => CZECH\n" ); + fprintf( stdout, " 44 => ENGLISH (UK)\n" ); + fprintf( stdout, " 45 => DANISH\n" ); + fprintf( stdout, " 46 => SWEDISH\n" ); + fprintf( stdout, " 47 => NORWEGIAN\n" ); + fprintf( stdout, " 49 => GERMAN (old german style)\n" ); + fprintf( stdout, " 55 => PORTUGUESE_BRAZILIAN\n" ); + fprintf( stdout, " 81 => JAPANESE\n" ); + fprintf( stdout, " 82 => KOREAN\n" ); + fprintf( stdout, " 86 => CHINESE_SIMPLIFIED\n" ); + fprintf( stdout, " 88 => CHINESE_TRADITIONAL\n" ); + fprintf( stdout, " 90 => TURKISH\n" ); + fprintf( stdout, " 96 => ARABIC\n" ); + fprintf( stdout, " 97 => HEBREW\n" ); + fprintf( stdout, "\n" ); +} + +/*****************************************************************************/ +#if defined(UNX) || defined(OS2) +int main( int argc, char *argv[] ) +#else +int _cdecl main( int argc, char *argv[] ) +#endif +/*****************************************************************************/ +{ + if (( argc != 5 ) && ( argc != 4 )) { + Help(); + exit ( 0 ); + } + + if ( argc == 4 ) { + if ( ByteString( argv[ 1 ] ) == "-p" ) { + + DirEntry aSource = DirEntry( String( argv[ 3 ], RTL_TEXTENCODING_ASCII_US )); + if ( !aSource.Exists()) { + fprintf( stderr, "\nERROR: GSI-File %s not found!\n\n", ByteString( argv[ 3 ] ).GetBuffer()); + exit ( 2 ); + } + + DirEntry aOutput( aSource ); + + String sBase = aOutput.GetBase(); + String sExt = aOutput.GetExtension(); + + String sGSI( argv[ 3 ], RTL_TEXTENCODING_ASCII_US ); + SvFileStream aGSI( sGSI, STREAM_STD_READ ); + if ( !aGSI.IsOpen()) { + fprintf( stderr, "\nERROR: Could not open GSI-File %s!\n\n", ByteString( argv[ 3 ] ).GetBuffer()); + exit ( 3 ); + } + + USHORT nFileType( GetGSIFileType( aGSI )); + + ULONG nMaxLines = (ULONG) ByteString( argv[ 2 ] ).ToInt64(); + if ( !nMaxLines ) { + fprintf( stderr, "\nERROR: Linecount must be at least 1!\n\n" ); + exit ( 3 ); + } + + ByteString sGSILine; + ByteString sOldId; + ULONG nLine = 0; + ULONG nOutputFile = 1; + + String sOutput( sBase ); + sOutput += String( "_", RTL_TEXTENCODING_ASCII_US ); + sOutput += String::CreateFromInt64( nOutputFile ); + if ( sExt.Len()) { + sOutput += String( ".", RTL_TEXTENCODING_ASCII_US ); + sOutput += sExt; + } + nOutputFile ++; + + aOutput.SetName( sOutput ); + SvFileStream aOutputStream( aOutput.GetFull(), STREAM_STD_WRITE | STREAM_TRUNC ); + + while ( !aGSI.IsEof()) { + + aGSI.ReadLine( sGSILine ); + ByteString sId( GetGSILineId( sGSILine, nFileType )); + + nLine++; + + if (( nLine >= nMaxLines ) && ( sId != sOldId )) { + aOutputStream.Close(); + + ByteString sText( aOutput.GetFull(), gsl_getSystemTextEncoding()); + sText += " with "; + sText += ByteString::CreateFromInt64( nLine ); + sText += " lines written."; + + fprintf( stdout, "%s\n", sText.GetBuffer()); + String sOutput1( sBase ); + sOutput1 += String( "_", RTL_TEXTENCODING_ASCII_US ); + sOutput1 += String::CreateFromInt64( nOutputFile ); + if ( sExt.Len()) { + sOutput1 += String( ".", RTL_TEXTENCODING_ASCII_US ); + sOutput1 += sExt; + } + nOutputFile ++; + + aOutput.SetName( sOutput1 ); + + aOutputStream.Open( aOutput.GetFull(), STREAM_STD_WRITE | STREAM_TRUNC ); + nLine = 0; + } + + aOutputStream.WriteLine( sGSILine ); + + sOldId = sId; + } + + aGSI.Close(); + aOutputStream.Close(); + + ByteString sText( aOutput.GetFull(), RTL_TEXTENCODING_ASCII_US ); + sText += " with "; + sText += ByteString::CreateFromInt64( nLine ); + sText += " lines written."; + } + else { + Help(); + exit( 1 ); + } + } + else { + if ( ByteString( argv[ 1 ] ) == "-t" || ByteString( argv[ 1 ] ) == "-f" ) { + rtl_TextEncoding nEncoding; + + ByteString sCurLangId( argv[ 2 ] ); + + ByteString sCharset( argv[ 3 ] ); + sCharset.ToUpperAscii(); + + if ( sCharset == "MS_932" ) nEncoding = RTL_TEXTENCODING_MS_932; + else if ( sCharset == "MS_936" ) nEncoding = RTL_TEXTENCODING_MS_936; + else if ( sCharset == "MS_949" ) nEncoding = RTL_TEXTENCODING_MS_949; + else if ( sCharset == "MS_950" ) nEncoding = RTL_TEXTENCODING_MS_950; + else if ( sCharset == "MS_1250" ) nEncoding = RTL_TEXTENCODING_MS_1250; + else if ( sCharset == "MS_1251" ) nEncoding = RTL_TEXTENCODING_MS_1251; + else if ( sCharset == "MS_1252" ) nEncoding = RTL_TEXTENCODING_MS_1252; + else if ( sCharset == "MS_1253" ) nEncoding = RTL_TEXTENCODING_MS_1253; + else if ( sCharset == "MS_1254" ) nEncoding = RTL_TEXTENCODING_MS_1254; + else if ( sCharset == "MS_1255" ) nEncoding = RTL_TEXTENCODING_MS_1255; + else if ( sCharset == "MS_1256" ) nEncoding = RTL_TEXTENCODING_MS_1256; + else if ( sCharset == "MS_1257" ) nEncoding = RTL_TEXTENCODING_MS_1257; + else if ( sCharset == "UTF8" ) nEncoding = RTL_TEXTENCODING_UTF8; + + else { + Help(); + exit ( 1 ); + } + + DirEntry aSource = DirEntry( String( argv[ 4 ], RTL_TEXTENCODING_ASCII_US )); + if ( !aSource.Exists()) { + fprintf( stderr, "\nERROR: GSI-File %s not found!\n\n", ByteString( argv[ 3 ] ).GetBuffer()); + exit ( 2 ); + } + + String sGSI( argv[ 4 ], RTL_TEXTENCODING_ASCII_US ); + SvFileStream aGSI( sGSI, STREAM_STD_READ ); + if ( !aGSI.IsOpen()) { + fprintf( stderr, "\nERROR: Could not open GSI-File %s!\n\n", ByteString( argv[ 3 ] ).GetBuffer()); + exit ( 3 ); + } + USHORT nFileType( GetGSIFileType( aGSI )); + + ByteString sGSILine; + while ( !aGSI.IsEof()) { + + aGSI.ReadLine( sGSILine ); + ByteString sLangId( GetGSILineLangId( sGSILine, nFileType )); + if ( sLangId == sCurLangId ) + ConvertGSILine(( ByteString( argv[ 1 ] ) == "-t" ), sGSILine, nEncoding, nFileType ); + + fprintf( stdout, "%s\n", sGSILine.GetBuffer()); + } + + aGSI.Close(); + } + else { + Help(); + exit( 1 ); + } + } + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/help/HelpCompiler.cxx b/l10ntools/source/help/HelpCompiler.cxx new file mode 100644 index 000000000000..8050a58c1411 --- /dev/null +++ b/l10ntools/source/help/HelpCompiler.cxx @@ -0,0 +1,591 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include "HelpCompiler.hxx" +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <libxslt/xslt.h> +#include <libxslt/xsltInternals.h> +#include <libxslt/transform.h> +#include <libxslt/xsltutils.h> +#ifdef __MINGW32__ +#include <tools/prewin.h> +#include <tools/postwin.h> +#endif +#include <osl/thread.hxx> + +static void impl_sleep( sal_uInt32 nSec ) +{ + TimeValue aTime; + aTime.Seconds = nSec; + aTime.Nanosec = 0; + + osl::Thread::wait( aTime ); +} + +HelpCompiler::HelpCompiler(StreamTable &in_streamTable, const fs::path &in_inputFile, + const fs::path &in_src, const fs::path &in_resEmbStylesheet, + const std::string &in_module, const std::string &in_lang, bool in_bExtensionMode) + : streamTable(in_streamTable), inputFile(in_inputFile), + src(in_src), module(in_module), lang(in_lang), resEmbStylesheet(in_resEmbStylesheet), + bExtensionMode( in_bExtensionMode ) +{ + xmlKeepBlanksDefaultValue = 0; +} + +xmlDocPtr HelpCompiler::getSourceDocument(const fs::path &filePath) +{ + static const char *params[4 + 1]; + static xsltStylesheetPtr cur = NULL; + + xmlDocPtr res; + if( bExtensionMode ) + { + res = xmlParseFile(filePath.native_file_string().c_str()); + if( !res ){ + impl_sleep( 3 ); + res = xmlParseFile(filePath.native_file_string().c_str()); + } + } + else + { + if (!cur) + { + static std::string fsroot('\'' + src.toUTF8() + '\''); + static std::string esclang('\'' + lang + '\''); + + xmlSubstituteEntitiesDefault(1); + xmlLoadExtDtdDefaultValue = 1; + cur = xsltParseStylesheetFile((const xmlChar *)resEmbStylesheet.native_file_string().c_str()); + + int nbparams = 0; + params[nbparams++] = "Language"; + params[nbparams++] = esclang.c_str(); + params[nbparams++] = "fsroot"; + params[nbparams++] = fsroot.c_str(); + params[nbparams] = NULL; + } + xmlDocPtr doc = xmlParseFile(filePath.native_file_string().c_str()); + if( !doc ) + { + impl_sleep( 3 ); + doc = xmlParseFile(filePath.native_file_string().c_str()); + } + + //???res = xmlParseFile(filePath.native_file_string().c_str()); + + res = xsltApplyStylesheet(cur, doc, params); + xmlFreeDoc(doc); + } + return res; +} + +HashSet HelpCompiler::switchFind(xmlDocPtr doc) +{ + HashSet hs; + xmlChar *xpath = (xmlChar*)"//switchinline"; + + xmlXPathContextPtr context = xmlXPathNewContext(doc); + xmlXPathObjectPtr result = xmlXPathEvalExpression(xpath, context); + xmlXPathFreeContext(context); + if (result) + { + xmlNodeSetPtr nodeset = result->nodesetval; + for (int i = 0; i < nodeset->nodeNr; i++) + { + xmlNodePtr el = nodeset->nodeTab[i]; + xmlChar *select = xmlGetProp(el, (xmlChar*)"select"); + if (select) + { + if (!strcmp((const char*)select, "appl")) + { + xmlNodePtr n1 = el->xmlChildrenNode; + while (n1) + { + if ((!xmlStrcmp(n1->name, (const xmlChar*)"caseinline"))) + { + xmlChar *appl = xmlGetProp(n1, (xmlChar*)"select"); + hs.push_back(std::string((const char*)appl)); + xmlFree(appl); + } + else if ((!xmlStrcmp(n1->name, (const xmlChar*)"defaultinline"))) + hs.push_back(std::string("DEFAULT")); + n1 = n1->next; + } + } + xmlFree(select); + } + } + xmlXPathFreeObject(result); + } + hs.push_back(std::string("DEFAULT")); + return hs; +} + +// returns a node representing the whole stuff compiled for the current +// application. +xmlNodePtr HelpCompiler::clone(xmlNodePtr node, const std::string& appl) +{ + xmlNodePtr parent = xmlCopyNode(node, 2); + xmlNodePtr n = node->xmlChildrenNode; + while (n != NULL) + { + bool isappl = false; + if ( (!strcmp((const char*)n->name, "switchinline")) || + (!strcmp((const char*)n->name, "switch")) ) + { + xmlChar *select = xmlGetProp(n, (xmlChar*)"select"); + if (select) + { + if (!strcmp((const char*)select, "appl")) + isappl = true; + xmlFree(select); + } + } + if (isappl) + { + xmlNodePtr caseNode = n->xmlChildrenNode; + if (appl == "DEFAULT") + { + while (caseNode) + { + if (!strcmp((const char*)caseNode->name, "defaultinline")) + { + xmlNodePtr cnl = caseNode->xmlChildrenNode; + while (cnl) + { + xmlAddChild(parent, clone(cnl, appl)); + cnl = cnl->next; + } + break; + } + caseNode = caseNode->next; + } + } + else + { + while (caseNode) + { + isappl=false; + if (!strcmp((const char*)caseNode->name, "caseinline")) + { + xmlChar *select = xmlGetProp(n, (xmlChar*)"select"); + if (select) + { + if (!strcmp((const char*)select, appl.c_str())) + isappl = true; + xmlFree(select); + } + if (isappl) + { + xmlNodePtr cnl = caseNode->xmlChildrenNode; + while (cnl) + { + xmlAddChild(parent, clone(cnl, appl)); + cnl = cnl->next; + } + break; + } + + } + caseNode = caseNode->next; + } + } + + } + else + xmlAddChild(parent, clone(n, appl)); + + n = n->next; + } + return parent; +} + +class myparser +{ +public: + std::string documentId; + std::string fileName; + std::string title; + HashSet *hidlist; + Hashtable *keywords; + Stringtable *helptexts; +private: + HashSet extendedHelpText; +public: + myparser(const std::string &indocumentId, const std::string &infileName, + const std::string &intitle) : documentId(indocumentId), fileName(infileName), + title(intitle) + { + hidlist = new HashSet; + keywords = new Hashtable; + helptexts = new Stringtable; + } + void traverse( xmlNodePtr parentNode ); +private: + std::string dump(xmlNodePtr node); +}; + +std::string myparser::dump(xmlNodePtr node) +{ + std::string app; + if (node->xmlChildrenNode) + { + xmlNodePtr list = node->xmlChildrenNode; + while (list) + { + app += dump(list); + list = list->next; + } + } + if (xmlNodeIsText(node)) + { + xmlChar *pContent = xmlNodeGetContent(node); + app += std::string((const char*)pContent); + xmlFree(pContent); + // std::cout << app << std::endl; + } + return app; +} + +void trim(std::string& str) +{ + std::string::size_type pos = str.find_last_not_of(' '); + if(pos != std::string::npos) + { + str.erase(pos + 1); + pos = str.find_first_not_of(' '); + if(pos != std::string::npos) + str.erase(0, pos); + } + else + str.erase(str.begin(), str.end()); +} + +void myparser::traverse( xmlNodePtr parentNode ) +{ + // traverse all nodes that belong to the parent + xmlNodePtr test ; + for (test = parentNode->xmlChildrenNode; test; test = test->next) + { + if (fileName.empty() && !strcmp((const char*)test->name, "filename")) + { + xmlNodePtr node = test->xmlChildrenNode; + if (xmlNodeIsText(node)) + { + xmlChar *pContent = xmlNodeGetContent(node); + fileName = std::string((const char*)pContent); + xmlFree(pContent); + } + } + else if (title.empty() && !strcmp((const char*)test->name, "title")) + { + title = dump(test); + if (title.empty()) + title = "<notitle>"; + } + else if (!strcmp((const char*)test->name, "bookmark")) + { + xmlChar *branchxml = xmlGetProp(test, (const xmlChar*)"branch"); + xmlChar *idxml = xmlGetProp(test, (const xmlChar*)"id"); + std::string branch((const char*)branchxml); + std::string anchor((const char*)idxml); + xmlFree (branchxml); + xmlFree (idxml); + + std::string hid; + + if (branch.find("hid") == 0) + { + size_t index = branch.find('/'); + if (index != std::string::npos) + { + hid = branch.substr(1 + index); + // one shall serve as a documentId + if (documentId.empty()) + documentId = hid; + extendedHelpText.push_back(hid); + std::string foo = anchor.empty() ? hid : hid + "#" + anchor; + HCDBG(std::cerr << "hid pushback" << foo << std::endl); + hidlist->push_back( anchor.empty() ? hid : hid + "#" + anchor); + } + else + continue; + } + else if (branch.compare("index") == 0) + { + LinkedList ll; + + for (xmlNodePtr nd = test->xmlChildrenNode; nd; nd = nd->next) + { + if (strcmp((const char*)nd->name, "bookmark_value")) + continue; + + std::string embedded; + xmlChar *embeddedxml = xmlGetProp(nd, (const xmlChar*)"embedded"); + if (embeddedxml) + { + embedded = std::string((const char*)embeddedxml); + xmlFree (embeddedxml); + std::transform (embedded.begin(), embedded.end(), + embedded.begin(), tolower); + } + + bool isEmbedded = !embedded.empty() && embedded.compare("true") == 0; + if (isEmbedded) + continue; + + std::string keyword = dump(nd); + size_t keywordSem = keyword.find(';'); + if (keywordSem != std::string::npos) + { + std::string tmppre = + keyword.substr(0,keywordSem); + trim(tmppre); + std::string tmppos = + keyword.substr(1+keywordSem); + trim(tmppos); + keyword = tmppre + ";" + tmppos; + } + ll.push_back(keyword); + } + if (!ll.empty()) + (*keywords)[anchor] = ll; + } + else if (branch.compare("contents") == 0) + { + // currently not used + } + } + else if (!strcmp((const char*)test->name, "ahelp")) + { + std::string text = dump(test); + trim(text); + std::string name; + + HashSet::const_iterator aEnd = extendedHelpText.end(); + for (HashSet::const_iterator iter = extendedHelpText.begin(); iter != aEnd; + ++iter) + { + name = *iter; + (*helptexts)[name] = text; + } + extendedHelpText.clear(); + } + + // traverse children + traverse(test); + } +} + +bool HelpCompiler::compile( void ) throw( HelpProcessingException ) +{ + // we now have the jaroutputstream, which will contain the document. + // now determine the document as a dom tree in variable docResolved + + xmlDocPtr docResolvedOrg = getSourceDocument(inputFile); + + // now add path to the document + // resolve the dom + if (!docResolvedOrg) + { + impl_sleep( 3 ); + docResolvedOrg = getSourceDocument(inputFile); + if( !docResolvedOrg ) + { + std::stringstream aStrStream; + aStrStream << "ERROR: file not existing: " << inputFile.native_file_string().c_str() << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + } + + // now find all applications for which one has to compile + std::string documentId; + std::string fileName; + std::string title; + // returns all applications for which one has to compile + HashSet applications = switchFind(docResolvedOrg); + + HashSet::const_iterator aEnd = applications.end(); + for (HashSet::const_iterator aI = applications.begin(); aI != aEnd; ++aI) + { + std::string appl = *aI; + std::string modulename = appl; + if (modulename[0] == 'S') + { + modulename = modulename.substr(1); + std::transform(modulename.begin(), modulename.end(), modulename.begin(), tolower); + } + if (modulename != "DEFAULT" && modulename != module) + continue; + + // returns a clone of the document with swich-cases resolved + xmlNodePtr docResolved = clone(xmlDocGetRootElement(docResolvedOrg), appl); + myparser aparser(documentId, fileName, title); + aparser.traverse(docResolved); + + documentId = aparser.documentId; + fileName = aparser.fileName; + title = aparser.title; + + HCDBG(std::cerr << documentId << " : " << fileName << " : " << title << std::endl); + + xmlDocPtr docResolvedDoc = xmlCopyDoc(docResolvedOrg, false); + xmlDocSetRootElement(docResolvedDoc, docResolved); + + if (modulename == "DEFAULT") + { + streamTable.dropdefault(); + streamTable.default_doc = docResolvedDoc; + streamTable.default_hidlist = aparser.hidlist; + streamTable.default_helptexts = aparser.helptexts; + streamTable.default_keywords = aparser.keywords; + } + else if (modulename == module) + { + streamTable.dropappl(); + streamTable.appl_doc = docResolvedDoc; + streamTable.appl_hidlist = aparser.hidlist; + streamTable.appl_helptexts = aparser.helptexts; + streamTable.appl_keywords = aparser.keywords; + } + else + { + std::stringstream aStrStream; + aStrStream << "ERROR: Found unexpected module name \"" << modulename + << "\" in file" << src.native_file_string().c_str() << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + + } // end iteration over all applications + + streamTable.document_id = documentId; + streamTable.document_path = fileName; + streamTable.document_title = title; + std::string actMod = module; + if ( !bExtensionMode && !fileName.empty()) + { + if (fileName.find("/text/") == 0) + { + int len = strlen("/text/"); + actMod = fileName.substr(len); + actMod = actMod.substr(0, actMod.find('/')); + } + } + streamTable.document_module = actMod; + + xmlFreeDoc(docResolvedOrg); + return true; +} + +namespace fs +{ + rtl_TextEncoding getThreadTextEncoding( void ) + { + static bool bNeedsInit = true; + static rtl_TextEncoding nThreadTextEncoding; + if( bNeedsInit ) + { + bNeedsInit = false; + nThreadTextEncoding = osl_getThreadTextEncoding(); + } + return nThreadTextEncoding; + } + + void create_directory(const fs::path indexDirName) + { + HCDBG( + std::cerr << "creating " << + rtl::OUStringToOString(indexDirName.data, RTL_TEXTENCODING_UTF8).getStr() + << std::endl + ); + osl::Directory::createPath(indexDirName.data); + } + + void rename(const fs::path &src, const fs::path &dest) + { + osl::File::move(src.data, dest.data); + } + + void copy(const fs::path &src, const fs::path &dest) + { + osl::File::copy(src.data, dest.data); + } + + bool exists(const fs::path &in) + { + osl::File tmp(in.data); + return (tmp.open(osl_File_OpenFlag_Read) == osl::FileBase::E_None); + } + + void remove(const fs::path &in) + { + osl::File::remove(in.data); + } + + void removeRecursive(rtl::OUString const& _suDirURL) + { + { + osl::Directory aDir(_suDirURL); + aDir.open(); + if (aDir.isOpen()) + { + osl::DirectoryItem aItem; + osl::FileStatus aStatus(osl_FileStatus_Mask_FileName | osl_FileStatus_Mask_Attributes); + while (aDir.getNextItem(aItem) == ::osl::FileBase::E_None) + { + if (osl::FileBase::E_None == aItem.getFileStatus(aStatus) && + aStatus.isValid(osl_FileStatus_Mask_FileName | osl_FileStatus_Mask_Attributes)) + { + rtl::OUString suFilename = aStatus.getFileName(); + rtl::OUString suFullFileURL; + suFullFileURL += _suDirURL; + suFullFileURL += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/")); + suFullFileURL += suFilename; + + if (aStatus.getFileType() == osl::FileStatus::Directory) + removeRecursive(suFullFileURL); + else + osl::File::remove(suFullFileURL); + } + } + aDir.close(); + } + } + osl::Directory::remove(_suDirURL); + } + + void remove_all(const fs::path &in) + { + removeRecursive(in.data); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/help/HelpCompiler.hxx b/l10ntools/source/help/HelpCompiler.hxx new file mode 100644 index 000000000000..5b57b7fbe680 --- /dev/null +++ b/l10ntools/source/help/HelpCompiler.hxx @@ -0,0 +1,319 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef HELPCOMPILER_HXX +#define HELPCOMPILER_HXX + +#include <string> +#include <hash_map> +#include <vector> +#include <list> +#include <fstream> +#include <iostream> +#include <sstream> +#include <algorithm> +#include <ctype.h> +#ifdef SYSTEM_DB +#include <db.h> +#else +#include <berkeleydb/db.h> +#endif + +#include <boost/shared_ptr.hpp> + +#include <libxml/xmlmemory.h> +#include <libxml/debugXML.h> +#include <libxml/HTMLtree.h> +#include <libxml/xmlIO.h> +#include <libxml/xinclude.h> +#include <libxml/catalog.h> + +#include <rtl/ustring.hxx> +#include <osl/thread.h> +#include <osl/process.h> +#include <osl/file.hxx> + +#include <compilehelp.hxx> + +#define EMULATEORIGINAL 1 + +#ifdef CMCDEBUG + #define HCDBG(foo) do { if (1) foo; } while(0) +#else + #define HCDBG(foo) do { if (0) foo; } while(0) +#endif + +namespace fs +{ + rtl_TextEncoding getThreadTextEncoding( void ); + + enum convert { native }; + class path + { + public: + ::rtl::OUString data; + public: + path() {} + path(const path &rOther) : data(rOther.data) {} + path(const std::string &in, convert) + { + rtl::OUString sWorkingDir; + osl_getProcessWorkingDir(&sWorkingDir.pData); + + rtl::OString tmp(in.c_str()); + rtl::OUString ustrSystemPath(rtl::OStringToOUString(tmp, getThreadTextEncoding())); + osl::File::getFileURLFromSystemPath(ustrSystemPath, data); + osl::File::getAbsoluteFileURL(sWorkingDir, data, data); + } + path(const std::string &FileURL) + { + rtl::OString tmp(FileURL.c_str()); + data = rtl::OStringToOUString(tmp, getThreadTextEncoding()); + } + std::string native_file_string() const + { + ::rtl::OUString ustrSystemPath; + osl::File::getSystemPathFromFileURL(data, ustrSystemPath); + rtl::OString tmp(rtl::OUStringToOString(ustrSystemPath, getThreadTextEncoding())); + HCDBG(std::cerr << "native_file_string is " << tmp.getStr() << std::endl); + return std::string(tmp.getStr()); + } + std::string native_directory_string() const { return native_file_string(); } + std::string toUTF8() const + { + rtl::OString tmp(rtl::OUStringToOString(data, RTL_TEXTENCODING_UTF8)); + return std::string(tmp.getStr()); + } + bool empty() const { return data.getLength() == 0; } + path operator/(const std::string &in) const + { + path ret(*this); + HCDBG(std::cerr << "orig was " << + rtl::OUStringToOString(ret.data, RTL_TEXTENCODING_UTF8).getStr() << std::endl); + rtl::OString tmp(in.c_str()); + rtl::OUString ustrSystemPath(rtl::OStringToOUString(tmp, getThreadTextEncoding())); + ret.data += rtl::OUString(sal_Unicode('/')); + ret.data += ustrSystemPath; + HCDBG(std::cerr << "final is " << + rtl::OUStringToOString(ret.data, RTL_TEXTENCODING_UTF8).getStr() << std::endl); + return ret; + } + void append(const char *in) + { + rtl::OString tmp(in); + rtl::OUString ustrSystemPath(rtl::OStringToOUString(tmp, getThreadTextEncoding())); + data = data + ustrSystemPath; + } + void append(const std::string &in) { append(in.c_str()); } + }; + + void create_directory(const fs::path indexDirName); + void rename(const fs::path &src, const fs::path &dest); + void copy(const fs::path &src, const fs::path &dest); + bool exists(const fs::path &in); + void remove_all(const fs::path &in); + void remove(const fs::path &in); +} + +struct joaat_hash +{ + size_t operator()(const std::string &str) const + { + size_t hash = 0; + const char *key = str.data(); + for (size_t i = 0; i < str.size(); i++) + { + hash += key[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return hash; + } +}; + +#define get16bits(d) ((((sal_uInt32)(((const sal_uInt8 *)(d))[1])) << 8)\ + +(sal_uInt32)(((const sal_uInt8 *)(d))[0]) ) + +struct SuperFastHash +{ + size_t operator()(const std::string &str) const + { + const char * data = str.data(); + int len = str.size(); + size_t hash = len, tmp; + if (len <= 0 || data == NULL) return 0; + + int rem = len & 3; + len >>= 2; + + /* Main loop */ + for (;len > 0; len--) + { + hash += get16bits (data); + tmp = (get16bits (data+2) << 11) ^ hash; + hash = (hash << 16) ^ tmp; + data += 2*sizeof (sal_uInt16); + hash += hash >> 11; + } + + /* Handle end cases */ + switch (rem) + { + case 3: hash += get16bits (data); + hash ^= hash << 16; + hash ^= data[sizeof (sal_uInt16)] << 18; + hash += hash >> 11; + break; + case 2: hash += get16bits (data); + hash ^= hash << 11; + hash += hash >> 17; + break; + case 1: hash += *data; + hash ^= hash << 10; + hash += hash >> 1; + } + + /* Force "avalanching" of final 127 bits */ + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + + return hash; + } +}; + +#define pref_hash joaat_hash + +typedef std::hash_map<std::string, std::string, pref_hash> Stringtable; +typedef std::list<std::string> LinkedList; +typedef std::vector<std::string> HashSet; + +typedef std::hash_map<std::string, LinkedList, pref_hash> Hashtable; + +class StreamTable +{ +public: + std::string document_id; + std::string document_path; + std::string document_module; + std::string document_title; + + HashSet *appl_hidlist; + Hashtable *appl_keywords; + Stringtable *appl_helptexts; + xmlDocPtr appl_doc; + + HashSet *default_hidlist; + Hashtable *default_keywords; + Stringtable *default_helptexts; + xmlDocPtr default_doc; + + StreamTable() : + appl_hidlist(NULL), appl_keywords(NULL), appl_helptexts(NULL), appl_doc(NULL), + default_hidlist(NULL), default_keywords(NULL), default_helptexts(NULL), default_doc(NULL) + {} + void dropdefault() + { + delete default_hidlist; + delete default_keywords; + delete default_helptexts; + if (default_doc) xmlFreeDoc(default_doc); + } + void dropappl() + { + delete appl_hidlist; + delete appl_keywords; + delete appl_helptexts; + if (appl_doc) xmlFreeDoc(appl_doc); + } + ~StreamTable() + { + dropappl(); + dropdefault(); + } +}; + +struct HelpProcessingException +{ + HelpProcessingErrorClass m_eErrorClass; + std::string m_aErrorMsg; + std::string m_aXMLParsingFile; + int m_nXMLParsingLine; + + HelpProcessingException( HelpProcessingErrorClass eErrorClass, const std::string& aErrorMsg ) + : m_eErrorClass( eErrorClass ) + , m_aErrorMsg( aErrorMsg ) + , m_nXMLParsingLine( 0 ) + {} + HelpProcessingException( const std::string& aErrorMsg, const std::string& aXMLParsingFile, int nXMLParsingLine ) + : m_eErrorClass( HELPPROCESSING_XMLPARSING_ERROR ) + , m_aErrorMsg( aErrorMsg ) + , m_aXMLParsingFile( aXMLParsingFile ) + , m_nXMLParsingLine( nXMLParsingLine ) + {} +}; + +class HelpCompiler +{ +public: + HelpCompiler(StreamTable &streamTable, + const fs::path &in_inputFile, + const fs::path &in_src, + const fs::path &in_resEmbStylesheet, + const std::string &in_module, + const std::string &in_lang, + bool in_bExtensionMode); + bool compile( void ) throw (HelpProcessingException); + void addEntryToJarFile(const std::string &prefix, + const std::string &entryName, const std::string &bytesToAdd); + void addEntryToJarFile(const std::string &prefix, + const std::string &entryName, const HashSet &bytesToAdd); + void addEntryToJarFile(const std::string &prefix, + const std::string &entryName, const Stringtable &bytesToAdd); + void addEntryToJarFile(const std::string &prefix, + const std::string &entryName, const Hashtable &bytesToAdd); +private: + xmlDocPtr getSourceDocument(const fs::path &filePath); + HashSet switchFind(xmlDocPtr doc); + xmlNodePtr clone(xmlNodePtr node, const std::string& appl); + StreamTable &streamTable; + const fs::path inputFile, src; + const std::string module, lang; + const fs::path resEmbStylesheet; + bool bExtensionMode; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/help/HelpFileDocument.java b/l10ntools/source/help/HelpFileDocument.java new file mode 100644 index 000000000000..15e62d6c6c52 --- /dev/null +++ b/l10ntools/source/help/HelpFileDocument.java @@ -0,0 +1,86 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +package com.sun.star.help; + +import java.io.File; +import java.io.Reader; +import java.io.FileInputStream; +import java.io.InputStreamReader; +//import java.io.FileReader; +import java.io.StringReader; + +import org.apache.lucene.document.Document; +import org.apache.lucene.document.Field; + +/** Lucene Document for help files */ +public class HelpFileDocument +{ + /** Creates reader for UTF-8 files + */ + private static Reader getReaderForFile( File aFile ) + throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException { + Reader aReader; + if( aFile != null ) { + FileInputStream fis = new FileInputStream( aFile ); + aReader = new InputStreamReader( fis, "UTF-8" ); + } + else { + aReader = new StringReader( "" ); + } + return aReader; + } + + /** Makes a document for a File. + */ + public static Document Document( String aModule, File aCaptionFile, File aContentFile ) + throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException { + Document doc = new Document(); + + // Add the path of the file as a field named "path". Use a field that is + // indexed (i.e. searchable), but don't tokenize the field into words. + File aFile = aCaptionFile != null ? aCaptionFile : aContentFile; + if( aFile != null ) + { + String aPath = "#HLP#" + aModule + "/" + aFile.getName(); + doc.add(new Field("path", aPath, Field.Store.YES, Field.Index.UN_TOKENIZED)); + } + + // Add the caption of the file to a field named "caption". Specify a Reader, + // so that the text of the file is tokenized and indexed, but not stored. + doc.add( new Field( "caption", getReaderForFile( aCaptionFile ) ) ); + + // Add the contents of the file to a field named "content". Specify a Reader, + // so that the text of the file is tokenized and indexed, but not stored. + doc.add( new Field( "content", getReaderForFile( aContentFile ) ) ); + + // return the document + return doc; + } + + private HelpFileDocument() {} +} diff --git a/l10ntools/source/help/HelpIndexerTool.java b/l10ntools/source/help/HelpIndexerTool.java new file mode 100644 index 000000000000..a39b5399e38d --- /dev/null +++ b/l10ntools/source/help/HelpIndexerTool.java @@ -0,0 +1,401 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +package com.sun.star.help; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; +import java.util.zip.CRC32; +import org.apache.lucene.analysis.standard.StandardAnalyzer; +import org.apache.lucene.analysis.cjk.CJKAnalyzer; +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.index.IndexWriter; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Date; + +public class HelpIndexerTool +{ + public HelpIndexerTool() + { + } + + + /** + * @param args the command line arguments + */ + public static void main( String[] args ) + { + boolean bExtensionMode = false; + mainImpl( args, bExtensionMode ); + } + + public static void mainImpl( String[] args, boolean bExtensionMode ) + { + String aDirToZipStr = ""; + String aSrcDirStr = ""; + String aLanguageStr = ""; + String aModule = ""; + String aTargetZipFileStr = ""; + String aCfsName = ""; + String aSegmentName = ""; + + // Scan arguments + //If this tool is invoked in the build process for extensions help, + //then -extension must be set. + boolean bExtension = false; + boolean bLang = false; + boolean bMod = false; + boolean bZipDir = false; + boolean bSrcDir = false; + boolean bOutput = false; + boolean bCfsName = false; + boolean bSegmentName = false; + + int nArgCount = args.length; + for( int i = 0 ; i < nArgCount ; i++ ) + { + if( "-extension".equals(args[i]) ) + { + bExtension = true; + } + else if( "-lang".equals(args[i]) ) + { + if( i + 1 < nArgCount ) + { + aLanguageStr = args[i + 1]; + bLang = true; + } + i++; + } + else if( "-mod".equals(args[i]) ) + { + if( i + 1 < nArgCount ) + { + aModule = args[i + 1]; + bMod = true; + } + i++; + } + else if( "-zipdir".equals(args[i]) ) + { + if( i + 1 < nArgCount ) + { + aDirToZipStr = args[i + 1]; + bZipDir = true; + } + i++; + } + else if( "-srcdir".equals(args[i]) ) + { + if( i + 1 < nArgCount ) + { + aSrcDirStr = args[i + 1]; + bSrcDir = true; + } + i++; + } + else if( "-o".equals(args[i]) ) + { + if( i + 1 < nArgCount ) + { + aTargetZipFileStr = args[i + 1]; + bOutput = true; + } + i++; + } + else if( "-checkcfsandsegname".equals(args[i]) ) + { + if( i + 1 < nArgCount ) + { + aCfsName = args[i + 1] + ".cfs"; + bCfsName = true; + } + i++; + if( i + 1 < nArgCount ) + { + aSegmentName = "segments" + args[i + 1]; + bSegmentName = true; + } + i++; + if (!(bCfsName && bSegmentName)) + { + System.out.println("Usage: HelpIndexer -checkcfsandsegname _0 _3 (2 arguments needed)"); + System.exit( -1 ); + } + } + } + + if( !bLang || !bMod || !bZipDir || (!bOutput && !bExtensionMode && !bExtension) ) + { + if( bExtensionMode ) + return; + + System.out.println("Usage: HelpIndexer -lang ISOLangCode -mod HelpModule -zipdir TempZipDir -o OutputZipFile"); + System.out.println("Usage: HelpIndexer -extension -lang ISOLangCode -mod HelpModule -zipdir PathToLangDir"); + System.exit( -1 ); + } + + String aIndexDirName = aModule + ".idxl"; + File aIndexDir = new File( aDirToZipStr + File.separator + aIndexDirName ); + if( !bSrcDir ) + aSrcDirStr = aDirToZipStr; + File aCaptionFilesDir = new File( aSrcDirStr + File.separator + "caption" ); + File aContentFilesDir = new File( aSrcDirStr + File.separator + "content" ); + + try + { + Date start = new Date(); + Analyzer analyzer = aLanguageStr.equals("ja") ? (Analyzer)new CJKAnalyzer() : (Analyzer)new StandardAnalyzer(); + IndexWriter writer = new IndexWriter( aIndexDir, analyzer, true ); + if( !bExtensionMode ) + System.out.println( "Lucene: Indexing to directory '" + aIndexDir + "'..." ); + int nRet = indexDocs( writer, aModule, bExtensionMode, aCaptionFilesDir, aContentFilesDir ); + if( nRet != -1 ) + { + if( !bExtensionMode ) + { + System.out.println(); + System.out.println( "Optimizing ..." ); + } + writer.optimize(); + } + writer.close(); + + boolean bCfsFileOk = true; + boolean bSegmentFileOk = true; + if( bCfsName && bSegmentName && !bExtensionMode && nRet != -1 ) + { + String aCompleteCfsFileName = aDirToZipStr + File.separator + aIndexDirName + File.separator + aCfsName; + String aCompleteSegmentFileName = aDirToZipStr + File.separator + aIndexDirName + File.separator + aSegmentName; + File aCfsFile = new File( aCompleteCfsFileName ); + File aSegmentFile = new File( aCompleteSegmentFileName ); + bCfsFileOk = aCfsFile.exists(); + bSegmentFileOk = aSegmentFile.exists(); + System.out.println( "Checking cfs file " + aCfsName+ ": " + (bCfsFileOk ? "Found" : "Not found") ); + System.out.println( "Checking segment file " + aSegmentName+ ": " + (bSegmentFileOk ? "Found" : "Not found") ); + } + + if( bExtensionMode || bExtension) + { + if( !bSrcDir ) + { + deleteRecursively( aCaptionFilesDir ); + deleteRecursively( aContentFilesDir ); + } + } + else + { + if( nRet == -1 ) + deleteRecursively( aIndexDir ); + + if( bCfsFileOk && bSegmentFileOk ) + System.out.println( "Zipping ..." ); + File aDirToZipFile = new File( aDirToZipStr ); + createZipFile( aDirToZipFile, aTargetZipFileStr ); + deleteRecursively( aDirToZipFile ); + } + + if( !bCfsFileOk ) + { + System.out.println( "cfs file check failed, terminating..." ); + System.exit( -1 ); + } + + if( !bSegmentFileOk ) + { + System.out.println( "segment file check failed, terminating..." ); + System.exit( -1 ); + } + + Date end = new Date(); + if( !bExtensionMode ) + System.out.println(end.getTime() - start.getTime() + " total milliseconds"); + } + catch (IOException e) + { + if( bExtensionMode ) + return; + + System.out.println(" caught a " + e.getClass() + + "\n with message: " + e.getMessage()); + System.exit( -1 ); + } + } + + private static int indexDocs(IndexWriter writer, String aModule, boolean bExtensionMode, + File aCaptionFilesDir, File aContentFilesDir) throws IOException + { + if( !aCaptionFilesDir.canRead() || !aCaptionFilesDir.isDirectory() ) + { + if( !bExtensionMode ) + System.out.println( "Not found: " + aCaptionFilesDir ); + return -1; + } + if( !aContentFilesDir.canRead() || !aContentFilesDir.isDirectory() ) + { + if( !bExtensionMode ) + System.out.println( "Not found: " + aContentFilesDir ); + return -1; + } + + String[] aCaptionFiles = aCaptionFilesDir.list(); + List aCaptionFilesList = Arrays.asList( aCaptionFiles ); + HashSet aCaptionFilesHashSet = new HashSet( aCaptionFilesList ); + + String[] aContentFiles = aContentFilesDir.list(); + List aContentFilesList = Arrays.asList( aContentFiles ); + HashSet aContentFilesHashSet = new HashSet( aContentFilesList ); + + // Loop over caption files and find corresponding content file + if( !bExtensionMode ) + System.out.println( "Indexing, adding files" ); + int nCaptionFilesLen = aCaptionFiles.length; + for( int i = 0 ; i < nCaptionFilesLen ; i++ ) + { + String aCaptionFileStr = aCaptionFiles[i]; + File aCaptionFile = new File( aCaptionFilesDir, aCaptionFileStr ); + File aContentFile = null; + if( aContentFilesHashSet.contains( aCaptionFileStr ) ) + aContentFile = new File( aContentFilesDir, aCaptionFileStr ); + + if( !bExtensionMode ) + System.out.print( "." ); + writer.addDocument( HelpFileDocument.Document( aModule, aCaptionFile, aContentFile ) ); + } + + // Loop over content files to find remaining files not mapped to caption files + int nContentFilesLen = aContentFiles.length; + for( int i = 0 ; i < nContentFilesLen ; i++ ) + { + String aContentFileStr = aContentFiles[i]; + if( !aCaptionFilesHashSet.contains( aContentFileStr ) ) + { + // Not already handled in caption files loop + File aCaptionFile = null; + File aContentFile = new File( aContentFilesDir, aContentFileStr ); + if( !bExtensionMode ) + System.out.print( "." ); + writer.addDocument( HelpFileDocument.Document( aModule, aCaptionFile, aContentFile ) ); + } + } + return 0; + } + + public static void createZipFile( File aDirToZip, String aTargetZipFileStr ) + throws FileNotFoundException, IOException + { + FileOutputStream fos = new FileOutputStream( aTargetZipFileStr ); + ZipOutputStream zos = new ZipOutputStream( fos ); + + File[] aChildrenFiles = aDirToZip.listFiles(); + int nFileCount = aChildrenFiles.length; + for( int i = 0 ; i < nFileCount ; i++ ) + addToZipRecursively( zos, aChildrenFiles[i], null ); + + zos.close(); + } + + public static void addToZipRecursively( ZipOutputStream zos, File aFile, String aBasePath ) + throws FileNotFoundException, IOException + { + if( aFile.isDirectory() ) + { + String aDirName = aFile.getName(); + if( aDirName.equalsIgnoreCase( "caption" ) || aDirName.equalsIgnoreCase( "content" ) ) + return; + + File[] aChildrenFiles = aFile.listFiles(); + String aNewBasePath = ""; + if( aBasePath != null ) + aNewBasePath += aBasePath + File.separator; + aNewBasePath += aDirName; + + int nFileCount = aChildrenFiles.length; + for( int i = 0 ; i < nFileCount ; i++ ) + addToZipRecursively( zos, aChildrenFiles[i], aNewBasePath ); + + return; + } + + // No directory + // read contents of file we are going to put in the zip + int fileLength = (int) aFile.length(); + FileInputStream fis = new FileInputStream( aFile ); + byte[] wholeFile = new byte[fileLength]; + int bytesRead = fis.read( wholeFile, 0, fileLength ); + fis.close(); + + String aFileName = aFile.getName(); + String aEntryName = ""; + if( aBasePath != null ) + aEntryName += aBasePath + "/"; + aEntryName += aFileName; + ZipEntry aZipEntry = new ZipEntry( aEntryName ); + aZipEntry.setTime( aFile.lastModified() ); + aZipEntry.setSize( fileLength ); + + int nMethod = ( aFileName.toLowerCase().endsWith( ".jar" ) ) + ? ZipEntry.STORED : ZipEntry.DEFLATED; + aZipEntry.setMethod( nMethod ); + + CRC32 tempCRC = new CRC32(); + tempCRC.update( wholeFile, 0, wholeFile.length ); + aZipEntry.setCrc( tempCRC.getValue() ); + + // write the contents into the zip element + zos.putNextEntry( aZipEntry ); + zos.write( wholeFile, 0, fileLength ); + zos.closeEntry(); + } + + static public boolean deleteRecursively( File aFile ) + { + if( aFile.isDirectory() ) + { + File[] aChildrenFiles = aFile.listFiles(); + int nFileCount = aChildrenFiles.length; + for( int i = 0 ; i < nFileCount ; i++ ) + { + File aChildrenFile = aChildrenFiles[i]; + boolean bSuccess = deleteRecursively( aChildrenFile ); + if( !bSuccess ) + return false; + } + } + + return aFile.delete(); + } +} + diff --git a/l10ntools/source/help/HelpLinker.cxx b/l10ntools/source/help/HelpLinker.cxx new file mode 100644 index 000000000000..c483507a8f45 --- /dev/null +++ b/l10ntools/source/help/HelpLinker.cxx @@ -0,0 +1,1229 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifdef AIX +# undef _THREAD_SAFE +#endif + +#include "HelpCompiler.hxx" + +#include <map> + +#include <string.h> +#include <limits.h> + +#include <libxslt/xslt.h> +#include <libxslt/transform.h> +#include <libxslt/xsltutils.h> +#include <libxslt/functions.h> +#include <libxslt/extensions.h> + +#include <sal/types.h> +#include <osl/time.h> +#include <rtl/bootstrap.hxx> + +#include <expat.h> + +#define DBHELP_ONLY + + +class IndexerPreProcessor +{ +private: + std::string m_aModuleName; + fs::path m_fsIndexBaseDir; + fs::path m_fsCaptionFilesDirName; + fs::path m_fsContentFilesDirName; + + xsltStylesheetPtr m_xsltStylesheetPtrCaption; + xsltStylesheetPtr m_xsltStylesheetPtrContent; + +public: + IndexerPreProcessor( const std::string& aModuleName, const fs::path& fsIndexBaseDir, + const fs::path& idxCaptionStylesheet, const fs::path& idxContentStylesheet ); + ~IndexerPreProcessor(); + + void processDocument( xmlDocPtr doc, const std::string& EncodedDocPath ); +}; + +IndexerPreProcessor::IndexerPreProcessor + ( const std::string& aModuleName, const fs::path& fsIndexBaseDir, + const fs::path& idxCaptionStylesheet, const fs::path& idxContentStylesheet ) + : m_aModuleName( aModuleName ) + , m_fsIndexBaseDir( fsIndexBaseDir ) +{ + m_fsCaptionFilesDirName = fsIndexBaseDir / "caption"; + fs::create_directory( m_fsCaptionFilesDirName ); + + m_fsContentFilesDirName = fsIndexBaseDir / "content"; + fs::create_directory( m_fsContentFilesDirName ); + + m_xsltStylesheetPtrCaption = xsltParseStylesheetFile + ((const xmlChar *)idxCaptionStylesheet.native_file_string().c_str()); + m_xsltStylesheetPtrContent = xsltParseStylesheetFile + ((const xmlChar *)idxContentStylesheet.native_file_string().c_str()); +} + +IndexerPreProcessor::~IndexerPreProcessor() +{ + if( m_xsltStylesheetPtrCaption ) + xsltFreeStylesheet( m_xsltStylesheetPtrCaption ); + if( m_xsltStylesheetPtrContent ) + xsltFreeStylesheet( m_xsltStylesheetPtrContent ); +} + + +std::string getEncodedPath( const std::string& Path ) +{ + rtl::OString aOStr_Path( Path.c_str() ); + rtl::OUString aOUStr_Path( rtl::OStringToOUString + ( aOStr_Path, fs::getThreadTextEncoding() ) ); + rtl::OUString aPathURL; + osl::File::getFileURLFromSystemPath( aOUStr_Path, aPathURL ); + rtl::OString aOStr_PathURL( rtl::OUStringToOString + ( aPathURL, fs::getThreadTextEncoding() ) ); + std::string aStdStr_PathURL( aOStr_PathURL.getStr() ); + return aStdStr_PathURL; +} + +void IndexerPreProcessor::processDocument + ( xmlDocPtr doc, const std::string &EncodedDocPath ) +{ + std::string aStdStr_EncodedDocPathURL = getEncodedPath( EncodedDocPath ); + + if( m_xsltStylesheetPtrCaption ) + { + xmlDocPtr resCaption = xsltApplyStylesheet( m_xsltStylesheetPtrCaption, doc, NULL ); + xmlNodePtr pResNodeCaption = resCaption->xmlChildrenNode; + if( pResNodeCaption ) + { + fs::path fsCaptionPureTextFile_docURL = m_fsCaptionFilesDirName / aStdStr_EncodedDocPathURL; + std::string aCaptionPureTextFileStr_docURL = fsCaptionPureTextFile_docURL.native_file_string(); + FILE* pFile_docURL = fopen( aCaptionPureTextFileStr_docURL.c_str(), "w" ); + if( pFile_docURL ) + { + fprintf( pFile_docURL, "%s\n", pResNodeCaption->content ); + fclose( pFile_docURL ); + } + } + xmlFreeDoc(resCaption); + } + + if( m_xsltStylesheetPtrContent ) + { + xmlDocPtr resContent = xsltApplyStylesheet( m_xsltStylesheetPtrContent, doc, NULL ); + xmlNodePtr pResNodeContent = resContent->xmlChildrenNode; + if( pResNodeContent ) + { + fs::path fsContentPureTextFile_docURL = m_fsContentFilesDirName / aStdStr_EncodedDocPathURL; + std::string aContentPureTextFileStr_docURL = fsContentPureTextFile_docURL.native_file_string(); + FILE* pFile_docURL = fopen( aContentPureTextFileStr_docURL.c_str(), "w" ); + if( pFile_docURL ) + { + fprintf( pFile_docURL, "%s\n", pResNodeContent->content ); + fclose( pFile_docURL ); + } + } + xmlFreeDoc(resContent); + } +} + +struct Data +{ + std::vector<std::string> _idList; + typedef std::vector<std::string>::const_iterator cIter; + + void append(const std::string &id) + { + _idList.push_back(id); + } + + std::string getString() const + { + std::string ret; + cIter aEnd = _idList.end(); + for (cIter aIter = _idList.begin(); aIter != aEnd; ++aIter) + ret += *aIter + ";"; + return ret; + } +}; + +void writeKeyValue_DBHelp( FILE* pFile, const std::string& aKeyStr, const std::string& aValueStr ) +{ + if( pFile == NULL ) + return; + char cLF = 10; + unsigned int nKeyLen = aKeyStr.length(); + unsigned int nValueLen = aValueStr.length(); + fprintf( pFile, "%x ", nKeyLen ); + if( nKeyLen > 0 ) + { + if (fwrite( aKeyStr.c_str(), 1, nKeyLen, pFile ) != nKeyLen) + fprintf(stderr, "fwrite to db failed\n"); + } + if (fprintf( pFile, " %x ", nValueLen ) < 0) + fprintf(stderr, "fwrite to db failed\n"); + if( nValueLen > 0 ) + { + if (fwrite( aValueStr.c_str(), 1, nValueLen, pFile ) != nValueLen) + fprintf(stderr, "fwrite to db failed\n"); + } + if (fprintf( pFile, "%c", cLF ) < 0) + fprintf(stderr, "fwrite to db failed\n"); +} + +class HelpKeyword +{ +private: + typedef std::hash_map<std::string, Data, pref_hash> DataHashtable; + DataHashtable _hash; + +public: + void insert(const std::string &key, const std::string &id) + { + Data &data = _hash[key]; + data.append(id); + } + + void dump(DB* table) + { + DataHashtable::const_iterator aEnd = _hash.end(); + for (DataHashtable::const_iterator aIter = _hash.begin(); aIter != aEnd; ++aIter) + { + const std::string &keystr = aIter->first; + DBT key; + memset(&key, 0, sizeof(key)); + key.data = const_cast<char*>(keystr.c_str()); + key.size = keystr.length(); + + const Data &data = aIter->second; + std::string str = data.getString(); + DBT value; + memset(&value, 0, sizeof(value)); + value.data = const_cast<char*>(str.c_str()); + value.size = str.length(); + + table->put(table, NULL, &key, &value, 0); + } + } + + void dump_DBHelp( const std::string& rFileName ) + { + FILE* pFile = fopen( rFileName.c_str(), "wb" ); + if( pFile == NULL ) + return; + + DataHashtable::const_iterator aEnd = _hash.end(); + for (DataHashtable::const_iterator aIter = _hash.begin(); aIter != aEnd; ++aIter) + writeKeyValue_DBHelp( pFile, aIter->first, aIter->second.getString() ); + + fclose( pFile ); + } +}; + +class HelpLinker +{ +public: + void main(std::vector<std::string> &args, +// std::string* pExtensionPath = NULL, const rtl::OUString* pOfficeHelpPath = NULL ) + std::string* pExtensionPath = NULL, + std::string* pDestination = NULL, + const rtl::OUString* pOfficeHelpPath = NULL ) + + throw( HelpProcessingException ); + + HelpLinker() + : init(true) + , m_pIndexerPreProcessor(NULL) + {} + ~HelpLinker() + { delete m_pIndexerPreProcessor; } + +private: + int locCount, totCount; + Stringtable additionalFiles; + HashSet helpFiles; + fs::path sourceRoot; + fs::path embeddStylesheet; + fs::path idxCaptionStylesheet; + fs::path idxContentStylesheet; + fs::path zipdir; + fs::path outputFile; + std::string extsource; + std::string extdestination; + std::string module; + std::string lang; + std::string hid; + std::string extensionPath; + std::string extensionDestination; + bool bExtensionMode; + fs::path indexDirName; + Stringtable hidlistTranslation; + fs::path indexDirParentName; + bool init; + IndexerPreProcessor* m_pIndexerPreProcessor; + void initIndexerPreProcessor(); + void link() throw( HelpProcessingException ); + void addBookmark( DB* dbBase, FILE* pFile_DBHelp, std::string thishid, + const std::string& fileB, const std::string& anchorB, + const std::string& jarfileB, const std::string& titleB ); +}; + +namespace URLEncoder +{ + static std::string encode(const std::string &rIn) + { + const char *good = "!$&'()*+,-.=@_"; + static const char hex[17] = "0123456789ABCDEF"; + + std::string result; + for (size_t i=0; i < rIn.length(); ++i) + { + unsigned char c = rIn[i]; + if (isalnum (c) || strchr (good, c)) + result += c; + else { + result += '%'; + result += hex[c >> 4]; + result += hex[c & 0xf]; + } + } + return result; + } +} + +void HelpLinker::addBookmark( DB* dbBase, FILE* pFile_DBHelp, std::string thishid, + const std::string& fileB, const std::string& anchorB, + const std::string& jarfileB, const std::string& titleB) +{ + HCDBG(std::cerr << "HelpLinker::addBookmark " << thishid << " " << + fileB << " " << anchorB << " " << jarfileB << " " << titleB << std::endl); + + std::string temp = thishid; + std::transform (temp.begin(), temp.end(), temp.begin(), toupper); + std::replace(temp.begin(), temp.end(), ':', '_'); + const std::string& translatedHid = hidlistTranslation[temp]; + if (!translatedHid.empty()) + thishid = translatedHid; + + thishid = URLEncoder::encode(thishid); + + DBT key; + memset(&key, 0, sizeof(key)); + key.data = const_cast<char*>(thishid.c_str()); + key.size = thishid.length(); + + int fileLen = fileB.length(); + if (!anchorB.empty()) + fileLen += (1 + anchorB.length()); + int dataLen = 1 + fileLen + 1 + jarfileB.length() + 1 + titleB.length(); + + std::vector<unsigned char> dataB(dataLen); + size_t i = 0; + dataB[i++] = static_cast<unsigned char>(fileLen); + for (size_t j = 0; j < fileB.length(); ++j) + dataB[i++] = fileB[j]; + if (!anchorB.empty()) + { + dataB[i++] = '#'; + for (size_t j = 0; j < anchorB.length(); ++j) + dataB[i++] = anchorB[j]; + } + dataB[i++] = static_cast<unsigned char>(jarfileB.length()); + for (size_t j = 0; j < jarfileB.length(); ++j) + dataB[i++] = jarfileB[j]; + + dataB[i++] = static_cast<unsigned char>(titleB.length()); + for (size_t j = 0; j < titleB.length(); ++j) + dataB[i++] = titleB[j]; + + DBT data; + memset(&data, 0, sizeof(data)); + data.data = &dataB[0]; + data.size = dataB.size(); + + if( dbBase != NULL ) + dbBase->put(dbBase, NULL, &key, &data, 0); + + if( pFile_DBHelp != NULL ) + { + std::string aValueStr( dataB.begin(), dataB.end() ); + writeKeyValue_DBHelp( pFile_DBHelp, thishid, aValueStr ); + } +} + +void HelpLinker::initIndexerPreProcessor() +{ + if( m_pIndexerPreProcessor ) + delete m_pIndexerPreProcessor; + std::string mod = module; + std::transform (mod.begin(), mod.end(), mod.begin(), tolower); + m_pIndexerPreProcessor = new IndexerPreProcessor( mod, indexDirParentName, + idxCaptionStylesheet, idxContentStylesheet ); +} + +/** +* +*/ +void HelpLinker::link() throw( HelpProcessingException ) +{ + bool bIndexForExtension = true; + + if( bExtensionMode ) + { + //indexDirParentName = sourceRoot; + indexDirParentName = extensionDestination; + } + else + { + indexDirParentName = zipdir; + fs::create_directory(indexDirParentName); + } + +#ifdef CMC_DEBUG + std::cerr << "will not delete tmpdir of " << indexDirParentName.native_file_string().c_str() << std::endl; +#endif + + std::string mod = module; + std::transform (mod.begin(), mod.end(), mod.begin(), tolower); + + // do the work here + // continue with introduction of the overall process thing into the + // here all hzip files will be worked on + std::string appl = mod; + if (appl[0] == 's') + appl = appl.substr(1); + + bool bUse_ = true; +#ifdef DBHELP_ONLY + if( !bExtensionMode ) + bUse_ = false; +#endif + + DB* helpText(0); +#ifndef DBHELP_ONLY + fs::path helpTextFileName(indexDirParentName / (mod + ".ht")); + db_create(&helpText,0,0); + helpText->open(helpText, NULL, helpTextFileName.native_file_string().c_str(), NULL, DB_BTREE, + DB_CREATE | DB_TRUNCATE, 0644); +#endif + + fs::path helpTextFileName_DBHelp(indexDirParentName / (mod + (bUse_ ? ".ht_" : ".ht"))); + FILE* pFileHelpText_DBHelp = fopen + ( helpTextFileName_DBHelp.native_file_string().c_str(), "wb" ); + + DB* dbBase(0); +#ifndef DBHELP_ONLY + fs::path dbBaseFileName(indexDirParentName / (mod + ".db")); + db_create(&dbBase,0,0); + dbBase->open(dbBase, NULL, dbBaseFileName.native_file_string().c_str(), NULL, DB_BTREE, + DB_CREATE | DB_TRUNCATE, 0644); +#endif + + fs::path dbBaseFileName_DBHelp(indexDirParentName / (mod + (bUse_ ? ".db_" : ".db"))); + FILE* pFileDbBase_DBHelp = fopen + ( dbBaseFileName_DBHelp.native_file_string().c_str(), "wb" ); + +#ifndef DBHELP_ONLY + DB* keyWord(0); + fs::path keyWordFileName(indexDirParentName / (mod + ".key")); + db_create(&keyWord,0,0); + keyWord->open(keyWord, NULL, keyWordFileName.native_file_string().c_str(), NULL, DB_BTREE, + DB_CREATE | DB_TRUNCATE, 0644); +#endif + + fs::path keyWordFileName_DBHelp(indexDirParentName / (mod + (bUse_ ? ".key_" : ".key"))); + + HelpKeyword helpKeyword; + + // catch HelpProcessingException to avoid locking data bases + try + { + + std::ifstream fileReader(hid.c_str()); + while (fileReader) + { + std::string key; + fileReader >> key; + std::transform (key.begin(), key.end(), key.begin(), toupper); + std::replace(key.begin(), key.end(), ':', '_'); + std::string data; + fileReader >> data; + if (!key.empty() && !data.empty()) + hidlistTranslation[key] = data; + } + fileReader.close(); + + // lastly, initialize the indexBuilder + if ( (!bExtensionMode || bIndexForExtension) && !helpFiles.empty()) + initIndexerPreProcessor(); + + if( !bExtensionMode ) + { +#ifndef OS2 // YD @TODO@ crashes libc runtime :-( + std::cout << "Making " << outputFile.native_file_string() << + " from " << helpFiles.size() << " input files" << std::endl; +#endif + } + + // here we start our loop over the hzip files. + HashSet::iterator end = helpFiles.end(); + for (HashSet::iterator iter = helpFiles.begin(); iter != end; ++iter) + { + if( !bExtensionMode ) + { + std::cout << "."; + std::cout.flush(); + } + + // process one file + // streamTable contains the streams in the hzip file + StreamTable streamTable; + const std::string &xhpFileName = *iter; + + if (!bExtensionMode && xhpFileName.rfind(".xhp") != xhpFileName.length()-4) + { + // only work on .xhp - files + std::cerr << + "ERROR: input list entry '" + << xhpFileName + << "' has the wrong extension (only files with extension .xhp " + << "are accepted)"; + continue; + } + + fs::path langsourceRoot(sourceRoot); + fs::path xhpFile; + + if( bExtensionMode ) + { + // langsourceRoot == sourceRoot for extensions + std::string xhpFileNameComplete( extensionPath ); + xhpFileNameComplete.append( '/' + xhpFileName ); + xhpFile = fs::path( xhpFileNameComplete ); + } + else + { + langsourceRoot.append('/' + lang + '/'); + xhpFile = fs::path(xhpFileName, fs::native); + } + + HelpCompiler hc( streamTable, xhpFile, langsourceRoot, + embeddStylesheet, module, lang, bExtensionMode ); + + HCDBG(std::cerr << "before compile of " << xhpFileName << std::endl); + bool success = hc.compile(); + HCDBG(std::cerr << "after compile of " << xhpFileName << std::endl); + + if (!success && !bExtensionMode) + { + std::stringstream aStrStream; + aStrStream << + "\nERROR: compiling help particle '" + << xhpFileName + << "' for language '" + << lang + << "' failed!"; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + + const std::string documentBaseId = streamTable.document_id; + std::string documentPath = streamTable.document_path; + if (documentPath.find("/") == 0) + documentPath = documentPath.substr(1); + + std::string documentJarfile = streamTable.document_module + ".jar"; + + std::string documentTitle = streamTable.document_title; + if (documentTitle.empty()) + documentTitle = "<notitle>"; + + const std::string& fileB = documentPath; + const std::string& jarfileB = documentJarfile; + std::string& titleB = documentTitle; + + // add once this as its own id. + addBookmark(dbBase, pFileDbBase_DBHelp, documentPath, fileB, std::string(), jarfileB, titleB); + + // first the database *.db + // ByteArrayInputStream bais = null; + // ObjectInputStream ois = null; + + const HashSet *hidlist = streamTable.appl_hidlist; + if (!hidlist) + hidlist = streamTable.default_hidlist; + if (hidlist && !hidlist->empty()) + { + // now iterate over all elements of the hidlist + HashSet::const_iterator aEnd = hidlist->end(); + for (HashSet::const_iterator hidListIter = hidlist->begin(); + hidListIter != aEnd; ++hidListIter) + { + std::string thishid = *hidListIter; + + std::string anchorB; + size_t index = thishid.rfind('#'); + if (index != std::string::npos) + { + anchorB = thishid.substr(1 + index); + thishid = thishid.substr(0, index); + } + addBookmark(dbBase, pFileDbBase_DBHelp, thishid, fileB, anchorB, jarfileB, titleB); + } + } + + // now the keywords + const Hashtable *anchorToLL = streamTable.appl_keywords; + if (!anchorToLL) + anchorToLL = streamTable.default_keywords; + if (anchorToLL && !anchorToLL->empty()) + { + std::string fakedHid = URLEncoder::encode(documentPath); + Hashtable::const_iterator aEnd = anchorToLL->end(); + for (Hashtable::const_iterator enumer = anchorToLL->begin(); + enumer != aEnd; ++enumer) + { + const std::string &anchor = enumer->first; + addBookmark(dbBase, pFileDbBase_DBHelp, documentPath, fileB, + anchor, jarfileB, titleB); + std::string totalId = fakedHid + "#" + anchor; + // std::cerr << hzipFileName << std::endl; + const LinkedList& ll = enumer->second; + LinkedList::const_iterator aOtherEnd = ll.end(); + for (LinkedList::const_iterator llIter = ll.begin(); + llIter != aOtherEnd; ++llIter) + { + helpKeyword.insert(*llIter, totalId); + } + } + + } + + // and last the helptexts + const Stringtable *helpTextHash = streamTable.appl_helptexts; + if (!helpTextHash) + helpTextHash = streamTable.default_helptexts; + if (helpTextHash && !helpTextHash->empty()) + { + Stringtable::const_iterator aEnd = helpTextHash->end(); + for (Stringtable::const_iterator helpTextIter = helpTextHash->begin(); + helpTextIter != aEnd; ++helpTextIter) + { + std::string helpTextId = helpTextIter->first; + const std::string& helpTextText = helpTextIter->second; + + std::string temp = helpTextId; + std::transform (temp.begin(), temp.end(), temp.begin(), toupper); + std::replace(temp.begin(), temp.end(), ':', '_'); + + const std::string& tHid = hidlistTranslation[temp]; + if (!tHid.empty()) + helpTextId = tHid; + helpTextId = URLEncoder::encode(helpTextId); + + DBT keyDbt; + memset(&keyDbt, 0, sizeof(keyDbt)); + keyDbt.data = const_cast<char*>(helpTextId.c_str()); + keyDbt.size = helpTextId.length(); + + DBT textDbt; + memset(&textDbt, 0, sizeof(textDbt)); + textDbt.data = const_cast<char*>(helpTextText.c_str()); + textDbt.size = helpTextText.length(); + + if( helpText != NULL ) + helpText->put(helpText, NULL, &keyDbt, &textDbt, 0); + + if( pFileHelpText_DBHelp != NULL ) + writeKeyValue_DBHelp( pFileHelpText_DBHelp, helpTextId, helpTextText ); + } + } + + //IndexerPreProcessor + if( !bExtensionMode || bIndexForExtension ) + { + // now the indexing + xmlDocPtr document = streamTable.appl_doc; + if (!document) + document = streamTable.default_doc; + if (document) + { + std::string temp = module; + std::transform (temp.begin(), temp.end(), temp.begin(), tolower); + m_pIndexerPreProcessor->processDocument(document, URLEncoder::encode(documentPath) ); + } + } + + } // while loop over hzip files ending + if( !bExtensionMode ) + std::cout << std::endl; + + } // try + catch( HelpProcessingException& ) + { + // catch HelpProcessingException to avoid locking data bases +#ifndef DBHELP_ONLY + helpText->close(helpText, 0); + dbBase->close(dbBase, 0); + keyWord->close(keyWord, 0); +#endif + if( pFileHelpText_DBHelp != NULL ) + fclose( pFileHelpText_DBHelp ); + if( pFileDbBase_DBHelp != NULL ) + fclose( pFileDbBase_DBHelp ); + throw; + } + +#ifndef DBHELP_ONLY + helpText->close(helpText, 0); + dbBase->close(dbBase, 0); + helpKeyword.dump(keyWord); + keyWord->close(keyWord, 0); +#endif + if( pFileHelpText_DBHelp != NULL ) + fclose( pFileHelpText_DBHelp ); + if( pFileDbBase_DBHelp != NULL ) + fclose( pFileDbBase_DBHelp ); + + helpKeyword.dump_DBHelp( keyWordFileName_DBHelp.native_file_string() ); + + if( !bExtensionMode ) + { + // New index + Stringtable::iterator aEnd = additionalFiles.end(); + for (Stringtable::iterator enumer = additionalFiles.begin(); enumer != aEnd; + ++enumer) + { + const std::string &additionalFileName = enumer->second; + const std::string &additionalFileKey = enumer->first; + + fs::path fsAdditionalFileName( additionalFileName, fs::native ); + std::string aNativeStr = fsAdditionalFileName.native_file_string(); + const char* pStr = aNativeStr.c_str(); + std::cerr << pStr; + + fs::path fsTargetName( indexDirParentName / additionalFileKey ); + + fs::copy( fsAdditionalFileName, fsTargetName ); + } + } + +/* + ///////////////////////////////////////////////////////////////////////// + /// remove temprary directory for index creation + ///////////////////////////////////////////////////////////////////////// +#ifndef CMC_DEBUG + if( !bExtensionMode ) + fs::remove_all( indexDirParentName ); +#endif +*/ +} + + +void HelpLinker::main( std::vector<std::string> &args, + std::string* pExtensionPath, std::string* pDestination, + const rtl::OUString* pOfficeHelpPath ) + throw( HelpProcessingException ) +{ + bExtensionMode = false; + helpFiles.clear(); + + if (args.size() > 0 && args[0][0] == '@') + { + std::vector<std::string> stringList; + std::string strBuf; + std::ifstream fileReader(args[0].substr(1).c_str()); + + while (fileReader) + { + std::string token; + fileReader >> token; + if (!token.empty()) + stringList.push_back(token); + } + fileReader.close(); + + args = stringList; + } + + size_t i = 0; + bool bSrcOption = false; + while (i < args.size()) + { + if (args[i].compare("-extlangsrc") == 0) + { + ++i; + if (i >= args.size()) + { + std::stringstream aStrStream; + aStrStream << "extension source missing" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + extsource = args[i]; + } + else if (args[i].compare("-extlangdest") == 0) + { + //If this argument is not provided then the location provided in -extsource will + //also be the destination + ++i; + if (i >= args.size()) + { + std::stringstream aStrStream; + aStrStream << "extension destination missing" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + extdestination = args[i]; + } + else if (args[i].compare("-src") == 0) + { + ++i; + if (i >= args.size()) + { + std::stringstream aStrStream; + aStrStream << "sourceroot missing" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + bSrcOption = true; + sourceRoot = fs::path(args[i], fs::native); + } + else if (args[i].compare("-sty") == 0) + { + ++i; + if (i >= args.size()) + { + std::stringstream aStrStream; + aStrStream << "embeddingStylesheet missing" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + + embeddStylesheet = fs::path(args[i], fs::native); + } + else if (args[i].compare("-zipdir") == 0) + { + ++i; + if (i >= args.size()) + { + std::stringstream aStrStream; + aStrStream << "idxtemp missing" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + + zipdir = fs::path(args[i], fs::native); + } + else if (args[i].compare("-idxcaption") == 0) + { + ++i; + if (i >= args.size()) + { + std::stringstream aStrStream; + aStrStream << "idxcaption stylesheet missing" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + + idxCaptionStylesheet = fs::path(args[i], fs::native); + } + else if (args[i].compare("-idxcontent") == 0) + { + ++i; + if (i >= args.size()) + { + std::stringstream aStrStream; + aStrStream << "idxcontent stylesheet missing" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + + idxContentStylesheet = fs::path(args[i], fs::native); + } + else if (args[i].compare("-o") == 0) + { + ++i; + if (i >= args.size()) + { + std::stringstream aStrStream; + aStrStream << "outputfilename missing" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + + outputFile = fs::path(args[i], fs::native); + } + else if (args[i].compare("-mod") == 0) + { + ++i; + if (i >= args.size()) + { + std::stringstream aStrStream; + aStrStream << "module name missing" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + + module = args[i]; + } + else if (args[i].compare("-lang") == 0) + { + ++i; + if (i >= args.size()) + { + std::stringstream aStrStream; + aStrStream << "language name missing" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + + lang = args[i]; + } + else if (args[i].compare("-hid") == 0) + { + ++i; + if (i >= args.size()) + { + std::stringstream aStrStream; + aStrStream << "hid list missing" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + + hid = args[i]; + } + else if (args[i].compare("-add") == 0) + { + std::string addFile, addFileUnderPath; + ++i; + if (i >= args.size()) + { + std::stringstream aStrStream; + aStrStream << "pathname missing" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + + addFileUnderPath = args[i]; + ++i; + if (i >= args.size()) + { + std::stringstream aStrStream; + aStrStream << "pathname missing" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + addFile = args[i]; + if (!addFileUnderPath.empty() && !addFile.empty()) + additionalFiles[addFileUnderPath] = addFile; + } + else + helpFiles.push_back(args[i]); + ++i; + } + + //We can be called from the helplinker executable or the extension manager + //In the latter case extsource is not used. + if( (pExtensionPath && pExtensionPath->length() > 0 && pOfficeHelpPath) + || !extsource.empty()) + { + bExtensionMode = true; + if (!extsource.empty()) + { + //called from helplinker.exe, pExtensionPath and pOfficeHelpPath + //should be NULL + sourceRoot = fs::path(extsource, fs::native); + extensionPath = sourceRoot.toUTF8(); + + if (extdestination.empty()) + { + std::stringstream aStrStream; + aStrStream << "-extlangdest is missing" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + else + { + //Convert from system path to file URL!!! + fs::path p(extdestination, fs::native); + extensionDestination = p.toUTF8(); + } + } + else + { //called from extension manager + extensionPath = *pExtensionPath; + sourceRoot = fs::path(extensionPath); + extensionDestination = *pDestination; + } + //check if -src option was used. This option must not be used + //when extension help is compiled. + if (bSrcOption) + { + std::stringstream aStrStream; + aStrStream << "-src must not be used together with -extsource missing" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + } + + if (!bExtensionMode && zipdir.empty()) + { + std::stringstream aStrStream; + aStrStream << "no index dir given" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + + if ( (!bExtensionMode && idxCaptionStylesheet.empty()) + || (!extsource.empty() && idxCaptionStylesheet.empty()) ) + { + //No extension mode and extension mode using commandline + //!extsource.empty indicates extension mode using commandline + // -idxcaption paramter is required + std::stringstream aStrStream; + aStrStream << "no index caption stylesheet given" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + else if ( bExtensionMode && extsource.empty()) + { + //This part is used when compileExtensionHelp is called from the extensions manager. + //If extension help is compiled using helplinker in the build process + rtl::OUString aIdxCaptionPathFileURL( *pOfficeHelpPath ); + aIdxCaptionPathFileURL += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/idxcaption.xsl")); + + rtl::OString aOStr_IdxCaptionPathFileURL( rtl::OUStringToOString + ( aIdxCaptionPathFileURL, fs::getThreadTextEncoding() ) ); + std::string aStdStr_IdxCaptionPathFileURL( aOStr_IdxCaptionPathFileURL.getStr() ); + + idxCaptionStylesheet = fs::path( aStdStr_IdxCaptionPathFileURL ); + } + + if ( (!bExtensionMode && idxContentStylesheet.empty()) + || (!extsource.empty() && idxContentStylesheet.empty()) ) + { + //No extension mode and extension mode using commandline + //!extsource.empty indicates extension mode using commandline + // -idxcontent paramter is required + std::stringstream aStrStream; + aStrStream << "no index content stylesheet given" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + else if ( bExtensionMode && extsource.empty()) + { + //If extension help is compiled using helplinker in the build process + //then -idxcontent must be supplied + //This part is used when compileExtensionHelp is called from the extensions manager. + rtl::OUString aIdxContentPathFileURL( *pOfficeHelpPath ); + aIdxContentPathFileURL += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/idxcontent.xsl")); + + rtl::OString aOStr_IdxContentPathFileURL( rtl::OUStringToOString + ( aIdxContentPathFileURL, fs::getThreadTextEncoding() ) ); + std::string aStdStr_IdxContentPathFileURL( aOStr_IdxContentPathFileURL.getStr() ); + + idxContentStylesheet = fs::path( aStdStr_IdxContentPathFileURL ); + } + if (!bExtensionMode && embeddStylesheet.empty()) + { + std::stringstream aStrStream; + aStrStream << "no embedding resolving file given" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + if (sourceRoot.empty()) + { + std::stringstream aStrStream; + aStrStream << "no sourceroot given" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + if (!bExtensionMode && outputFile.empty()) + { + std::stringstream aStrStream; + aStrStream << "no output file given" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + if (module.empty()) + { + std::stringstream aStrStream; + aStrStream << "module missing" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + if (!bExtensionMode && lang.empty()) + { + std::stringstream aStrStream; + aStrStream << "language missing" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + if (!bExtensionMode && hid.empty()) + { + std::stringstream aStrStream; + aStrStream << "hid list missing" << std::endl; + throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() ); + } + + link(); +} + +int main(int argc, char**argv) +{ + sal_uInt32 starttime = osl_getGlobalTimer(); + std::vector<std::string> args; + for (int i = 1; i < argc; ++i) + args.push_back(std::string(argv[i])); + try + { + HelpLinker* pHelpLinker = new HelpLinker(); + pHelpLinker->main( args ); + delete pHelpLinker; + } + catch( const HelpProcessingException& e ) + { + std::cerr << e.m_aErrorMsg; + exit(1); + } + sal_uInt32 endtime = osl_getGlobalTimer(); +#ifndef OS2 // YD @TODO@ crashes libc runtime :-( + std::cout << "time taken was " << (endtime-starttime)/1000.0 << " seconds" << std::endl; +#endif + return 0; +} + +// Variable to set an exception in "C" StructuredXMLErrorFunction +static const HelpProcessingException* GpXMLParsingException = NULL; + +extern "C" void StructuredXMLErrorFunction(void *userData, xmlErrorPtr error) +{ + (void)userData; + (void)error; + + std::string aErrorMsg = error->message; + std::string aXMLParsingFile; + if( error->file != NULL ) + aXMLParsingFile = error->file; + int nXMLParsingLine = error->line; + HelpProcessingException* pException = new HelpProcessingException( aErrorMsg, aXMLParsingFile, nXMLParsingLine ); + GpXMLParsingException = pException; + + // Reset error handler + xmlSetStructuredErrorFunc( NULL, NULL ); +} + +HelpProcessingErrorInfo& HelpProcessingErrorInfo::operator=( const struct HelpProcessingException& e ) +{ + m_eErrorClass = e.m_eErrorClass; + rtl::OString tmpErrorMsg( e.m_aErrorMsg.c_str() ); + m_aErrorMsg = rtl::OStringToOUString( tmpErrorMsg, fs::getThreadTextEncoding() ); + rtl::OString tmpXMLParsingFile( e.m_aXMLParsingFile.c_str() ); + m_aXMLParsingFile = rtl::OStringToOUString( tmpXMLParsingFile, fs::getThreadTextEncoding() ); + m_nXMLParsingLine = e.m_nXMLParsingLine; + return *this; +} + + +// Returns true in case of success, false in case of error +HELPLINKER_DLLPUBLIC bool compileExtensionHelp +( + const rtl::OUString& aOfficeHelpPath, + const rtl::OUString& aExtensionName, + const rtl::OUString& aExtensionLanguageRoot, + sal_Int32 nXhpFileCount, const rtl::OUString* pXhpFiles, + const rtl::OUString& aDestination, + HelpProcessingErrorInfo& o_rHelpProcessingErrorInfo +) +{ + bool bSuccess = true; + + std::vector<std::string> args; + args.reserve(nXhpFileCount + 2); + args.push_back(std::string("-mod")); + rtl::OString aOExtensionName = rtl::OUStringToOString( aExtensionName, fs::getThreadTextEncoding() ); + args.push_back(std::string(aOExtensionName.getStr())); + + for( sal_Int32 iXhp = 0 ; iXhp < nXhpFileCount ; ++iXhp ) + { + rtl::OUString aXhpFile = pXhpFiles[iXhp]; + + rtl::OString aOXhpFile = rtl::OUStringToOString( aXhpFile, fs::getThreadTextEncoding() ); + args.push_back(std::string(aOXhpFile.getStr())); + } + + rtl::OString aOExtensionLanguageRoot = rtl::OUStringToOString( aExtensionLanguageRoot, fs::getThreadTextEncoding() ); + const char* pExtensionPath = aOExtensionLanguageRoot.getStr(); + std::string aStdStrExtensionPath = pExtensionPath; + rtl::OString aODestination = rtl::OUStringToOString(aDestination, fs::getThreadTextEncoding()); + const char* pDestination = aODestination.getStr(); + std::string aStdStrDestination = pDestination; + + // Set error handler + xmlSetStructuredErrorFunc( NULL, (xmlStructuredErrorFunc)StructuredXMLErrorFunction ); + try + { + HelpLinker* pHelpLinker = new HelpLinker(); + pHelpLinker->main( args, &aStdStrExtensionPath, &aStdStrDestination, &aOfficeHelpPath ); + delete pHelpLinker; + } + catch( const HelpProcessingException& e ) + { + if( GpXMLParsingException != NULL ) + { + o_rHelpProcessingErrorInfo = *GpXMLParsingException; + delete GpXMLParsingException; + GpXMLParsingException = NULL; + } + else + { + o_rHelpProcessingErrorInfo = e; + } + bSuccess = false; + } + // Reset error handler + xmlSetStructuredErrorFunc( NULL, NULL ); + + // i83624: Tree files + ::rtl::OUString aTreeFileURL = aExtensionLanguageRoot; + aTreeFileURL += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/help.tree")); + osl::DirectoryItem aTreeFileItem; + osl::FileBase::RC rcGet = osl::DirectoryItem::get( aTreeFileURL, aTreeFileItem ); + osl::FileStatus aFileStatus( FileStatusMask_FileSize ); + if( rcGet == osl::FileBase::E_None && + aTreeFileItem.getFileStatus( aFileStatus ) == osl::FileBase::E_None && + aFileStatus.isValid( FileStatusMask_FileSize ) ) + { + sal_uInt64 ret, len = aFileStatus.getFileSize(); + char* s = new char[ int(len) ]; // the buffer to hold the installed files + osl::File aFile( aTreeFileURL ); + aFile.open( osl_File_OpenFlag_Read ); + aFile.read( s, len, ret ); + aFile.close(); + + XML_Parser parser = XML_ParserCreate( 0 ); + int parsed = XML_Parse( parser, s, int( len ), true ); + + if( parsed == 0 ) + { + XML_Error nError = XML_GetErrorCode( parser ); + o_rHelpProcessingErrorInfo.m_eErrorClass = HELPPROCESSING_XMLPARSING_ERROR; + o_rHelpProcessingErrorInfo.m_aErrorMsg = rtl::OUString::createFromAscii( XML_ErrorString( nError ) );; + o_rHelpProcessingErrorInfo.m_aXMLParsingFile = aTreeFileURL; + // CRAHSES!!! o_rHelpProcessingErrorInfo.m_nXMLParsingLine = XML_GetCurrentLineNumber( parser ); + bSuccess = false; + } + + XML_ParserFree( parser ); + delete[] s; + } + + return bSuccess; +} + +// vnd.sun.star.help://swriter/52821?Language=en-US&System=UNIX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/help/compilehelp.hxx b/l10ntools/source/help/compilehelp.hxx new file mode 100644 index 000000000000..b81ddfbdadf2 --- /dev/null +++ b/l10ntools/source/help/compilehelp.hxx @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef COMPILE_HXX +#define COMPILE_HXX + +#include "sal/types.h" + +#if defined(HELPLINKER_DLLIMPLEMENTATION) +#define HELPLINKER_DLLPUBLIC SAL_DLLPUBLIC_EXPORT +#else +#define HELPLINKER_DLLPUBLIC SAL_DLLPUBLIC_IMPORT +#endif +#define HELPLINKER_DLLPRIVATE SAL_DLLPRIVATE + +#include <rtl/ustring.hxx> + +enum HelpProcessingErrorClass +{ + HELPPROCESSING_NO_ERROR, + HELPPROCESSING_GENERAL_ERROR, // Missing files, options etc. + HELPPROCESSING_INTERNAL_ERROR, // Unexpected problems + HELPPROCESSING_XMLPARSING_ERROR // Errors thrown by libxml +}; + +struct HelpProcessingErrorInfo +{ + HelpProcessingErrorClass m_eErrorClass; + rtl::OUString m_aErrorMsg; + rtl::OUString m_aXMLParsingFile; + sal_Int32 m_nXMLParsingLine; + + HelpProcessingErrorInfo( void ) + : m_eErrorClass( HELPPROCESSING_NO_ERROR ) + , m_nXMLParsingLine( -1 ) + {} + + HelpProcessingErrorInfo& operator=( const struct HelpProcessingException& e ); +}; + + +// Returns true in case of success, false in case of error +HELPLINKER_DLLPUBLIC bool compileExtensionHelp +( + const rtl::OUString& aOfficeHelpPath, + const rtl::OUString& aExtensionName, + const rtl::OUString& aExtensionLanguageRoot, + sal_Int32 nXhpFileCount, const rtl::OUString* pXhpFiles, + const rtl::OUString& aDestination, + HelpProcessingErrorInfo& o_rHelpProcessingErrorInfo +); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/help/helplinker.pmk b/l10ntools/source/help/helplinker.pmk new file mode 100644 index 000000000000..6e99d322f434 --- /dev/null +++ b/l10ntools/source/help/helplinker.pmk @@ -0,0 +1,31 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +# define HELPLINKER_DLLIMPLEMENTATION (see @ inc/xmlhelp/helplinkerdllapi.h) +CDEFS += -DHELPLINKER_DLLIMPLEMENTATION + +VISIBILITY_HIDDEN=TRUE diff --git a/l10ntools/source/help/makefile.mk b/l10ntools/source/help/makefile.mk new file mode 100644 index 000000000000..b66077501a8d --- /dev/null +++ b/l10ntools/source/help/makefile.mk @@ -0,0 +1,116 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/.. +PRJNAME = l10ntools +TARGET = HelpLinker +LIBBASENAME = helplinker +PACKAGE = com$/sun$/star$/help +TARGETTYPE=CUI + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : helplinker.pmk + +.IF "$(SYSTEM_LIBXSLT)" == "YES" +CFLAGS+= $(LIBXSLT_CFLAGS) +.ELSE +LIBXSLTINCDIR=external$/libxslt +CFLAGS+= -I$(SOLARINCDIR)$/$(LIBXSLTINCDIR) +.ENDIF + +.IF "$(SYSTEM_DB)" == "YES" +CFLAGS+=-DSYSTEM_DB -I$(DB_INCLUDES) +.ENDIF + +.IF "$(SYSTEM_EXPAT)" == "YES" +CFLAGS+=-DSYSTEM_EXPAT +.ENDIF + +OBJFILES=\ + $(OBJ)$/HelpLinker.obj \ + $(OBJ)$/HelpCompiler.obj +SLOFILES=\ + $(SLO)$/HelpLinker.obj \ + $(SLO)$/HelpCompiler.obj + +EXCEPTIONSFILES=\ + $(OBJ)$/HelpLinker.obj \ + $(OBJ)$/HelpCompiler.obj \ + $(SLO)$/HelpLinker.obj \ + $(SLO)$/HelpCompiler.obj +.IF "$(OS)" == "MACOSX" && "$(CPU)" == "P" && "$(COM)" == "GCC" +# There appears to be a GCC 4.0.1 optimization error causing _file:good() to +# report true right before the call to writeOut at HelpLinker.cxx:1.12 l. 954 +# but out.good() to report false right at the start of writeOut at +# HelpLinker.cxx:1.12 l. 537: +NOOPTFILES=\ + $(OBJ)$/HelpLinker.obj \ + $(SLO)$/HelpLinker.obj +.ENDIF + +APP1TARGET= $(TARGET) +APP1OBJS=\ + $(OBJ)$/HelpLinker.obj \ + $(OBJ)$/HelpCompiler.obj + +APP1STDLIBS+=$(SALLIB) $(BERKELEYLIB) $(XSLTLIB) $(EXPATASCII3RDLIB) + +SHL1TARGET =$(LIBBASENAME)$(DLLPOSTFIX) +SHL1LIBS= $(SLB)$/$(TARGET).lib +SHL1IMPLIB =i$(LIBBASENAME) +SHL1DEF =$(MISC)$/$(SHL1TARGET).def +SHL1STDLIBS =$(SALLIB) $(BERKELEYLIB) $(XSLTLIB) $(EXPATASCII3RDLIB) +SHL1USE_EXPORTS =ordinal + +DEF1NAME =$(SHL1TARGET) +DEFLIB1NAME =$(TARGET) + +JAVAFILES = \ + HelpIndexerTool.java \ + HelpFileDocument.java + + +JAVACLASSFILES = \ + $(CLASSDIR)$/$(PACKAGE)$/HelpIndexerTool.class \ + $(CLASSDIR)$/$(PACKAGE)$/HelpFileDocument.class + +.IF "$(SYSTEM_LUCENE)" == "YES" +EXTRAJARFILES += $(LUCENE_CORE_JAR) $(LUCENE_ANALYZERS_JAR) +.ELSE +JARFILES += lucene-core-2.3.jar lucene-analyzers-2.3.jar +.ENDIF +JAVAFILES = $(subst,$(CLASSDIR)$/$(PACKAGE)$/, $(subst,.class,.java $(JAVACLASSFILES))) + +JARCLASSDIRS = $(PACKAGE)/* +JARTARGET = HelpIndexerTool.jar +JARCOMPRESS = TRUE + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/l10ntools/source/helpex.cxx b/l10ntools/source/helpex.cxx new file mode 100644 index 000000000000..abe5acd41024 --- /dev/null +++ b/l10ntools/source/helpex.cxx @@ -0,0 +1,293 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_l10ntools.hxx" +#include <stdio.h> +#include <stdlib.h> + +// local includes +#include "helpmerge.hxx" + +// defines to parse command line +#define STATE_NON 0x0001 +#define STATE_INPUT 0x0002 +#define STATE_OUTPUT 0x0003 +#define STATE_PRJ 0x0004 +#define STATE_ROOT 0x0005 +#define STATE_SDFFILE 0x0006 +#define STATE_ERRORLOG 0x0007 +#define STATE_BREAKHELP 0x0008 +#define STATE_UNMERGE 0x0009 +#define STATE_UTF8 0x000A +#define STATE_LANGUAGES 0x000B +#define STATE_FORCE_LANGUAGES 0x000C +#define STATE_OUTPUTX 0xfe +#define STATE_OUTPUTY 0xff + +// set of global variables +ByteString sInputFile; +BOOL bEnableExport; +BOOL bMergeMode; +BOOL bErrorLog; +BOOL bUTF8; +ByteString sPrj; +ByteString sPrjRoot; +ByteString sOutputFile; +ByteString sOutputFileX; +ByteString sOutputFileY; +ByteString sSDFFile; + +/*****************************************************************************/ +BOOL ParseCommandLine( int argc, char* argv[]) +/*****************************************************************************/ +{ + bEnableExport = FALSE; + bMergeMode = FALSE; + bErrorLog = TRUE; + bUTF8 = TRUE; + sPrj = ""; + sPrjRoot = ""; + Export::sLanguages = ""; + Export::sForcedLanguages = ""; + + USHORT nState = STATE_NON; + BOOL bInput = FALSE; + + // parse command line + for( int i = 1; i < argc; i++ ) { + if ( ByteString( argv[ i ]).ToUpperAscii() == "-I" ) { + nState = STATE_INPUT; // next tokens specifies source files + } + else if ( ByteString( argv[ i ]).ToUpperAscii() == "-O" ) { + nState = STATE_OUTPUT; // next token specifies the dest file + } + else if ( ByteString( argv[ i ]).ToUpperAscii() == "-X" ) { + nState = STATE_OUTPUTX; // next token specifies the dest file + } + else if ( ByteString( argv[ i ]).ToUpperAscii() == "-Y" ) { + nState = STATE_OUTPUTY; // next token specifies the dest file + } + else if ( ByteString( argv[ i ]).ToUpperAscii() == "-P" ) { + nState = STATE_PRJ; // next token specifies the cur. project + } + else if ( ByteString( argv[ i ]).ToUpperAscii() == "-LF" ) { + nState = STATE_FORCE_LANGUAGES; + } + + else if ( ByteString( argv[ i ]).ToUpperAscii() == "-R" ) { + nState = STATE_ROOT; // next token specifies path to project root + } + else if ( ByteString( argv[ i ]).ToUpperAscii() == "-M" ) { + nState = STATE_SDFFILE; // next token specifies the merge database + } + else if ( ByteString( argv[ i ]).ToUpperAscii() == "-E" ) { + nState = STATE_ERRORLOG; + bErrorLog = FALSE; + } + else if ( ByteString( argv[ i ]).ToUpperAscii() == "-UTF8" ) { + nState = STATE_UTF8; + bUTF8 = TRUE; + } + else if ( ByteString( argv[ i ]).ToUpperAscii() == "-NOUTF8" ) { + nState = STATE_UTF8; + bUTF8 = FALSE; + } + else if ( ByteString( argv[ i ]).ToUpperAscii() == "-L" ) { + nState = STATE_LANGUAGES; + } + else { + switch ( nState ) { + case STATE_NON: { + return FALSE; // no valid command line + } + //break; + case STATE_INPUT: { + sInputFile = argv[ i ]; + bInput = TRUE; // source file found + } + break; + case STATE_OUTPUT: { + sOutputFile = argv[ i ]; // the dest. file + } + break; + case STATE_OUTPUTX: { + sOutputFileX = argv[ i ]; // the dest. file + } + break; + case STATE_OUTPUTY: { + sOutputFileY = argv[ i ]; // the dest. file + } + break; + case STATE_PRJ: { + sPrj = argv[ i ]; +// sPrj.ToLowerAscii(); // the project + } + break; + case STATE_ROOT: { + sPrjRoot = argv[ i ]; // path to project root + } + break; + case STATE_SDFFILE: { + sSDFFile = argv[ i ]; + bMergeMode = TRUE; // activate merge mode, cause merge database found + } + break; + case STATE_LANGUAGES: { + Export::sLanguages = argv[ i ]; + } + case STATE_FORCE_LANGUAGES:{ + Export::sForcedLanguages = argv[ i ]; + } + break; + } + } + } + + if ( bInput ) { + // command line is valid + bEnableExport = TRUE; + return TRUE; + } + + // command line is not valid + return FALSE; +} + + +/*****************************************************************************/ +void Help() +/*****************************************************************************/ +{ + fprintf( stdout, "Syntax: HELPEX[-p Prj][-r PrjRoot]-i FileIn ( -o FileOut | -x path -y relfile )[-m DataBase][-e][-b][-u][-L l1,l2,...] -LF l1,l2 \n" ); + fprintf( stdout, " Prj: Project\n" ); + fprintf( stdout, " PrjRoot: Path to project root (..\\.. etc.)\n" ); + fprintf( stdout, " FileIn: Source file (*.lng)\n" ); + fprintf( stdout, " FileOut: Destination file (*.*)\n" ); + fprintf( stdout, " DataBase: Mergedata (*.sdf)\n" ); + fprintf( stdout, " -L: Restrict the handled languages. l1,l2,... are elements of (en-US,fr,de...)\n" ); + fprintf( stdout, " A fallback language can be defined like this: l1=f1.\n" ); + fprintf( stdout, " f1, f2,... are also elements of (en-US,fr,de...)\n" ); + fprintf( stdout, " Example: -L fr=en-US\n" ); + fprintf( stdout, " Restriction to fr, en-US will be fallback for fr\n" ); + fprintf( stdout, " -LF: Force the creation of that languages\n" ); + +} + +/*****************************************************************************/ +#ifndef TESTDRIVER + +#if defined(UNX) || defined(OS2) +int main( int argc, char *argv[] ) +#else +int _cdecl main( int argc, char *argv[] ) +#endif +/*****************************************************************************/ +{ + + if ( !ParseCommandLine( argc, argv )) { + Help(); + return 1; + } + //sal_uInt32 startfull = Export::startMessure(); + + bool hasInputList = sInputFile.GetBuffer()[0]=='@'; +// printf("x = %s , y = %s , o = %s\n", sOutputFileX.GetBuffer(), sOutputFileY.GetBuffer() , sOutputFile.GetBuffer() ); + bool hasNoError = true; + + if ( sOutputFile.Len() ){ // Merge single file ? + //printf("DBG: Inputfile = %s\n",sInputFile.GetBuffer()); + HelpParser aParser( sInputFile, bUTF8 , false ); + + if ( bMergeMode ) + { + + //sal_uInt64 startreadloc = Export::startMessure(); + MergeDataFile aMergeDataFile( sSDFFile, sInputFile , FALSE, RTL_TEXTENCODING_MS_1252 ); + //MergeDataFile aMergeDataFile( sSDFFile, sInputFile , FALSE, RTL_TEXTENCODING_MS_1252, false ); + //Export::stopMessure( ByteString("read localize.sdf") , startreadloc ); + + hasNoError = aParser.Merge( sSDFFile, sOutputFile , Export::sLanguages , aMergeDataFile ); + } + else + hasNoError = aParser.CreateSDF( sOutputFile, sPrj, sPrjRoot, sInputFile, new XMLFile( '0' ), "help" ); + }else if ( sOutputFileX.Len() && sOutputFileY.Len() && hasInputList ) { // Merge multiple files ? + if ( bMergeMode ){ + + ifstream aFStream( sInputFile.Copy( 1 , sInputFile.Len() ).GetBuffer() , ios::in ); + + if( !aFStream ){ + cerr << "ERROR: - helpex - Can't open the file " << sInputFile.Copy( 1 , sInputFile.Len() ).GetBuffer() << "\n"; + exit(-1); + } + + vector<ByteString> filelist; + rtl::OStringBuffer filename; + sal_Char aChar; + while( aFStream.get( aChar ) ) + { + if( aChar == ' ' || aChar == '\n') + filelist.push_back( ByteString( filename.makeStringAndClear().getStr() ) ); + else + filename.append( aChar ); + } + if( filename.getLength() > 0 ) + filelist.push_back( ByteString ( filename.makeStringAndClear().getStr() ) ); + + aFStream.close(); + ByteString sHelpFile(""); // dummy + //MergeDataFile aMergeDataFile( sSDFFile, sHelpFile , FALSE, RTL_TEXTENCODING_MS_1252, false ); + MergeDataFile aMergeDataFile( sSDFFile, sHelpFile , FALSE, RTL_TEXTENCODING_MS_1252 ); + + //aMergeDataFile.Dump(); + std::vector<ByteString> aLanguages; + HelpParser::parse_languages( aLanguages , aMergeDataFile ); + + bool bCreateDir = true; + for( vector<ByteString>::iterator pos = filelist.begin() ; pos != filelist.end() ; ++pos ) + { + sHelpFile = *pos; + cout << ".";cout.flush(); + + HelpParser aParser( sHelpFile , bUTF8 , true ); + hasNoError = aParser.Merge( sSDFFile , sOutputFileX , sOutputFileY , true , aLanguages , aMergeDataFile , bCreateDir ); + bCreateDir = false; + } + } + } else + cerr << "helpex ERROR: Wrong input parameters!\n"; + + //Export::stopMessure( ByteString("full cycle") , startfull ); + if( hasNoError ) + return 0; + else + return 1; +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/helpmerge.cxx b/l10ntools/source/helpmerge.cxx new file mode 100644 index 000000000000..d650f3b41e28 --- /dev/null +++ b/l10ntools/source/helpmerge.cxx @@ -0,0 +1,715 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_l10ntools.hxx" +#include <tools/fsys.hxx> +#include <osl/file.hxx> +// local includes +#include <stdio.h> +#include <stdlib.h> +#include "helpmerge.hxx" +#include "utf8conv.hxx" +#include <algorithm> +#include <sys/types.h> +#include <sys/stat.h> +#include <iostream> +#include <fstream> +#include <vector> +#include "rtl/strbuf.hxx" +#ifdef WNT +#include <direct.h> +#include "tools/prewin.h" +#include <windows.h> +#include "tools/postwin.h" +#endif + +/*****************************************************************************/ +void HelpParser::FillInFallbacks( LangHashMap& rElem_out, ByteString sLangIdx_in ){ +/*****************************************************************************/ + static const ByteString ENGLISH_LANGUAGECODE( "en-US" ); + static const ByteString GERMAN_LANGUAGECODE ( "de" ); + ByteString sCur; + XMLElement* pTmp = NULL; + XMLElement* pTmp2 = NULL; + + sCur = sLangIdx_in; + ByteString sFallback( sCur ); + GetIsoFallback( sFallback ); + if( (rElem_out.find( sFallback ) != rElem_out.end()) && rElem_out[ sFallback ] != NULL ){ + pTmp2 = rElem_out[ sFallback ]; + pTmp = new XMLElement( *pTmp2 ) ; // Copy + pTmp->SetPos( pTmp2->GetPos()+1 ); + pTmp->ChangeLanguageTag( String( sLangIdx_in , RTL_TEXTENCODING_ASCII_US) ); + rElem_out[ sLangIdx_in ] = pTmp; + pTmp2 = NULL; + } + else if( (rElem_out.find( ENGLISH_LANGUAGECODE ) != rElem_out.end()) && rElem_out[ ENGLISH_LANGUAGECODE ] != NULL ){// No English + pTmp2 = rElem_out[ ENGLISH_LANGUAGECODE ]; + pTmp = new XMLElement( *pTmp2 ) ; // Copy + pTmp->SetPos( pTmp2->GetPos()+1 ); + pTmp->ChangeLanguageTag( String( sLangIdx_in , RTL_TEXTENCODING_ASCII_US) ); + rElem_out[ sCur ] = pTmp; + pTmp2 = NULL; + } + else if( (rElem_out.find( GERMAN_LANGUAGECODE ) != rElem_out.end() ) && rElem_out[ GERMAN_LANGUAGECODE ] != NULL ){// No English + pTmp2 = rElem_out[ GERMAN_LANGUAGECODE ]; + pTmp = new XMLElement( *pTmp2 ); // Copy + pTmp->SetPos( pTmp2->GetPos()+1 ); + pTmp->ChangeLanguageTag( String( sLangIdx_in , RTL_TEXTENCODING_ASCII_US ) ); + rElem_out[ sCur ] = pTmp; + pTmp2 = NULL; + }else{ + fprintf(stdout,"ERROR: No Fallback found for language %s:\n",sCur.GetBuffer()); + rElem_out[ sCur ]=new XMLElement(); // Use dummy element + } +} + +/*****************************************************************************/ +void HelpParser::Dump(XMLHashMap* rElem_in) { +/*****************************************************************************/ + for(XMLHashMap::iterator pos = rElem_in->begin();pos != rElem_in->end(); ++pos){ + Dump(pos->second,pos->first); + } +} +/*****************************************************************************/ +void HelpParser::Dump(LangHashMap* rElem_in,const ByteString sKey_in) { +/*****************************************************************************/ + ByteString x; + OString y; + fprintf(stdout,"+------------%s-----------+\n",sKey_in.GetBuffer() ); + for(LangHashMap::iterator posn=rElem_in->begin();posn!=rElem_in->end();++posn){ + x=posn->first; + y=posn->second->ToOString(); + fprintf(stdout,"key=%s value=%s\n",x.GetBuffer(),y.getStr()); + } + fprintf(stdout,"+--------------------------+\n"); +} + +HelpParser::HelpParser( const ByteString &rHelpFile, bool rUTF8 , bool rHasInputList ) + : sHelpFile( rHelpFile ), + bUTF8 ( rUTF8 ), + bHasInputList( rHasInputList ) + {}; + +/*****************************************************************************/ +bool HelpParser::CreateSDF( +/*****************************************************************************/ + const ByteString &rSDFFile_in, const ByteString &rPrj_in,const ByteString &rRoot_in, + const ByteString &sHelpFile, XMLFile *pXmlFile, const ByteString &rGsi1){ + // GSI File constants + static const String GSI_SEQUENCE1( String::CreateFromAscii("\t0\t") ); + static const String GSI_SEQUENCE2( String::CreateFromAscii("\t\t\t0\t") ); + static const String GSI_TAB ( String::CreateFromAscii("\t") ); + static const String GSI_SEQUENCE4( String::CreateFromAscii("\t\t\t\t") ); + static const String ret ( String::CreateFromAscii("\n") ); + static const String ret_char ( String::CreateFromAscii("") ); + static const String tab ( String::CreateFromAscii("\t") ); + static const String tab_char ( String::CreateFromAscii("") ); + + SimpleXMLParser aParser; + String sUsedTempFile; + String sXmlFile; + + if( Export::fileHasUTF8ByteOrderMarker( sHelpFile ) ){ + DirEntry aTempFile = Export::GetTempFile(); + DirEntry aSourceFile( String( sHelpFile , RTL_TEXTENCODING_ASCII_US ) ); + aSourceFile.CopyTo( aTempFile , FSYS_ACTION_COPYFILE ); + String sTempFile = aTempFile.GetFull(); + Export::RemoveUTF8ByteOrderMarkerFromFile( ByteString( sTempFile , RTL_TEXTENCODING_ASCII_US ) ); + sUsedTempFile = sTempFile; + sXmlFile = sTempFile; + }else{ + sUsedTempFile = String::CreateFromAscii(""); + sXmlFile = String( sHelpFile , RTL_TEXTENCODING_ASCII_US ); + } + +// ByteString fullFilePath; + //DirEntry aFile( sXmlFile ); + //makeAbsolutePath( sHelpFile , rRoot_in); + ByteString fullFilePath = rPrj_in; + fullFilePath.Append( "\\" ); + fullFilePath.Append( makeAbsolutePath( sHelpFile , rRoot_in ) ); + fullFilePath.SearchAndReplaceAll( "\\", "/" ); + + String strFullPath( fullFilePath.GetBuffer() , RTL_TEXTENCODING_ASCII_US ); + + //printf( "%s\n", fullFilePath.GetBuffer() ); + std::auto_ptr <XMLFile> file ( aParser.Execute( strFullPath , sXmlFile, pXmlFile ) ); + + if(file.get() == NULL){ + printf("%s\n",ByteString(aParser.GetError().sMessage,RTL_TEXTENCODING_ASCII_US).GetBuffer()); + exit(-1); + //return false; + } + file->Extract(); + if( !file->CheckExportStatus() ){ + return true; + } + SvFileStream aSDFStream( String( rSDFFile_in, RTL_TEXTENCODING_ASCII_US ), + STREAM_STD_WRITE | STREAM_TRUNC ); + + if ( !aSDFStream.IsOpen()) { + fprintf(stdout,"Can't open file %s\n",rSDFFile_in.GetBuffer()); + return false; + } + + ByteString sActFileName = makeAbsolutePath( sHelpFile , rRoot_in ); + + XMLHashMap* aXMLStrHM = file->GetStrings(); + LangHashMap* pElem; + XMLElement* pXMLElement = NULL; + + //Dump(aXMLStrHM); + + ByteString sTimeStamp( Export::GetTimeStamp() ); + OUString sOUTimeStamp( sTimeStamp.GetBuffer() , sTimeStamp.Len() , RTL_TEXTENCODING_ASCII_US ); + + OUStringBuffer sBuffer; + const OUString sOUPrj( rPrj_in.GetBuffer() , rPrj_in.Len() , RTL_TEXTENCODING_ASCII_US ); + const OUString sOUActFileName(sActFileName.GetBuffer() , sActFileName.Len() , RTL_TEXTENCODING_ASCII_US ); + const OUString sOUGsi1( rGsi1.GetBuffer() , rGsi1.Len() , RTL_TEXTENCODING_ASCII_US ); + + Export::InitLanguages( false ); + std::vector<ByteString> aLanguages = Export::GetLanguages(); + + std::vector<ByteString> order = file->getOrder(); + std::vector<ByteString>::iterator pos; + XMLHashMap::iterator posm; + + for( pos = order.begin(); pos != order.end() ; ++pos ) + { + posm = aXMLStrHM->find( *pos ); + pElem = posm->second; + ByteString sCur; + + for( unsigned int n = 0; n < aLanguages.size(); n++ ) + { + sCur = aLanguages[ n ]; + if(pElem->find( sCur )==pElem->end()) + { + FillInFallbacks( *pElem , sCur ); + } + pXMLElement = (*pElem)[ sCur ]; + + if( pXMLElement != NULL ) + { + OUString data = pXMLElement->ToOUString(); + String sTmp = String(data.getStr()); + sTmp.SearchAndReplaceAll(ret,ret_char); // Remove \n + sTmp.SearchAndReplaceAll(tab,tab_char); // Remove \t + + data = OUString( sTmp ); + sBuffer.append( sOUPrj ); + sBuffer.append( GSI_TAB ); //"\t"; + if ( rRoot_in.Len()) + sBuffer.append( sOUActFileName ); + sBuffer.append( GSI_SEQUENCE1 ); //"\t0\t"; + sBuffer.append( sOUGsi1 ); //"help"; + sBuffer.append( GSI_TAB ); //"\t"; + ByteString sID = posm->first; // ID + sBuffer.append( OUString( sID.GetBuffer() , sID.Len() , RTL_TEXTENCODING_UTF8 ) ); + sBuffer.append( GSI_TAB ); //"\t"; + ByteString sOldRef = pXMLElement->GetOldref(); // oldref + sBuffer.append( OUString(sOldRef.GetBuffer() , sOldRef.Len() , RTL_TEXTENCODING_UTF8 ) ); + sBuffer.append( GSI_SEQUENCE2 ); //"\t\t\t0\t"; + sBuffer.append( OUString( sCur.GetBuffer() , sCur.Len() , RTL_TEXTENCODING_UTF8 ) ); + sBuffer.append( GSI_TAB ); //"\t"; + sBuffer.append( data ); + sBuffer.append( GSI_SEQUENCE4 ); //"\t\t\t\t"; + sBuffer.append( sOUTimeStamp ); + ByteString sOut( sBuffer.makeStringAndClear().getStr() , RTL_TEXTENCODING_UTF8 ); + //if( !sCur.EqualsIgnoreCaseAscii("de") ||( sCur.EqualsIgnoreCaseAscii("de") && !Export::isMergingGermanAllowed( rPrj_in ) ) ) + //{ + if( data.getLength() > 0 ) aSDFStream.WriteLine( sOut ); + //} + pXMLElement=NULL; + }else fprintf(stdout,"\nDBG: NullPointer in HelpParser::CreateSDF , Language %s\n",sCur.GetBuffer() ); + } + + } + //Dump(aXMLStrHM); + aSDFStream.Close(); + + if( !sUsedTempFile.EqualsIgnoreCaseAscii( "" ) ){ + DirEntry aTempFile( sUsedTempFile ); + aTempFile.Kill(); + } + return TRUE; +} + +ByteString HelpParser::makeAbsolutePath( const ByteString& sHelpFile , const ByteString& rRoot_in ) +{ + DirEntry aEntry( String( sHelpFile, RTL_TEXTENCODING_ASCII_US )); + aEntry.ToAbs(); + String sFullEntry = aEntry.GetFull(); + aEntry += DirEntry( String( "..", RTL_TEXTENCODING_ASCII_US )); + aEntry += DirEntry( rRoot_in ); + ByteString sPrjEntry( aEntry.GetFull(), gsl_getSystemTextEncoding()); + ByteString sActFileName( + sFullEntry.Copy( sPrjEntry.Len() + 1 ), gsl_getSystemTextEncoding()); + + sActFileName.SearchAndReplaceAll( "/", "\\" ); + return sActFileName; +} +bool HelpParser::Merge( const ByteString &rSDFFile, const ByteString &rDestinationFile , + ByteString& sLanguage , MergeDataFile& aMergeDataFile ) +{ + + (void) rSDFFile; + bool hasNoError = true; + + SimpleXMLParser aParser; + + String sUsedTempFile; + String sXmlFile; + + if( Export::fileHasUTF8ByteOrderMarker( sHelpFile ) ){ + DirEntry aTempFile = Export::GetTempFile(); + DirEntry aSourceFile( String( sHelpFile , RTL_TEXTENCODING_ASCII_US ) ); + aSourceFile.CopyTo( aTempFile , FSYS_ACTION_COPYFILE ); + String sTempFile = aTempFile.GetFull(); + Export::RemoveUTF8ByteOrderMarkerFromFile( ByteString( sTempFile , RTL_TEXTENCODING_ASCII_US ) ); + sUsedTempFile = sTempFile; + sXmlFile = sTempFile; + }else{ + sUsedTempFile = String::CreateFromAscii(""); + sXmlFile = String( sHelpFile , RTL_TEXTENCODING_ASCII_US ); + } + + OUString sOUHelpFile( sXmlFile ); + String fullFilePath; + DirEntry aFile( sXmlFile ); + + XMLFile* xmlfile = ( aParser.Execute( aFile.GetFull() , sOUHelpFile, new XMLFile( '0' ) ) ); + printf("Dest file %s\n",rDestinationFile.GetBuffer()); + hasNoError = MergeSingleFile( xmlfile , aMergeDataFile , sLanguage , rDestinationFile ); + delete xmlfile; + if( !sUsedTempFile.EqualsIgnoreCaseAscii( "" ) ){ + DirEntry aTempFile( sUsedTempFile ); + aTempFile.Kill(); + } + return hasNoError; +} + +bool ByteStringEqual( const ByteString& rKey1, const ByteString& rKey2 ) { + return rKey1.CompareTo( rKey2 )==COMPARE_EQUAL; +}; +bool ByteStringLess( const ByteString& rKey1, const ByteString& rKey2 ) { + return rKey1.CompareTo( rKey2 )==COMPARE_LESS; +} + +void HelpParser::parse_languages( std::vector<ByteString>& aLanguages , MergeDataFile& aMergeDataFile ){ + std::vector<ByteString> aTmp; + + const ByteString DE ("de"); + const ByteString ENUS ("en-US"); + static const ByteString ALL( "ALL" ); + + Export::InitLanguages( false ); + + if( Export::sLanguages.EqualsIgnoreCaseAscii( ALL ) ) + { + aLanguages = aMergeDataFile.GetLanguages(); + aLanguages.push_back( DE ); + aLanguages.push_back( ENUS ); + + if( !Export::sForcedLanguages.Equals("") ) + { + std::vector<ByteString> aFL = Export::GetForcedLanguages(); + std::copy( aFL.begin() , + aFL.end() , + back_inserter( aLanguages ) + ); + std::sort( aLanguages.begin() , aLanguages.end() , ByteStringLess ); + std::vector<ByteString>::iterator unique_iter = std::unique( aLanguages.begin() , aLanguages.end() , ByteStringEqual ); + std::copy( aLanguages.begin() , unique_iter , back_inserter( aTmp ) ); + aLanguages = aTmp; + } + } + else{ + aLanguages = Export::GetLanguages(); + } + +} + +bool HelpParser::Merge( + const ByteString &rSDFFile, const ByteString &rPathX , const ByteString &rPathY , bool bISO , + const std::vector<ByteString>& aLanguages , MergeDataFile& aMergeDataFile , bool bCreateDir ) +{ + + + (void) rSDFFile ; + bool hasNoError = true; + SimpleXMLParser aParser; + String sUsedTempFile; + String sXmlFile; + + if( Export::fileHasUTF8ByteOrderMarker( sHelpFile ) ) + { + DirEntry aTempFile = Export::GetTempFile(); + DirEntry aSourceFile( String( sHelpFile , RTL_TEXTENCODING_ASCII_US ) ); + aSourceFile.CopyTo( aTempFile , FSYS_ACTION_COPYFILE ); + String sTempFile = aTempFile.GetFull(); + Export::RemoveUTF8ByteOrderMarkerFromFile( ByteString( sTempFile , RTL_TEXTENCODING_ASCII_US ) ); + sUsedTempFile = sTempFile; + sXmlFile = sTempFile; + } + else + { + sUsedTempFile = String::CreateFromAscii(""); + sXmlFile = String( sHelpFile , RTL_TEXTENCODING_ASCII_US ); + } + + + OUString sOUHelpFile( sXmlFile ); + String fullFilePath; + DirEntry aFile( sXmlFile ); + + XMLFile* xmlfile = ( aParser.Execute( aFile.GetFull() , sOUHelpFile, new XMLFile( '0' ) ) ); + xmlfile->Extract(); + + if( xmlfile == NULL) + { + printf("%s\n",ByteString(aParser.GetError().sMessage,RTL_TEXTENCODING_UTF8).GetBuffer()); + exit(-1); + //return false; + } + + + ByteString sCur; + for( unsigned int n = 0; n < aLanguages.size(); n++ ){ + sCur = aLanguages[ n ]; + + ByteString sFilepath; + if( bISO ) sFilepath = GetOutpath( rPathX , sCur , rPathY ); + else sFilepath = rPathX; + if( bCreateDir ) MakeDir( sFilepath ); + + XMLFile* file = new XMLFile( *xmlfile ); + sFilepath.Append( sHelpFile ); + hasNoError = MergeSingleFile( file , aMergeDataFile , sCur , sFilepath ); + delete file; + + if( !hasNoError ) return false; // Stop on error + } + + if( !sUsedTempFile.EqualsIgnoreCaseAscii( "" ) ) + { + DirEntry aTempFile( sUsedTempFile ); + aTempFile.Kill(); + } + delete xmlfile; + return hasNoError; +} + +bool HelpParser::MergeSingleFile( XMLFile* file , MergeDataFile& aMergeDataFile , const ByteString& sLanguage , + ByteString sPath ) +{ + file->Extract(); + + XMLHashMap* aXMLStrHM = file->GetStrings(); + LangHashMap* aLangHM; + static ResData pResData( "","",""); + pResData.sResTyp = "help"; + + ByteString sTmp = Export::sLanguages; + + sTmp.EraseLeadingAndTrailingChars(); + + for(XMLHashMap::iterator pos=aXMLStrHM->begin();pos!=aXMLStrHM->end();++pos) // Merge every l10n related string + { + + aLangHM = pos->second; + //printf("*********************DUMPING HASHMAP***************************************"); + //Dump( aXMLStrHM ); + //printf("DBG: sHelpFile = %s\n",sHelpFile.GetBuffer() ); + + pResData.sGId = pos->first; + pResData.sFilename = sHelpFile; + + ProcessHelp( aLangHM , sLanguage, &pResData , aMergeDataFile ); + } + + + // Init temp and target file + ByteString sTempFile; + ByteString sTargetFile( sPath ); + ByteString sTempFileCopy; + + static const ByteString INPATH = Export::GetEnv( "INPATH" ); + Export::getRandomName( sPath , sTempFile , INPATH ); + Export::getRandomName( sPath , sTempFileCopy , INPATH ); + // Write in the temp file + bool hasNoError = file->Write ( sTempFile ); + if( !hasNoError ) + { + cerr << "ERROR: file->Write failed\n"; + return false; + } + + DirEntry aTmp( sTempFile ); + DirEntry aTmp2( sTempFileCopy ); + DirEntry aTar( sTargetFile ); + + if( !Export::CopyFile( sTempFile , sTempFileCopy ) ) + { +#if defined(UNX) || defined(OS2) + sleep( 3 ); +#else + Sleep( 3 ); +#endif + if( !Export::CopyFile( sTempFile , sTempFileCopy ) ) + { + cerr << "ERROR: Can not copy file from " << sTempFile.GetBuffer() << " to " << sTempFileCopy.GetBuffer() << "\n"; + return false; + } + } + //remove( sTargetFile.GetBuffer() ); + + FileStat aFSTest( aTar ); + if( aFSTest.GetSize() < 1 ) + { + remove( sTargetFile.GetBuffer() ); + } + int rc; +#if defined(UNX) || defined(OS2) + rc = rename( sTempFile.GetBuffer() , sTargetFile.GetBuffer() ); +#else + rc = MoveFileEx( sTempFile.GetBuffer() , sTargetFile.GetBuffer(), MOVEFILE_REPLACE_EXISTING ); +#endif + FileStat aFS( aTar ); + + //cout << "mv " << sTempFile.GetBuffer() << " " << sTargetFile.GetBuffer() << "\n"; + //cout << "rc -> " << rc << " filesize -> " << aFS.GetSize() << "\n"; +// Windows rename returns -1 if the file already exits +//#ifdef UNX + if( rc < 0 || aFS.GetSize() < 1 ) +//#else +// if( aFS.GetSize() < 1 ) +//#endif + { +#if defined(UNX) || defined(OS2) + sleep( 3 ); +#else + Sleep( 3 ); +#endif + aFSTest.Update( aTar ); + if( aFSTest.GetSize() < 1 ) + { + remove( sTargetFile.GetBuffer() ); + } +#if defined(UNX) || defined(OS2) + rc = rename( sTempFileCopy.GetBuffer() , sTargetFile.GetBuffer() ); +#else + rc = MoveFileEx( sTempFileCopy.GetBuffer() , sTargetFile.GetBuffer() , MOVEFILE_REPLACE_EXISTING ); +#endif + aFS.Update( aTar ); + + //cout << "mv2 " << sTempFileCopy.GetBuffer() << " " << sTargetFile.GetBuffer() << "\n"; + //cout << "rc -> " << rc << " filesize -> " << aFS.GetSize() << "\n"; + +// Windows rename returns -1 if the file already exits +//#ifdef WNT +// if( aFS.GetSize() < 1 ) +//#else + if( rc < 0 || aFS.GetSize() < 1 ) +//#endif + { + cerr << "ERROR: helpex Can't rename file " << sTempFileCopy.GetBuffer() << " to " << sTargetFile.GetBuffer() << " rename rc=" << rc << " filesize=" << aFS.GetSize() << "\n"; + aTmp.Kill(); + aTmp2.Kill(); + if( aFS.GetSize() < 1 ) + aTar.Kill(); + return false; + } + } + aTmp.Kill(); + aTmp2.Kill(); + + return true; +} + +ByteString HelpParser::GetOutpath( const ByteString& rPathX , const ByteString& sCur , const ByteString& rPathY ){ + ByteString testpath = rPathX; + static const ByteString sDelimiter( DirEntry::GetAccessDelimiter(), RTL_TEXTENCODING_ASCII_US ); + testpath.EraseTrailingChars( '/' ); + testpath.EraseTrailingChars( '\\' ); + testpath += sDelimiter; + testpath += sCur; + testpath += sDelimiter; + ByteString sRelativePath( rPathY ); + sRelativePath.EraseLeadingChars( '/' ); + sRelativePath.EraseLeadingChars( '\\' ); + testpath += sRelativePath; + testpath += sDelimiter; + return testpath; +} +void HelpParser::MakeDir( const ByteString& sPath ){ + ByteString sTPath( sPath ); + ByteString sDelimiter( DirEntry::GetAccessDelimiter(), RTL_TEXTENCODING_ASCII_US ); + sTPath.SearchAndReplaceAll( sDelimiter , '/' ); + USHORT cnt = sTPath.GetTokenCount( '/' ); + ByteString sCreateDir; + for( USHORT i = 0 ; i < cnt ; i++ ) + { + sCreateDir += sTPath.GetToken( i , '/' ); + sCreateDir += sDelimiter; +#ifdef WNT + _mkdir( sCreateDir.GetBuffer() ); +#else + mkdir( sCreateDir.GetBuffer() , S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH ); +#endif + } +} + + +/* ProcessHelp Methode: search for en-US entry and replace it with the current language*/ +void HelpParser::ProcessHelp( LangHashMap* aLangHM , const ByteString& sCur , ResData *pResData , MergeDataFile& aMergeDataFile ){ + + XMLElement* pXMLElement = NULL; + PFormEntrys *pEntrys = NULL; + XMLData *data = NULL; + + String sNewdata; + ByteString sLId; + ByteString sGId; + + pEntrys = NULL; + +#ifdef MERGE_SOURCE_LANGUAGES + if( true ){ // Merge en-US! +#else + if( !sCur.EqualsIgnoreCaseAscii("en-US") ){ +#endif + pXMLElement = (*aLangHM)[ "en-US" ]; + if( pXMLElement == NULL ) + { + printf("Error: Can't find en-US entry\n"); + } + if( pXMLElement != NULL ) + { + sLId = pXMLElement->GetOldref(); + pResData->sId = sLId; + + pEntrys = aMergeDataFile.GetPFormEntrys( pResData ); + if( pEntrys != NULL) + { + ByteString sNewText; + pEntrys->GetText( sNewText, STRING_TYP_TEXT, sCur , true ); + sNewdata = String( sNewText , RTL_TEXTENCODING_UTF8 ); + if ( sNewdata.Len()) + { + if( pXMLElement != NULL ) + { + data = new XMLData( sNewdata , NULL , true ); // Add new one + pXMLElement->RemoveAndDeleteAllChilds(); + pXMLElement->AddChild( data ); + aLangHM->erase( sCur ); + } + } + }else if( pResData == NULL ){fprintf(stdout,"Can't find GID=%s LID=%s TYP=%s\n",pResData->sGId.GetBuffer(),pResData->sId.GetBuffer(),pResData->sResTyp.GetBuffer());} + pXMLElement->ChangeLanguageTag( String( sCur , RTL_TEXTENCODING_ASCII_US) ); + } + + } +} +/* Process() Method merges */ +void HelpParser::Process( LangHashMap* aLangHM , const ByteString& sCur , ResData *pResData , MergeDataFile& aMergeDataFile ){ + + XMLElement* pXMLElement = NULL; + PFormEntrys *pEntrys = NULL; + XMLData *data = NULL; + XMLParentNode *parent = NULL; + XMLDefault *xmldefault = NULL; + + short curLang = 0; + String sNewdata; + bool isFallback = false; + ByteString sLId; + ByteString sGId; + + pEntrys = NULL; + +#ifdef MERGE_SOURCE_LANGUAGES + if( true ){ // Merge en-US! +#else + if( !sCur.EqualsIgnoreCaseAscii("en-US") ){ +#endif + pXMLElement = (*aLangHM)[ sCur ]; + if( pXMLElement == NULL ) + { + FillInFallbacks( *aLangHM , sCur ); + pXMLElement = ( *aLangHM )[ sCur ]; + isFallback = true; + } + if( pXMLElement != NULL ) + { + parent = pXMLElement->GetParent(); + sLId = pXMLElement->GetOldref(); + pResData->sId = sLId; + + pEntrys = aMergeDataFile.GetPFormEntrys( pResData ); + if( pEntrys != NULL) + { + ByteString sNewText; + pEntrys->GetText( sNewText, STRING_TYP_TEXT, sCur , true ); + sNewdata = String( sNewText , RTL_TEXTENCODING_UTF8 ); + if ( sNewdata.Len()) + { + printf("Entries found\n"); + if( pXMLElement != NULL ) + { + data = new XMLData( sNewdata , NULL , true ); // Add new one + if( pXMLElement->ToOUString().compareTo( OUString(data->GetData()) ) != 0 ) + { + pXMLElement->RemoveAndDeleteAllChilds(); + pXMLElement->AddChild( data ); + } + if( isFallback ) + { + xmldefault = new XMLDefault( String::CreateFromAscii("\n") , NULL ); + int pos = parent->GetPosition( pXMLElement->GetId() ); + if( pos != -1 ){ + parent->AddChild(xmldefault , pos+1 ); + parent->AddChild(pXMLElement , pos+2 ); + } + else fprintf(stdout,"ERROR: Can't find reference Element of id %s language %d\n",pXMLElement->GetId().GetBuffer(),curLang); + } + + aLangHM->erase( sCur ); + } + } + delete pResData; + }else if( pResData == NULL ){fprintf(stdout,"Can't find GID=%s LID=%s TYP=%s\n",pResData->sGId.GetBuffer(),pResData->sId.GetBuffer(),pResData->sResTyp.GetBuffer());} + } + + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/inireader.cxx b/l10ntools/source/inireader.cxx new file mode 100644 index 000000000000..003902087469 --- /dev/null +++ b/l10ntools/source/inireader.cxx @@ -0,0 +1,135 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +#include <unicode/regex.h> +#include <unicode/unistr.h> +#include <string> +#include <fstream> +#include <iostream> +#include "inireader.hxx" + +using namespace std; +namespace transex3 +{ + +bool INIreader::read( INImap& myMap , string& filename ) +{ + ifstream aFStream( filename.c_str() ); + if( aFStream && aFStream.is_open()) + { + string line; + string section; + string param_key; + string param_value; + stringmap* myvalues = 0; + + while( std::getline( aFStream , line ) ) + { + trim( line ); + if( line.empty() ){ + } + else if( is_section( line , section ) ) + { + //cerr << "[" << section << "]\n"; + myvalues = new stringmap(); + myMap[ section ] = myvalues ; + } + else if ( is_parameter( line , param_key , param_value ) ) + { + //cerr << "" << param_key << " = " << param_value << "\n"; + if( myvalues ) + { + (*myvalues)[ param_key ] = param_value ; + } + else + { + cerr << "ERROR: The INI file " << filename << " appears to be broken ... parameters without a section?!?\n"; + if( aFStream.is_open() ) aFStream.close(); + return false; + } + } + } + + if( aFStream.is_open() ) + aFStream.close(); + + return true; + } + else + { + cerr << "ERROR: Can't open file '" << filename << "'\n"; + } + return false; +} + +bool INIreader::is_section( string& line , string& section_str ) +{ + // Error in regex ? + check_status( section_status ); + UnicodeString target( line.c_str() , line.length() ); + + section_match->reset( target ); + check_status( section_status ); + + if( section_match->find() ) + { + check_status( section_status ); + UnicodeString result( section_match->group( 1 , section_status) ); + check_status( section_status ); + toStlString( result , section_str ); + + return true; + } + return false; +} + +bool INIreader::is_parameter( string& line , string& parameter_key , string& parameter_value ) +{ + // Error in regex ? + check_status( parameter_status ); + UnicodeString target( line.c_str() , line.length() ); + + parameter_match->reset( target ); + check_status( parameter_status ); + + if( parameter_match->find() ) + { + check_status( parameter_status ); + + UnicodeString result1( parameter_match->group( 1 , parameter_status) ); + check_status( parameter_status ); + toStlString( result1 , parameter_key ); + UnicodeString result2( parameter_match->group( 2 , parameter_status) ); + check_status( parameter_status ); + toStlString( result2 , parameter_value ); + + return true; + } + return false; +} + +void INIreader::check_status( UErrorCode status ) +{ + if( U_FAILURE( status) ) + { + cerr << "Error in or while using regex: " << u_errorName( status ) << "\n"; + exit(-1); + } +} + +void INIreader::toStlString( const UnicodeString& str , string& stl_str) +{ + // convert to string + char* buffer = new char[ str.length()*3 ]; + str.extract( 0 , str.length() , buffer ); + stl_str = string( buffer ); + delete [] buffer; +} + +void INIreader::trim( string& str ) +{ + string str1 = str.substr( 0 , str.find_last_not_of(' ') + 1 ); + str = str1.empty() ? str1 : str1.substr( str1.find_first_not_of(' ') ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/lngex.cxx b/l10ntools/source/lngex.cxx new file mode 100644 index 000000000000..cc37c2f553ba --- /dev/null +++ b/l10ntools/source/lngex.cxx @@ -0,0 +1,208 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_l10ntools.hxx" +#include <stdio.h> + +// local includes +#include "lngmerge.hxx" + +// defines to parse command line +#define STATE_NON 0x0001 +#define STATE_INPUT 0x0002 +#define STATE_OUTPUT 0x0003 +#define STATE_PRJ 0x0004 +#define STATE_ROOT 0x0005 +#define STATE_MERGESRC 0x0006 +#define STATE_ERRORLOG 0x0007 +#define STATE_BREAKHELP 0x0008 +#define STATE_UNMERGE 0x0009 +#define STATE_UTF8 0x000A +#define STATE_ULF 0x000B +#define STATE_LANGUAGES 0x000C + +// set of global variables +ByteString sInputFile; +BOOL bEnableExport; +BOOL bMergeMode; +BOOL bErrorLog; +BOOL bUTF8; +BOOL bULF; // ULF = Unicode Language File +ByteString sPrj; +ByteString sPrjRoot; +ByteString sOutputFile; +ByteString sMergeSrc; + +/*****************************************************************************/ +BOOL ParseCommandLine( int argc, char* argv[]) +/*****************************************************************************/ +{ + bEnableExport = FALSE; + bMergeMode = FALSE; + bErrorLog = TRUE; + bUTF8 = TRUE; + bULF = FALSE; + sPrj = ""; + sPrjRoot = ""; + Export::sLanguages = ""; + + USHORT nState = STATE_NON; + BOOL bInput = FALSE; + + // parse command line + for( int i = 1; i < argc; i++ ) { + ByteString sSwitch( argv[ i ] ); + sSwitch.ToUpperAscii(); + if ( sSwitch == "-I" ) { + nState = STATE_INPUT; // next tokens specifies source files + } + else if ( sSwitch == "-O" ) { + nState = STATE_OUTPUT; // next token specifies the dest file + } + else if ( sSwitch == "-P" ) { + nState = STATE_PRJ; // next token specifies the cur. project + } + else if ( sSwitch == "-R" ) { + nState = STATE_ROOT; // next token specifies path to project root + } + else if ( sSwitch == "-M" ) { + nState = STATE_MERGESRC; // next token specifies the merge database + } + else if ( sSwitch == "-E" ) { + nState = STATE_ERRORLOG; + bErrorLog = FALSE; + } + else if ( sSwitch == "-UTF8" ) { + nState = STATE_UTF8; + bUTF8 = TRUE; + } +/* else if ( sSwitch == "-NOUTF8" ) { + nState = STATE_UTF8; + bUTF8 = FALSE; + }*/ +/* else if ( sSwitch == "-ULF" ) { + nState = STATE_ULF; + bULF = TRUE; + }*/ + else if ( sSwitch == "-L" ) { + nState = STATE_LANGUAGES; + } + else { + switch ( nState ) { + case STATE_NON: { + return FALSE; // no valid command line + } + //break; + case STATE_INPUT: { + sInputFile = argv[ i ]; + bInput = TRUE; // source file found + } + break; + case STATE_OUTPUT: { + sOutputFile = argv[ i ]; // the dest. file + } + break; + case STATE_PRJ: { + sPrj = argv[ i ]; +// sPrj.ToLowerAscii(); // the project + } + break; + case STATE_ROOT: { + sPrjRoot = argv[ i ]; // path to project root + } + break; + case STATE_MERGESRC: { + sMergeSrc = argv[ i ]; + bMergeMode = TRUE; // activate merge mode, cause merge database found + } + break; + case STATE_LANGUAGES: { + Export::sLanguages = argv[ i ]; + } + break; + } + } + } + + if ( bInput ) { + // command line is valid + bULF = TRUE; + bEnableExport = TRUE; + return TRUE; + } + + // command line is not valid + return FALSE; +} + + +/*****************************************************************************/ +void Help() +/*****************************************************************************/ +{ + fprintf( stdout, "Syntax:ULFEX[-p Prj][-r PrjRoot]-i FileIn -o FileOut[-m DataBase][-L l1,l2,...]\n" ); + fprintf( stdout, " Prj: Project\n" ); + fprintf( stdout, " PrjRoot: Path to project root (..\\.. etc.)\n" ); + fprintf( stdout, " FileIn: Source file (*.lng)\n" ); + fprintf( stdout, " FileOut: Destination file (*.*)\n" ); + fprintf( stdout, " DataBase: Mergedata (*.sdf)\n" ); + fprintf( stdout, " -L: Restrict the handled languages. l1,l2,... are elements of (de,en-US...)\n" ); + fprintf( stdout, " A fallback language can be defined like this: l1=f1.\n" ); + fprintf( stdout, " f1, f2,... are also elements of (de,en-US...)\n" ); + fprintf( stdout, " Example: -L de,es=en-US\n" ); + fprintf( stdout, " Restriction to de and es, en-US will be fallback for es\n" ); +} + +/*****************************************************************************/ +#if defined(UNX) || defined(OS2) +int main( int argc, char *argv[] ) +#else +int _cdecl main( int argc, char *argv[] ) +#endif +/*****************************************************************************/ +{ + if ( !ParseCommandLine( argc, argv )) { + Help(); + return 1; + } + fprintf(stdout, "."); + fflush( stdout ); + + if ( sOutputFile.Len()) { + LngParser aParser( sInputFile, bUTF8, bULF ); + if ( bMergeMode ) + aParser.Merge( sMergeSrc, sOutputFile , sPrj ); + else + aParser.CreateSDF( sOutputFile, sPrj, sPrjRoot ); + } + + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/lngmerge.cxx b/l10ntools/source/lngmerge.cxx new file mode 100644 index 000000000000..5f6273a24ac6 --- /dev/null +++ b/l10ntools/source/lngmerge.cxx @@ -0,0 +1,361 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_l10ntools.hxx" +#include <tools/fsys.hxx> + +// local includes +#include "lngmerge.hxx" +#include "utf8conv.hxx" +#include <iostream> +using namespace std; +// +// class LngParser +// +/*****************************************************************************/ +LngParser::LngParser( const ByteString &rLngFile, BOOL bUTF8, BOOL bULFFormat ) +/*****************************************************************************/ + : + nError( LNG_OK ), + pLines( NULL ), + sSource( rLngFile ), + bDBIsUTF8( bUTF8 ), + bULF( bULFFormat ) +{ + pLines = new LngLineList(); + DirEntry aEntry( String( sSource, RTL_TEXTENCODING_ASCII_US )); + if ( aEntry.Exists()) { + SvFileStream aStream( String( sSource, RTL_TEXTENCODING_ASCII_US ), STREAM_STD_READ ); + if ( aStream.IsOpen()) { + ByteString sLine; + bool bFirstLine = true; + while ( !aStream.IsEof()) { + aStream.ReadLine( sLine ); + + if( bFirstLine ){ // Always remove UTF8 BOM from the first line + Export::RemoveUTF8ByteOrderMarker( sLine ); + bFirstLine = false; + } + + pLines->push_back( new ByteString( sLine ) ); + } + } + else + nError = LNG_COULD_NOT_OPEN; + } + else + nError = LNG_FILE_NOTFOUND; +} + +/*****************************************************************************/ +LngParser::~LngParser() +/*****************************************************************************/ +{ + for ( size_t i = 0, n = pLines->size(); i < n; i++ ) + delete (*pLines)[ i ]; + pLines->clear(); + delete pLines; +} + +/*****************************************************************************/ +void LngParser::FillInFallbacks( ByteStringHashMap Text ) +/*****************************************************************************/ +{ + ByteString sCur; + for( unsigned int n = 0; n < aLanguages.size(); n++ ){ + sCur = aLanguages[ n ]; + + if( Export::isAllowed( sCur ) ){ + ByteString sFallbackLang = Export::GetFallbackLanguage( sCur ); + if( sFallbackLang.Len() ){ + Text[ sCur ] = Text[ sFallbackLang ]; + } + } + } +} + +/*****************************************************************************/ +BOOL LngParser::CreateSDF( + const ByteString &rSDFFile, const ByteString &rPrj, + const ByteString &rRoot ) +/*****************************************************************************/ +{ + + Export::InitLanguages( false ); + aLanguages = Export::GetLanguages(); + SvFileStream aSDFStream( String( rSDFFile, RTL_TEXTENCODING_ASCII_US ), + STREAM_STD_WRITE | STREAM_TRUNC ); + if ( !aSDFStream.IsOpen()) { + nError = SDF_COULD_NOT_OPEN; + } + aSDFStream.SetStreamCharSet( RTL_TEXTENCODING_UTF8 ); + nError = SDF_OK; + DirEntry aEntry( String( sSource, RTL_TEXTENCODING_ASCII_US )); + aEntry.ToAbs(); + String sFullEntry = aEntry.GetFull(); + aEntry += DirEntry( String( "..", RTL_TEXTENCODING_ASCII_US )); + aEntry += DirEntry( rRoot ); + ByteString sPrjEntry( aEntry.GetFull(), gsl_getSystemTextEncoding()); + ByteString sActFileName( + sFullEntry.Copy( sPrjEntry.Len() + 1 ), gsl_getSystemTextEncoding()); + sActFileName.SearchAndReplaceAll( "/", "\\" ); + + size_t nPos = 0; + BOOL bStart = true; + ByteString sGroup; + ByteStringHashMap Text; + ByteString sID; + ByteString sLine; + + while( nPos < pLines->size() ) { + sLine = *(*pLines)[ nPos++ ]; + while( nPos < pLines->size() && !isNextGroup( sGroup , sLine ) ) { + ReadLine( sLine , Text ); + sID = sGroup; + sLine = *(*pLines)[ nPos++ ]; + }; + if( bStart ) { + bStart = false; + sID = sGroup; + } + else { + WriteSDF( aSDFStream , Text , rPrj , rRoot , sActFileName , sID ); + } + } + aSDFStream.Close(); + return true; +} + + void LngParser::WriteSDF( SvFileStream &aSDFStream , ByteStringHashMap &rText_inout , + const ByteString &rPrj , const ByteString &rRoot , + const ByteString &sActFileName , const ByteString &sID ) + { + + BOOL bExport = true; + if ( bExport ) { + ByteString sTimeStamp( Export::GetTimeStamp()); + ByteString sCur; + FillInFallbacks( rText_inout ); + for( unsigned int n = 0; n < aLanguages.size(); n++ ){ + sCur = aLanguages[ n ]; + ByteString sAct = rText_inout[ sCur ]; + if ( !sAct.Len() && sCur.Len() ) + sAct = rText_inout[ ByteString("en-US") ]; + + ByteString sOutput( rPrj ); sOutput += "\t"; + if ( rRoot.Len()) + sOutput += sActFileName; + sOutput += "\t0\t"; + sOutput += "LngText\t"; + sOutput += sID; sOutput += "\t\t\t\t0\t"; + sOutput += sCur; sOutput += "\t"; + sOutput += sAct; sOutput += "\t\t\t\t"; + sOutput += sTimeStamp; + aSDFStream.WriteLine( sOutput ); + } + } + } + bool LngParser::isNextGroup( ByteString &sGroup_out , ByteString &sLine_in ){ + sLine_in.EraseLeadingChars( ' ' ); + sLine_in.EraseTrailingChars( ' ' ); + if (( sLine_in.GetChar( 0 ) == '[' ) && + ( sLine_in.GetChar( sLine_in.Len() - 1 ) == ']' )){ + sGroup_out = sLine_in.GetToken( 1, '[' ).GetToken( 0, ']' ); + sGroup_out.EraseLeadingChars( ' ' ); + sGroup_out.EraseTrailingChars( ' ' ); + return true; + } + return false; + } + void LngParser::ReadLine( const ByteString &sLine_in , ByteStringHashMap &rText_inout){ + ByteString sLang = sLine_in.GetToken( 0, '=' ); + sLang.EraseLeadingChars( ' ' ); + sLang.EraseTrailingChars( ' ' ); + ByteString sText = sLine_in.GetToken( 1, '\"' ).GetToken( 0, '\"' ); + if( sLang.Len() ) + rText_inout[ sLang ] = sText; + } + +/*****************************************************************************/ +BOOL LngParser::Merge( + const ByteString &rSDFFile, const ByteString &rDestinationFile , const ByteString& rPrj ) +/*****************************************************************************/ +{ + (void) rPrj; + Export::InitLanguages( true ); + SvFileStream aDestination( + String( rDestinationFile, RTL_TEXTENCODING_ASCII_US ), + STREAM_STD_WRITE | STREAM_TRUNC ); + if ( !aDestination.IsOpen()) { + nError = LNG_COULD_NOT_OPEN; + } + nError = LNG_OK; + + MergeDataFile aMergeDataFile( rSDFFile, sSource , FALSE, RTL_TEXTENCODING_MS_1252);//, bDBIsUTF8 ); + ByteString sTmp( Export::sLanguages ); + if( sTmp.ToUpperAscii().Equals("ALL") ) + Export::SetLanguages( aMergeDataFile.GetLanguages() ); + aLanguages = Export::GetLanguages(); + + size_t nPos = 0; + BOOL bGroup = FALSE; + ByteString sGroup; + + // seek to next group + while ( nPos < pLines->size() && !bGroup ) { + ByteString sLine( *(*pLines)[ nPos ] ); + sLine.EraseLeadingChars( ' ' ); + sLine.EraseTrailingChars( ' ' ); + if (( sLine.GetChar( 0 ) == '[' ) && + ( sLine.GetChar( sLine.Len() - 1 ) == ']' )) + { + sGroup = sLine.GetToken( 1, '[' ).GetToken( 0, ']' ); + sGroup.EraseLeadingChars( ' ' ); + sGroup.EraseTrailingChars( ' ' ); + bGroup = TRUE; + } + nPos ++; + } + + while ( nPos < pLines->size()) { + ByteStringHashMap Text; + ByteString sID( sGroup ); + ULONG nLastLangPos = 0; + + ResData *pResData = new ResData( "", sID , sSource ); + pResData->sResTyp = "LngText"; + PFormEntrys *pEntrys = aMergeDataFile.GetPFormEntrys( pResData ); + // read languages + bGroup = FALSE; + + ByteString sLanguagesDone; + + while ( nPos < pLines->size() && !bGroup ) { + ByteString sLine( *(*pLines)[ nPos ] ); + sLine.EraseLeadingChars( ' ' ); + sLine.EraseTrailingChars( ' ' ); + if (( sLine.GetChar( 0 ) == '[' ) && + ( sLine.GetChar( sLine.Len() - 1 ) == ']' )) + { + sGroup = sLine.GetToken( 1, '[' ).GetToken( 0, ']' ); + sGroup.EraseLeadingChars( ' ' ); + sGroup.EraseTrailingChars( ' ' ); + bGroup = TRUE; + nPos ++; + sLanguagesDone = ""; + } + else if ( sLine.GetTokenCount( '=' ) > 1 ) { + ByteString sLang = sLine.GetToken( 0, '=' ); + sLang.EraseLeadingChars( ' ' ); + sLang.EraseTrailingChars( ' ' ); + + ByteString sSearch( ";" ); + sSearch += sLang; + sSearch += ";"; + + if (( sLanguagesDone.Search( sSearch ) != STRING_NOTFOUND )) { + LngLineList::iterator it = pLines->begin(); + ::std::advance( it, nPos ); + pLines->erase( it ); + } + if( bULF && pEntrys ) + { + // this is a valid text line + ByteString sText = sLine.GetToken( 1, '\"' ).GetToken( 0, '\"' ); + if( sLang.Len() ){ + ByteString sNewText; + pEntrys->GetText( sNewText, STRING_TYP_TEXT, sLang, TRUE ); + + if ( sNewText.Len()) { + ByteString *pLine = (*pLines)[ nPos ]; + + ByteString sText1( sLang ); + sText1 += " = \""; + sText1 += sNewText; + sText1 += "\""; + *pLine = sText1; + Text[ sLang ] = sNewText; + } + } + nLastLangPos = nPos; + nPos ++; + sLanguagesDone += sSearch; + } + else { + nLastLangPos = nPos; + nPos ++; + sLanguagesDone += sSearch; + } + } + else + nPos++; + } + ByteString sCur; + if ( nLastLangPos ) { + for( unsigned int n = 0; n < aLanguages.size(); n++ ){ + sCur = aLanguages[ n ]; + if( !sCur.EqualsIgnoreCaseAscii("en-US") && !Text[ sCur ].Len() && pEntrys ) { + + ByteString sNewText; + pEntrys->GetText( sNewText, STRING_TYP_TEXT, sCur, TRUE ); + if (( sNewText.Len()) && + !(( sCur.Equals("x-comment") ) && ( sNewText == "-" ))) + { + ByteString sLine; + sLine += sCur; + sLine += " = \""; + sLine += sNewText; + sLine += "\""; + + nLastLangPos++; + nPos++; + + if ( nLastLangPos < pLines->size() ) { + LngLineList::iterator it = pLines->begin(); + ::std::advance( it, nLastLangPos ); + pLines->insert( it, new ByteString( sLine ) ); + } else { + pLines->push_back( new ByteString( sLine ) ); + } + } + } + } + } + + delete pResData; + } + + for ( size_t i = 0; i < pLines->size(); i++ ) + aDestination.WriteLine( *(*pLines)[ i ] ); + + aDestination.Close(); + return TRUE; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/localize.cxx b/l10ntools/source/localize.cxx new file mode 100644 index 000000000000..1d7836ac67a3 --- /dev/null +++ b/l10ntools/source/localize.cxx @@ -0,0 +1,979 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_l10ntools.hxx" + +#include "srciter.hxx" +#include "export.hxx" +#include "treeconfig.hxx" +#include <string> +#include <vector> +#include <stdio.h> +#include <iostream> +#include "tools/errcode.hxx" +#include "tools/fsys.hxx" + +#ifndef L10NTOOLS_FILE_HXX +#define L10NTOOLS_FILE_HXX +#include <l10ntools/file.hxx> +#endif + +namespace transex3 +{ + +// +// SourceTreeLocalizer +// + +const char *ExeTable[][5] = { + { "src", "transex3", " -UTF8 -e", "negative", "noiso" }, + { "hrc", "transex3", " -UTF8 -e", "positive", "noiso" }, + { "tree", "xhtex", "", "negative", "noiso" }, + { "xtx", "xtxex", "", "negative", "noiso" }, + { "ulf", "ulfex", " -e", "negative", "noiso" }, + { "xrb", "xmlex", "-UTF8 -e", "negative", "iso" }, + { "xxl", "xmlex", "-UTF8 -e", "negative", "iso" }, + { "xgf", "xmlex", "-UTF8 -e -t:xgf", "negative", "iso" }, + { "xcd", "cfgex", "-UTF8 -e", "negative", "iso" }, + { "xcu", "cfgex", "-UTF8 -e", "negative", "iso" }, + { "xcs", "cfgex", "-UTF8 -e -f", "negative", "iso" }, + { "xrm", "xrmex", "-UTF8 -e", "negative", "iso" }, + { "xhp", "helpex", " -e", "negative", "noiso" }, + { "properties", "jpropex", " -e", "negative", "noiso" }, + { "NULL", "NULL", "NULL", "NULL", "NULL" } +}; + +const char *NegativeList[] = { + "officecfg/data/org.openoffice.Office.Labels.xcd", + "officecfg/data/org/openoffice/Office/Labels.xcd", + "officecfg/data/org/openoffice/Office/SFX.xcd", + "officecfg/data/org/openoffice/Office/Accelerators.xcu", + "hidother.src", + "dictionaries/da_DK/help/da/help.tree", + "dictionaries/da_DK/help/da/org.openoffice.da.hunspell.dictionaries/page1.xph", + "dictionaries/hu_HU/help/hu/help.tree", + "dictionaries/hu_HU/help/hu/org.openoffice.hu.hunspell.dictionaries/page1.xph", + "NULL" +}; + +const char *PositiveList[] = { + "svx/inc/globlmn_tmpl.hrc", + "sw/source/ui/inc/swmn_tmpl.hrc", + "sw/source/ui/inc/swacc_tmpl.hrc", + "sw/source/ui/inc/toolbox_tmpl.hrc", + "offmgr/inc/offmenu_tmpl.hrc", + "offmgr/source/offapp/intro/intro_tmpl.hrc", + "dbaccess/source/ui/inc/toolbox_tmpl.hrc", + "svx/source/intro/intro_tmpl.hrc", + "dbaccess/source/ui/dlg/AutoControls_tmpl.hrc", + "svx/source/unodialogs/textconversiondlgs/chinese_direction_tmpl.hrc", + "chart2/source/controller/dialogs/res_DataLabel_tmpl.hrc", + "chart2/source/controller/dialogs/res_LegendPosition_tmpl.hrc", + "chart2/source/controller/dialogs/res_Statistic_tmpl.hrc", + "chart2/source/controller/dialogs/res_Titlesx_tmpl.hrc", + "chart2/source/controller/dialogs/res_SecondaryAxisCheckBoxes_tmpl.hrc", + "chart2/source/controller/menu/MenuItems_tmpl.hrc", + "chart2/source/controller/dialogs/res_ErrorBar_tmpl.hrc", + "chart2/source/controller/dialogs/res_Trendline_tmpl.hrc", + "svx.link/inc/globlmn_tmpl.hrc", + "sw.link/source/ui/inc/swmn_tmpl.hrc", + "sw.link/source/ui/inc/swacc_tmpl.hrc", + "sw.link/source/ui/inc/toolbox_tmpl.hrc", + "offmgr.link/inc/offmenu_tmpl.hrc", + "offmgr.link/source/offapp/intro/intro_tmpl.hrc", + "dbaccess.link/source/ui/inc/toolbox_tmpl.hrc", + "svx.link/source/intro/intro_tmpl.hrc", + "dbaccess.link/source/ui/dlg/AutoControls_tmpl.hrc", + "svx.link/source/unodialogs/textconversiondlgs/chinese_direction_tmpl.hrc", + "chart2.link/source/controller/dialogs/res_DataLabel_tmpl.hrc", + "chart2.link/source/controller/dialogs/res_LegendPosition_tmpl.hrc", + "chart2.link/source/controller/dialogs/res_Statistic_tmpl.hrc", + "chart2.link/source/controller/dialogs/res_Titlesx_tmpl.hrc", + "chart2.link/source/controller/dialogs/res_SecondaryAxisCheckBoxes_tmpl.hrc", + "chart2.link/source/controller/menu/MenuItems_tmpl.hrc", + "chart2.link/source/controller/dialogs/res_ErrorBar_tmpl.hrc", + "chart2.link/source/controller/dialogs/res_Trendline_tmpl.hrc", + "NULL" +}; + + +const char PRJ_DIR_NAME[] = "prj"; +const char DLIST_NAME[] = "d.lst"; + +#define LOCALIZE_NONE 0x0000 +#define LOCALIZE_EXTRACT 0x0001 +#define LOCALIZE_MERGE 0x0002 + +class SourceTreeLocalizer : public SourceTreeIterator +{ +private: + SvFileStream aSDF; + USHORT nMode; + + ByteString sLanguageRestriction; + + ByteString sOutputFile; + + int nFileCnt; + + const ByteString GetProjectName( BOOL bAbs = FALSE ); + const ByteString GetProjectRootRel(); + + + BOOL CheckNegativeList( const ByteString &rFileName ); + BOOL CheckPositiveList( const ByteString &rFileName ); + + void WorkOnFile( + const ByteString &rFileName, + const ByteString &rExecutable, + const ByteString &rParameter + ); + + void WorkOnFileType( + const ByteString &rDirectory, + const ByteString &rExtension, + const ByteString &rExecutable, + const ByteString &rParameter, + const ByteString &rCollectMode + ); + void WorkOnDirectory( const ByteString &rDirectory ); + BOOL ExecuteMerge(); + BOOL MergeSingleFile( + const ByteString &rPrj, + const ByteString &rFile, + const ByteString &rSDFFile + ); + +public: + SourceTreeLocalizer( const ByteString &rRoot, const ByteString &rVersion , bool bLocal , bool skip_links ); + ~SourceTreeLocalizer(); + + ByteString getSourceLanguages( ByteString sLanguageRestriction , ByteString sCommand ); + + void SetLanguageRestriction( const ByteString& rRestrictions ) + { sLanguageRestriction = rRestrictions; } + int getFileCnt(); + BOOL Extract( const ByteString &rDestinationFile ); + BOOL Merge( const ByteString &rSourceFile , const ByteString &rOutput ); + int GetFileCnt(); + virtual void OnExecuteDirectory( const rtl::OUString &rDirectory ); +}; + +/*****************************************************************************/ +SourceTreeLocalizer::SourceTreeLocalizer( + const ByteString &rRoot, const ByteString &rVersion, bool bLocal_in , bool skip_links ) +/*****************************************************************************/ + : SourceTreeIterator( rRoot, rVersion , bLocal_in ), + nMode( LOCALIZE_NONE ), + nFileCnt( 0 ) +{ + bSkipLinks = skip_links ; +} + +/*****************************************************************************/ +SourceTreeLocalizer::~SourceTreeLocalizer() +/*****************************************************************************/ +{ +} + +/*****************************************************************************/ +const ByteString SourceTreeLocalizer::GetProjectName( BOOL bAbs ) +/*****************************************************************************/ +{ + BOOL bFound = FALSE; + DirEntry aCur; + aCur.ToAbs(); + + for ( ; ! bFound && aCur.Level() > 1; aCur.CutName() ) + { + DirEntry aTest = aCur + DirEntry(PRJ_DIR_NAME) + DirEntry(DLIST_NAME); + if ( aTest.Exists() ) + { + if ( bAbs ) + return ByteString( aCur.GetFull(), RTL_TEXTENCODING_ASCII_US ); + else + return ByteString( aCur.GetName(), RTL_TEXTENCODING_ASCII_US ); + } + } + + return ""; +} +/*****************************************************************************/ +int SourceTreeLocalizer::GetFileCnt(){ +/*****************************************************************************/ + return nFileCnt; +} + +/*****************************************************************************/ +const ByteString SourceTreeLocalizer::GetProjectRootRel() +/*****************************************************************************/ +{ + ByteString sProjectRoot( GetProjectName( TRUE )); + DirEntry aCur; + aCur.ToAbs(); + ByteString sCur( aCur.GetFull(), RTL_TEXTENCODING_ASCII_US ); + + if( sCur.SearchAndReplace( sProjectRoot, "" ) == STRING_NOTFOUND ) + return ""; + + ByteString sDelimiter( + DirEntry::GetAccessDelimiter(), RTL_TEXTENCODING_ASCII_US ); + + sCur.SearchAndReplaceAll( sDelimiter, "/" ); + sCur.EraseLeadingChars( '/' ); + ULONG nCount = sCur.GetTokenCount( '/' ); + + ByteString sProjectRootRel; + for ( ULONG i = 0; i < nCount; i++ ) { + if ( sProjectRootRel.Len()) + sProjectRootRel += sDelimiter; + sProjectRootRel += ".."; + } + if ( sProjectRootRel.Len()) + return sProjectRootRel; + + return "."; +} + +bool skipProject( ByteString sPrj ) +{ + static const ByteString READLICENSE( "readlicense" ); + return sPrj.EqualsIgnoreCaseAscii( READLICENSE ); +} + +/*****************************************************************************/ +void SourceTreeLocalizer::WorkOnFile( + const ByteString &rFileName, const ByteString &rExecutable, + const ByteString &rParameter ) +/*****************************************************************************/ +{ + String sFull( rFileName, RTL_TEXTENCODING_ASCII_US ); + DirEntry aEntry( sFull ); + ByteString sFileName( aEntry.GetName(), RTL_TEXTENCODING_ASCII_US ); + + // set current working directory + DirEntry aPath( aEntry.GetPath()); + DirEntry aOldCWD; + aPath.SetCWD(); + + ByteString sPrj( GetProjectName()); + if ( sPrj.Len() && !skipProject( sPrj ) ) + { + ByteString sRoot( GetProjectRootRel()); + + DirEntry aTemp( Export::GetTempFile()); + ByteString sTempFile( aTemp.GetFull(), RTL_TEXTENCODING_ASCII_US ); + + ByteString sDel; +#if defined(WNT) || defined(OS2) + sDel=ByteString("\\"); +#else + sDel=ByteString("/"); +#endif + ByteString sPath1( Export::GetEnv("SOLARVER") ); + ByteString sPath2( Export::GetEnv("INPATH") ); + ByteString sPath3( "bin" ); + ByteString sPath4( Export::GetEnv("UPDMINOREXT") ); + ByteString sExecutable( sPath1 ); +#if defined(WNT) || defined(OS2) + sExecutable.SearchAndReplaceAll( "/", sDel ); +#endif + sExecutable += sDel ; + sExecutable += sPath2 ; + sExecutable += sDel; + sExecutable += sPath3 ; + sExecutable += sPath4 ; + sExecutable += sDel ; + sExecutable += rExecutable ; + + + ByteString sCommand( sExecutable ); + sCommand += " "; + sCommand += rParameter; + sCommand += " -p "; + sCommand += sPrj; + sCommand += " -r "; + sCommand += sRoot; + sCommand += " -i "; + sCommand += sFileName; + sCommand += " -o "; + sCommand += sTempFile; + if ( sLanguageRestriction.Len()) { + sCommand += " -l "; + sCommand += getSourceLanguages( sLanguageRestriction , sCommand ); + } + + //printf("DBG: %s\n",sCommand.GetBuffer()); + if (system(sCommand.GetBuffer()) == -1) + fprintf(stderr, "%s failed\n", sCommand.GetBuffer()); + nFileCnt++; + printf("."); + fflush( stdout ); + + SvFileStream aSDFIn( aTemp.GetFull(), STREAM_READ ); + ByteString sLine; + while ( aSDFIn.IsOpen() && !aSDFIn.IsEof()) { + aSDFIn.ReadLine( sLine ); + if ( sLine.Len()) { + aSDF.WriteLine( sLine ); + } + } + aSDFIn.Close(); + + aTemp.Kill(); + + } + // reset current working directory + aOldCWD.SetCWD(); +} + +ByteString SourceTreeLocalizer::getSourceLanguages( ByteString sLanguageRestriction_inout , ByteString sCommand ) +{ + // Source languages in helpcontent2 and macromigration en-US only! + if( sCommand.Search("helpex") != STRING_NOTFOUND ) { + sLanguageRestriction_inout.Assign( ByteString("en-US") ); + } + else if( sCommand.Search("xmlex") != STRING_NOTFOUND ){ + sLanguageRestriction_inout.Assign( ByteString("en-US") ); + } + return sLanguageRestriction_inout; +} + +/*****************************************************************************/ +BOOL SourceTreeLocalizer::CheckNegativeList( const ByteString &rFileName ) +/*****************************************************************************/ +{ + ULONG nIndex = 0; + BOOL bReturn = TRUE; + + ByteString sDelimiter( + DirEntry::GetAccessDelimiter(), RTL_TEXTENCODING_ASCII_US ); + + ByteString sFileName( rFileName ); + sFileName.ToLowerAscii(); + + ByteString sNegative( NegativeList[ nIndex ] ); + while( !sNegative.Equals( "NULL" ) && bReturn ) { + sNegative.SearchAndReplaceAll( "\\", sDelimiter ); + sNegative.SearchAndReplaceAll( "/", sDelimiter ); + sNegative.ToLowerAscii(); + + if( sFileName.Search( sNegative ) == sFileName.Len() - sNegative.Len()) + bReturn = FALSE; + + nIndex++; + sNegative = NegativeList[ nIndex ]; + } + + return bReturn; +} + +/*****************************************************************************/ +BOOL SourceTreeLocalizer::CheckPositiveList( const ByteString &rFileName ) +/*****************************************************************************/ +{ + ULONG nIndex = 0; + BOOL bReturn = FALSE; + + ByteString sDelimiter( + DirEntry::GetAccessDelimiter(), RTL_TEXTENCODING_ASCII_US ); + + ByteString sFileName( rFileName ); + sFileName.ToLowerAscii(); + + ByteString sNegative( PositiveList[ nIndex ] ); + while( !sNegative.Equals( "NULL" ) && !bReturn ) { + sNegative.SearchAndReplaceAll( "\\", sDelimiter ); + sNegative.SearchAndReplaceAll( "/", sDelimiter ); + sNegative.ToLowerAscii(); + + if( sFileName.Search( sNegative ) == sFileName.Len() - sNegative.Len()) + bReturn = TRUE; + + nIndex++; + sNegative = PositiveList[ nIndex ]; + } + + return bReturn; +} + +/*****************************************************************************/ +void SourceTreeLocalizer::WorkOnFileType( + const ByteString &rDirectory, const ByteString &rExtension, + const ByteString &rExecutable, const ByteString &rParameter, + const ByteString &rCollectMode +) +/*****************************************************************************/ +{ + String sWild( rDirectory, RTL_TEXTENCODING_ASCII_US ); + sWild += DirEntry::GetAccessDelimiter(); + sWild += String::CreateFromAscii( "*." ); + sWild += String( rExtension, RTL_TEXTENCODING_ASCII_US ); + + DirEntry aEntry( sWild ); + Dir aDir( sWild, FSYS_KIND_FILE ); + + for ( USHORT i = 0; i < aDir.Count(); i++ ) { + DirEntry aFile( aDir[ i ] ); + ByteString sFile( aFile.GetFull(), RTL_TEXTENCODING_ASCII_US ); + + BOOL bAllowed = TRUE; + + if ( rCollectMode.Equals( "negative" )) + bAllowed = CheckNegativeList( sFile ); + else if ( rCollectMode.Equals( "positive" )) + bAllowed = CheckPositiveList( sFile ); + + if ( bAllowed ) + WorkOnFile( sFile, rExecutable, rParameter ); + } +} + +/*****************************************************************************/ +void SourceTreeLocalizer::WorkOnDirectory( const ByteString &rDirectory ) +/*****************************************************************************/ +{ + //printf("Working on Directory %s\n",rDirectory.GetBuffer()); + ULONG nIndex = 0; + ByteString sExtension( ExeTable[ nIndex ][ 0 ] ); + ByteString sExecutable( ExeTable[ nIndex ][ 1 ] ); + ByteString sParameter( ExeTable[ nIndex ][ 2 ] ); + ByteString sCollectMode( ExeTable[ nIndex ][ 3 ] ); + + while( !sExtension.Equals( "NULL" )) { + WorkOnFileType( + rDirectory, + sExtension, + sExecutable, + sParameter, + sCollectMode + ); + + nIndex++; + + sExtension = ExeTable[ nIndex ][ 0 ]; + sExecutable = ExeTable[ nIndex ][ 1 ]; + sParameter = ExeTable[ nIndex ][ 2 ]; + sCollectMode = ExeTable[ nIndex ][ 3 ]; + } +} + +void SourceTreeLocalizer::OnExecuteDirectory( const rtl::OUString &aDirectory ) +{ + ByteString rDirectory( rtl::OUStringToOString( aDirectory , RTL_TEXTENCODING_UTF8 , aDirectory.getLength() ) ) ; + if ( nMode == LOCALIZE_NONE ){ + } + else + WorkOnDirectory( rDirectory ); +} + +/*****************************************************************************/ +BOOL SourceTreeLocalizer::Extract( const ByteString &rDestinationFile ) +/*****************************************************************************/ +{ + nMode = LOCALIZE_EXTRACT; + + aSDF.Open( String( rDestinationFile , RTL_TEXTENCODING_ASCII_US ) , STREAM_STD_WRITE ); + aSDF.SetLineDelimiter( LINEEND_CRLF ); + + BOOL bReturn = aSDF.IsOpen(); + if ( bReturn ) { + aSDF.Seek( STREAM_SEEK_TO_END ); + bReturn = StartExecute(); + aSDF.Close(); + } + else{ + printf("ERROR: Can't create file %s\n", rDestinationFile.GetBuffer() ); + } + nMode = LOCALIZE_NONE; + aSDF.Close(); + return bReturn; +} + +/*****************************************************************************/ +BOOL SourceTreeLocalizer::MergeSingleFile( + const ByteString &rPrj, + const ByteString &rFile, + const ByteString &rSDFFile +) +/*****************************************************************************/ +{ + //printf("MergeSingleFile(%s,%s,%s)",rPrj.GetBuffer(),rFile.GetBuffer(),rSDFFile.GetBuffer()); + if ( !rFile.Len()) + return TRUE; + + ByteString sRoot( Export::GetEnv( "SRC_ROOT" )); + DirEntry aEntry( String( sRoot, RTL_TEXTENCODING_ASCII_US )); + aEntry += DirEntry( String( rPrj, RTL_TEXTENCODING_ASCII_US )); + + ByteString sDelimiter( + DirEntry::GetAccessDelimiter(), RTL_TEXTENCODING_ASCII_US ); + + ByteString sCur( rFile ); + sCur.SearchAndReplaceAll( "\\", sDelimiter ); + sCur.SearchAndReplaceAll( "/", sDelimiter ); + + aEntry += DirEntry( String( sCur, RTL_TEXTENCODING_ASCII_US )); + ByteString sFile( aEntry.GetFull(), RTL_TEXTENCODING_ASCII_US ); + + ByteString sBCur( aEntry.GetFull(), RTL_TEXTENCODING_ASCII_US ); + + ULONG nIndex = 0; + ByteString sExtension( aEntry.GetExtension(), RTL_TEXTENCODING_ASCII_US ); + ByteString sCandidate( ExeTable[ nIndex ][ 0 ] ); + + while( !sCandidate.Equals ("NULL") && !sCandidate.Equals(sExtension) ) + sCandidate = ExeTable[ ++nIndex ][ 0 ]; + + if ( !sCandidate.Equals( "NULL" ) ) { + if( !aEntry.Exists()) { + DirEntryKind theDir=FSYS_KIND_FILE; + Dir myDir( aEntry.GetPath(), theDir); + DirEntry current; + BOOL found=FALSE; + for( USHORT x=0; x < myDir.Count() && !found;){ + current=myDir[x++]; + StringCompare result=current.GetName().CompareIgnoreCaseToAscii( aEntry.GetName() ); + if( result==COMPARE_EQUAL ){ + fprintf(stderr,"WARNING: %s not found\n", ByteString(aEntry.GetFull(),RTL_TEXTENCODING_ASCII_US).GetBuffer() ); + fprintf(stderr,"but use %s instead \n" , ByteString(current.GetFull(), RTL_TEXTENCODING_ASCII_US).GetBuffer() ); + aEntry=current; + found=TRUE; + } + } + if(!found) return TRUE; + + } + + DirEntry aOut( Export::GetTempFile() ); + ByteString sOutput; + if( sOutputFile.Len() == 0 ) + sOutput = ByteString ( aOut.GetFull(), RTL_TEXTENCODING_ASCII_US ); + else + sOutput = sOutputFile; + ByteString sCommand( ExeTable[ nIndex ][ 1 ] ); + sCommand += " -i "; + sCommand += ByteString( aEntry.GetName(), RTL_TEXTENCODING_ASCII_US ); + sCommand += " -m "; + sCommand += rSDFFile; + sCommand += " -o "; + sCommand += sOutput; + sCommand += " "; + sCommand += ByteString( ExeTable[ nIndex ][ 2 ] ); + if ( sLanguageRestriction.Len()) { + sCommand += " -l "; + sCommand += sLanguageRestriction; + } + + DirEntry aPath( aEntry.GetPath()); + DirEntry aOldCWD; + aPath.SetCWD(); + + if (system(sCommand.GetBuffer()) == -1) + fprintf(stderr, "%s failed\n", sCommand.GetBuffer()); + nFileCnt++; + printf("."); + SvFileStream aInStream( aOut.GetFull(), STREAM_READ ); + if ( !aInStream.IsOpen()) { + fprintf( stderr, + "ERROR: Unable to open file %s for reading!\n", + sOutput.GetBuffer()); + } + else { + FileStat::SetReadOnlyFlag( aEntry, FALSE ); + String myStr2(aEntry.GetFull()); + String aTemp22 = String::CreateFromAscii("_tmp"); + myStr2.Append(aTemp22); + + ByteString test(myStr2,RTL_TEXTENCODING_ASCII_US); + SvFileStream aOutStream( myStr2, STREAM_STD_WRITE | STREAM_TRUNC ); + if ( !aOutStream.IsOpen()) { + ByteString test2(myStr2,RTL_TEXTENCODING_ASCII_US); + fprintf( stderr,"ERROR: Unable to open file %s for modification!\n", test2.GetBuffer()); + aInStream.Close(); + } + + else { + ByteString sLine; + aOutStream.SetLineDelimiter( LINEEND_LF ); + + aInStream.ReadLine( sLine ); + while ( !aInStream.IsEof()) { + aOutStream.WriteLine( sLine ); + aInStream.ReadLine( sLine ); + } + aInStream.Close(); + aOutStream.Close(); + + + DirEntry myTempFile(ByteString(myStr2,RTL_TEXTENCODING_ASCII_US)); // xxx_tmp -> + DirEntry myFile(ByteString(aEntry.GetFull(),RTL_TEXTENCODING_ASCII_US));// xxx + + DirEntry oldFile(ByteString(aEntry.GetFull(),RTL_TEXTENCODING_ASCII_US)); + + if(oldFile.Kill()==ERRCODE_NONE){ + if(myTempFile.MoveTo(myFile)!=ERRCODE_NONE){ + fprintf( stderr, "ERROR: Can't rename file %s\n",ByteString(myStr2,RTL_TEXTENCODING_ASCII_US).GetBuffer()); + } + } + else{ + fprintf( stderr, "ERROR: Can't remove file %s\n",ByteString(aEntry.GetFull(),RTL_TEXTENCODING_ASCII_US).GetBuffer()); + } + } // else + + aOldCWD.SetCWD(); + aOut.Kill(); + } // else + } + return TRUE; +} +/*****************************************************************************/ +BOOL SourceTreeLocalizer::ExecuteMerge( ) +/*****************************************************************************/ +{ + DirEntry aEntry( Export::GetTempFile()); + BOOL bReturn = TRUE; + bool bMerged = false; + + ByteString sFileName; + ByteString sCurFile; + ByteString sLine; + ByteString sFileKey; + + SvFileStream aFile; + + ByteString sOutputFileName = sOutputFile; + ByteString sInpath("."); + sInpath += Export::GetEnv("INPATH"); + ByteString sBlank(""); + + sOutputFileName.SearchAndReplaceAll( sInpath , sBlank ); + + String sDel = DirEntry::GetAccessDelimiter(); + ByteString sBDel( sDel.GetBuffer() , sDel.Len() , RTL_TEXTENCODING_UTF8 ); + if( bLocal ){ + xub_StrLen nPos = sOutputFileName.SearchBackward( sBDel.GetChar(0) ); + sOutputFileName = sOutputFileName.Copy( nPos+1 , sOutputFileName.Len()-nPos-1 ); + } + ByteStringBoolHashMap aFileHM; + // Read all possible files + while ( !aSDF.IsEof()) { + aSDF.ReadLine( sLine ); + sFileName = sLine.GetToken( 0, '\t' ); + sFileName += "#"; + sFileName += sLine.GetToken( 1, '\t' ); + aFileHM[sFileName]=true; + } + + for( ByteStringBoolHashMap::iterator iter = aFileHM.begin(); iter != aFileHM.end(); ++iter ){ + sFileKey = iter->first; + aSDF.Seek( 0 ); + aFile.Open( aEntry.GetFull(), STREAM_STD_WRITE |STREAM_TRUNC ); + + while ( !aSDF.IsEof()) { + aSDF.ReadLine( sLine ); + sFileName = sLine.GetToken( 0, '\t' ); + sFileName += "#"; + sFileName += sLine.GetToken( 1, '\t' ); + if( sFileName.Len() && ( sFileName.CompareTo(sFileKey) == COMPARE_EQUAL ) ){ + if ( aFile.IsOpen() && sLine.Len()) + aFile.WriteLine( sLine ); + } + } + if ( aFile.IsOpen()) + aFile.Close(); + + ByteString sPrj( sFileKey.GetToken( 0, '#' )); + ByteString sFile( sFileKey.GetToken( 1, '#' )); + ByteString sSDFFile( aFile.GetFileName(), RTL_TEXTENCODING_ASCII_US ); + + //printf("localize test sPrj = %s , sFile = %s , sSDFFile = %s sOutputFileName = %s\n",sPrj.GetBuffer(), sFile.GetBuffer() , sSDFFile.GetBuffer() , sOutputFileName.GetBuffer() ); + + // Test + bLocal = true; + // Test + + if( bLocal ){ + USHORT nPos = sFile.SearchBackward( '\\' ); + ByteString sTmp = sFile.Copy( nPos+1 , sFile.Len()-nPos-1 ); + //printf("'%s'='%s'\n",sTmp.GetBuffer(), sOutputFileName.GetBuffer()); + if( sTmp.CompareTo(sOutputFileName) == COMPARE_EQUAL ){ + bMerged = true; + if ( !MergeSingleFile( sPrj, sFile, sSDFFile )) + bReturn = FALSE; + }else{ + bMerged = true; + //printf("MergeSingleFile('%s','%s','%s')\n",sPrj.GetBuffer(),sFile.GetBuffer(),sSDFFile.GetBuffer()); + if ( !MergeSingleFile( sPrj, sFile, sSDFFile )) + bReturn = FALSE; + } + } + } + aEntry.Kill(); + // If Outputfile not included in the SDF file copy it without merge + + if( bLocal && !bMerged ){ + DirEntry aSourceFile( sOutputFileName.GetBuffer() ); + FSysError aErr = aSourceFile.CopyTo( DirEntry ( sOutputFile.GetBuffer() ) , FSYS_ACTION_COPYFILE ); + if( aErr != FSYS_ERR_OK ){ + printf("ERROR: Can't copy file '%s' to '%s' %d\n",sOutputFileName.GetBuffer(),sOutputFile.GetBuffer(),sal::static_int_cast<int>(aErr)); + } + } + return bReturn; + +} + +/*****************************************************************************/ +BOOL SourceTreeLocalizer::Merge( const ByteString &rSourceFile , const ByteString &rOutput ) +/*****************************************************************************/ +{ + sOutputFile = rOutput; + nMode = LOCALIZE_MERGE; + aSDF.Open( String( rSourceFile, RTL_TEXTENCODING_ASCII_US ), + STREAM_STD_READ ); + + BOOL bReturn = aSDF.IsOpen(); + if ( bReturn ) { + bReturn = ExecuteMerge(); +// aSDF.Close(); + } + aSDF.Close(); + nMode = LOCALIZE_NONE; + return bReturn; +} + +} +using namespace transex3; + +#define STATE_NONE 0x0000 +#define STATE_EXPORT 0x0001 +#define STATE_MERGE 0x0002 +#define STATE_ISOCODE 0x0003 +#define STATE_LANGUAGES 0x0004 +#define STATE_FILENAME 0x0005 +#define STATE_OUTPUT 0x0006 + +/*****************************************************************************/ +void Help() +/*****************************************************************************/ +{ + fprintf( stdout, + "localize (c)2001 by Sun Microsystems\n" + "====================================\n" ); + fprintf( stdout, + "As part of the L10N framework, localize extracts and merges translations\n" + "out of and into the whole source tree.\n\n" + "Syntax: localize -e -l en-US -f FileName \n" + "Parameter:\n" + "\t-e: Extract mode\n" + "\tFileName: Output file when extract mode, input file when merge mode\n" + "\tl1...ln: supported languages (\"all\" for all languages).\n" + ); + + fprintf( stdout, + "Valid language codes for l1...ln and f1...fn are:\n" ); + fprintf( stdout, + "\nExample 1:\n" + "==========\n" + "localize -e -l en-US -f MyFile\n\n" + "All strings will be extracted for language de and language en-US.\n" + ); +} + +/*****************************************************************************/ +int Error() +/*****************************************************************************/ +{ + Help(); + return 1; +} + +/*****************************************************************************/ +BOOL CheckLanguages( ByteString &rLanguages ) +/*****************************************************************************/ +{ + ByteString sTmp( rLanguages ); + return true; +} + +/*****************************************************************************/ +#if defined(UNX) || defined(OS2) +int main( int argc, char *argv[] ) +#else +int _cdecl main( int argc, char *argv[] ) +#endif +/*****************************************************************************/ +{ + String sTempBase( String::CreateFromAscii( "loc" )); + DirEntry::SetTempNameBase( sTempBase ); + USHORT nState = STATE_NONE; + + BOOL bExport = FALSE; + BOOL bMerge = FALSE; + bool bSkipLinks = false; + + ByteString sLanguages; + ByteString sFileName; + ByteString sOutput; + + bExport = TRUE; + + for( int i = 1; i < argc; i++ ) { + ByteString sSwitch( argv[ i ] ); + sSwitch.ToUpperAscii(); + + if ( sSwitch.Equals( "-E" )) { + nState = STATE_EXPORT; + if ( bMerge ) + return Error(); + bExport = TRUE; + } + else if ( sSwitch.Equals( "-I" ) ) + nState = STATE_ISOCODE; + else if ( sSwitch.Equals( "-L" ) ) + nState = STATE_LANGUAGES; + else if ( sSwitch.Equals( "-F" ) ) + nState = STATE_FILENAME; + else if ( ByteString( argv[ i ]).ToUpperAscii().Equals( "-O" ) ) + nState = STATE_OUTPUT; + else { + switch ( nState ) { + case STATE_NONE: + return Error(); + case STATE_OUTPUT: + if ( sOutput.Len()) + return Error(); + sOutput = ByteString( argv[ i ] ); + nState = STATE_NONE; + break; + case STATE_LANGUAGES: + if ( sLanguages.Len()) + return Error(); + sLanguages = ByteString( argv[ i ] ); + nState = STATE_NONE; + break; + case STATE_FILENAME: + if ( sFileName.Len()) + return Error(); + sFileName = ByteString( argv[ i ] ); + nState = STATE_NONE; + break; + default: + return Error(); + } + } + } + if ( !bMerge && !bExport ) { + Help(); + return 1; + } + + ByteString sSolarVer( Export::GetEnv( "WORK_STAMP" )); + ByteString sVersion( Export::GetEnv( "WORK_STAMP" )); + + if ( !sSolarVer.Len() || !sVersion.Len()) { + fprintf( stderr, "ERROR: No environment set!\n" ); + return 1; + } + + if ( !CheckLanguages( sLanguages )) + return 2; + + if ( !sFileName.Len()) { + fprintf( stderr, "ERROR: No filename given\n" ); + return 3; + } + + DirEntry aEntry( String( sFileName , RTL_TEXTENCODING_ASCII_US )); + aEntry.ToAbs(); + String sFullEntry = aEntry.GetFull(); + ByteString sFileABS( aEntry.GetFull(), gsl_getSystemTextEncoding()); + //printf("B %s\nA %s\n",rDestinationFile.GetBuffer(), sFile.GetBuffer()); + sFileName = sFileABS; + + Treeconfig treeconfig; + vector<string> repos; + bool hasPwd = treeconfig.getActiveRepositories( repos ); + if( hasPwd ) cout << "Found special path!\n"; + + string minor_ext; + bool has_minor_ext; + + if( Export::GetEnv("UPDMINOREXT") != NULL ) + { + minor_ext = string( Export::GetEnv("UPDMINOREXT") ); + has_minor_ext = minor_ext.size(); + } + else + has_minor_ext = false; + + // localize through all repositories + for( vector<string>::iterator iter = repos.begin(); iter != repos.end() ; ++iter ) + { + string curRepository; + if( has_minor_ext ) + curRepository = string( Export::GetEnv("SOURCE_ROOT_DIR") ) + "/" + *iter + minor_ext; + else + curRepository = string( Export::GetEnv("SOURCE_ROOT_DIR") ) + "/" + *iter; + cout << "Localizing repository " << curRepository << "\n"; + SourceTreeLocalizer aIter( ByteString( curRepository.c_str() ) , sVersion , (sOutput.Len() > 0) , bSkipLinks ); + aIter.SetLanguageRestriction( sLanguages ); + if ( bExport ){ + fflush( stdout ); + if( *iter == "ooo" ) + aIter.Extract( sFileName ); + else + { + ByteString sFileNameWithExt( sFileName ); + sFileNameWithExt += ByteString( "." ); + sFileNameWithExt += ByteString( (*iter).c_str() ); + aIter.Extract( sFileNameWithExt ); + } + printf("\n%d files found!\n",aIter.GetFileCnt()); + } + } + if( hasPwd ) + { + string pwd; + Export::getCurrentDir( pwd ); + cout << "Localizing repository " << pwd << "\n"; + SourceTreeLocalizer aIter( ByteString( pwd.c_str() ) , sVersion , (sOutput.Len() > 0) , bSkipLinks ); + aIter.SetLanguageRestriction( sLanguages ); + if ( bExport ){ + fflush( stdout ); + aIter.Extract( sFileName ); + printf("\n%d files found!\n",aIter.GetFileCnt()); + } + + } + + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/makefile.mk b/l10ntools/source/makefile.mk new file mode 100644 index 000000000000..fc4203b0d9d3 --- /dev/null +++ b/l10ntools/source/makefile.mk @@ -0,0 +1,199 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=.. + +INCPRE=$(MISC) + +PRJNAME=l10ntools +TARGET=transex +TARGETTYPE=CUI +LIBTARGET=no +# --- Settings ----------------------------------------------------- +ENABLE_EXCEPTIONS=TRUE + +.INCLUDE : settings.mk +CDEFS+= -DYY_NEVER_INTERACTIVE=1 +#CDEFS+= -pg + +.IF "$(SYSTEM_EXPAT)" == "YES" +CFLAGS+=-DSYSTEM_EXPAT +.ENDIF + + +# --- Files -------------------------------------------------------- + +OBJFILES= \ + $(OBJ)$/export.obj \ + $(OBJ)$/export2.obj \ + $(OBJ)$/merge.obj \ + $(OBJ)$/srciter.obj \ + $(OBJ)$/utf8conv.obj \ + $(OBJ)$/xmlparse.obj \ + $(OBJ)$/helpmerge.obj \ + $(OBJ)$/helpex.obj \ + $(OBJ)$/file.obj \ + $(OBJ)$/directory.obj + + +LIB1TARGET= $(LB)$/$(TARGET).lib +LIB1ARCHIV= $(LB)$/libtransex.a +#LIB1FILES= $(LB)$/transex3.lib +LIB1OBJFILES= $(OBJ)$/export.obj \ + $(OBJ)$/export2.obj \ + $(OBJ)$/merge.obj \ + $(OBJ)$/srciter.obj \ + $(OBJ)$/file.obj \ + $(OBJ)$/directory.obj \ + $(OBJ)$/utf8conv.obj + + +APP1VERSIONMAP=exports.map + +# extractor and merger for *.src and *.hrc +APP1TARGET= transex3 +#APP1OBJS= $(OBJ)$/src_yy.obj +APP1OBJS= $(OBJ)$/src_yy_wrapper.obj + +APP1STDLIBS+= \ + $(TOOLSLIB) \ + $(SALLIB) + +.IF "$(OS)"=="MACOSX" +# static libs at end for OS X +.ENDIF + +APP1LIBS+= $(LB)$/$(TARGET).lib +APP1DEPN= $(OBJ)$/src_yy_wrapper.obj $(LB)$/$(TARGET).lib + +APP2TARGET= helpex +APP2OBJS= $(OBJ)$/helpmerge.obj $(OBJ)$/xmlparse.obj $(OBJ)$/export2.obj $(OBJ)$/utf8conv.obj $(OBJ)$/merge.obj $(OBJ)$/helpex.obj +APP2RPATH= NONE + +.IF "$(OS)"!="MACOSX" +.ENDIF + +APP2STDLIBS+=$(SALLIB) $(EXPATASCII3RDLIB) $(TOOLSLIB) + +.IF "$(OS)"=="MACOSX" +# static libs at end for OS X +.ENDIF + +# extractor and merger for *.lng and *.lng +APP3TARGET= ulfex +APP3OBJS= $(OBJ)$/lngmerge.obj $(OBJ)$/merge.obj $(OBJ)$/export2.obj $(OBJ)$/lngex.obj $(OBJ)$/utf8conv.obj +APP3RPATH= NONE + +.IF "$(OS)"!="MACOSX" +#APP3STDLIBS+= $(BTSTRPLIB) +.ENDIF +APP3STDLIBS+= \ + $(TOOLSLIB) \ + $(SALLIB) +.IF "$(OS)"=="MACOSX" +# static libs at end for OS X +.ENDIF + +# encoding converter for *.gsi +APP4TARGET= gsiconv +APP4OBJS= $(OBJ)$/utf8conv.obj $(OBJ)$/gsiconv.obj +APP4STDLIBS+= \ + $(TOOLSLIB) \ + $(SALLIB) + +# tag checker for *.gsi +APP5TARGET= gsicheck +APP5OBJS= $(OBJ)$/gsicheck.obj $(OBJ)$/tagtest.obj +APP5STDLIBS+= \ + $(TOOLSLIB) \ + $(SALLIB) + +# extractor and merger for *.cfg +APP6TARGET= cfgex +APP6OBJS= $(OBJ)$/cfgmerge.obj $(OBJ)$/cfg_yy_wrapper.obj $(OBJ)$/merge.obj $(OBJ)$/export2.obj $(OBJ)$/utf8conv.obj + +.IF "$(OS)"!="MACOSX" +#APP6STDLIBS+= $(BTSTRPLIB) +.ENDIF + +APP6STDLIBS+= \ + $(TOOLSLIB) \ + $(SALLIB) + +.IF "$(OS)"=="MACOSX" +# static libs at end for OS X +.ENDIF + +# extractor and merger for *.xrm +APP7TARGET= xrmex +APP7OBJS= $(OBJ)$/xrmmerge.obj $(OBJ)$/xrm_yy_wrapper.obj $(OBJ)$/merge.obj $(OBJ)$/export2.obj $(OBJ)$/utf8conv.obj +APP7RPATH= NONE + +.IF "$(OS)"!="MACOSX" +.ENDIF + +APP7STDLIBS+= \ + $(TOOLSLIB) \ + $(SALLIB) + +.IF "$(OS)"=="MACOSX" +# static libs at end for OS X +.ENDIF + +# +#APP8TARGET= treeconfig +#APP8OBJS= $(OBJ)$/treeconfig.obj $(OBJ)$/inireader.obj $(OBJ)$/export2.obj +#APP8STDLIBS=$(TOOLSLIB) $(SALLIB) $(ICUINLIB) $(STLPORT) + +# localizer for l10n framework +APP9TARGET= localize_sl +EXCEPTIONSFILES= \ + $(OBJ)$/localize.obj +APP9OBJS= $(OBJ)$/localize.obj $(OBJ)$/utf8conv.obj $(OBJ)$/srciter.obj $(OBJ)$/export2.obj $(OBJ)$/file.obj $(OBJ)$/directory.obj $(OBJ)$/treeconfig.obj $(OBJ)$/inireader.obj + +APP9STDLIBS+= \ + $(TOOLSLIB) \ + $(ICUINLIB) \ + $(ICUUCLIB) \ + $(STLPORTLIB) \ + $(SALLIB) + +DEPOBJFILES=$(APP1OBJS) $(APP2OBJS) $(APP3OBJS) $(APP4OBJS) $(APP5OBJS) $(APP6OBJS) $(APP7OBJS) $(APP8OBJS) $(APP9OBJS) + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + +$(MISC)$/%_yy.c : %lex.l + flex -l -w -8 -o$@ $< + +# Helper to suppress warnings in lex generated c code, see #i57362# + +$(OBJ)$/src_yy_wrapper.obj: $(MISC)$/src_yy.c +$(OBJ)$/cfg_yy_wrapper.obj: $(MISC)$/cfg_yy.c +$(OBJ)$/xrm_yy_wrapper.obj: $(MISC)$/xrm_yy.c + diff --git a/l10ntools/source/merge.cxx b/l10ntools/source/merge.cxx new file mode 100644 index 000000000000..b85a75461926 --- /dev/null +++ b/l10ntools/source/merge.cxx @@ -0,0 +1,459 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_l10ntools.hxx" +#include <stdio.h> +#include <tools/fsys.hxx> +#include "export.hxx" +#include "utf8conv.hxx" +#include <iostream> + +using namespace std; + +extern void ConvertHalfwitdhToFullwidth( String& rString ); + +// +// class PFormEntrys +// + +ByteString PFormEntrys::Dump(){ + ByteString sRet( "PFormEntrys\n" ); + //sRet.Append( Export::DumpMap( ByteString("sText") , sText ) ); + //sRet.Append("\n"); + ByteString a("sText"); + if ( sText.size() ) Export::DumpMap( a , sText ); + return sRet; +} + +BOOL PFormEntrys::GetTransex3Text( ByteString &rReturn, + USHORT nTyp, const ByteString &nLangIndex, BOOL bDel ) +{ + BOOL rc = GetText( rReturn , nTyp , nLangIndex , bDel ); + ByteString test( rReturn ); + for( USHORT idx = 0; idx < rReturn.Len(); idx++ ) + { + if( rReturn.GetChar( idx ) == '\"' && ( idx >= 1 ) && rReturn.GetChar( idx-1 ) == '\\' ) + { + rReturn.Erase( idx-1 , 1 ); + } + } + //if( !rReturn.Equals( test ) ) + // printf("*CHANGED******************\n%s\n%s\n",test.GetBuffer(),rReturn.GetBuffer()); + return rc; +} +/*****************************************************************************/ +BOOL PFormEntrys::GetText( ByteString &rReturn, + USHORT nTyp, const ByteString &nLangIndex, BOOL bDel ) +/*****************************************************************************/ +{ + + /*printf("DBG: PFormEntrys::GetText(nId=%s)\n",nLangIndex.GetBuffer() ); + + // DEBUG****************** + ByteStringHashMap::const_iterator idbg; + std::cout << "HASHKEYS : \n"; + for( idbg = sText.begin() ; idbg != sText.end(); ++idbg ) + std::cout << (idbg->first).GetBuffer() << "\n"; + std::cout << "\n\n"; + std::cout << "String sText[ nLangIndex ] = " << sText[ nLangIndex ].GetBuffer() << "\n"; + // DEBUG****************** +*/ + + BOOL bReturn=TRUE; + switch ( nTyp ) { + case STRING_TYP_TEXT : + rReturn = sText[ nLangIndex ]; + if ( bDel ) + sText[ nLangIndex ] = ""; + bReturn = bTextFirst[ nLangIndex ]; + bTextFirst[ nLangIndex ] = FALSE; + break; + case STRING_TYP_HELPTEXT : + rReturn = sHelpText; + break; + case STRING_TYP_QUICKHELPTEXT : + rReturn = sQuickHelpText[ nLangIndex ]; + if ( bDel ) + sQuickHelpText[ nLangIndex ] = ""; + bReturn = bQuickHelpTextFirst[ nLangIndex ]; + bQuickHelpTextFirst[ nLangIndex ] = FALSE; + break; + case STRING_TYP_TITLE : + rReturn = sTitle[ nLangIndex ]; + if ( bDel ) + sTitle[ nLangIndex ] = ""; + bReturn = bTitleFirst[ nLangIndex ]; + bTitleFirst[ nLangIndex ] = FALSE; + break; + } + //printf("Returning '%s'\n",rReturn.GetBuffer()); + return bReturn; +} + + +// +// class MergeData +// + +/*****************************************************************************/ +MergeData::~MergeData() +/*****************************************************************************/ +{ +} + +/*****************************************************************************/ +PFormEntrys* MergeData::GetPFormEntrys( ResData *pResData ) +/*****************************************************************************/ +{ + + (void) pResData; // FIXME + if( aMap.find( ByteString("HACK") ) != aMap.end() ){ + return aMap[ ByteString("HACK") ]; + } + else{ + return 0; + } +} + +void MergeData::Insert( const ByteString& rPFO , PFormEntrys* pfEntrys ){ + (void) rPFO; // FIXME + aMap.insert( PFormEntrysHashMap::value_type( ByteString("HACK") , pfEntrys ) ); + +} +ByteString MergeData::Dump(){ + ByteString sRet( "MergeData\n" ); + + printf("MergeData sTyp = %s , sGid = %s , sLid =%s , sFilename = %s\n",sTyp.GetBuffer(),sGID.GetBuffer(),sLID.GetBuffer(), sFilename.GetBuffer() ); + + PFormEntrysHashMap::const_iterator idbg; + for( idbg = aMap.begin() ; idbg != aMap.end(); ++idbg ){ + printf("aMap[ %s ] = " ,idbg->first.GetBuffer()); + ( (PFormEntrys*)(idbg->second) )->Dump(); + printf("\n") ; + } + printf("\n") ; + return sRet; +} + +PFormEntrys* MergeData::GetPFObject( const ByteString& rPFO ){ + if( aMap.find( ByteString("HACK") ) != aMap.end() ){ + return aMap[ rPFO ]; + } + else{ + return 0; + } +} + + +/*****************************************************************************/ +PFormEntrys *MergeData::InsertEntry( const ByteString &rPForm ) +/*****************************************************************************/ +{ + PFormEntrys* pFEntrys = new PFormEntrys( rPForm ); + aMap.insert( PFormEntrysHashMap::value_type( rPForm , pFEntrys ) ); + return pFEntrys; +} + +/*****************************************************************************/ +BOOL MergeData::operator==( ResData *pData ) +/*****************************************************************************/ +{ + ByteString sResTyp_upper( pData->sResTyp ); + sResTyp_upper.ToUpperAscii(); + ByteString sTyp_upper( sTyp ); + sTyp_upper.ToUpperAscii(); + + return (( pData->sId == sLID ) && + ( pData->sGId == sGID ) && + ( sResTyp_upper == sTyp_upper ) + ); +} + +// +// class MergeDataFile +// + +#define FFORMAT_UNKNOWN 0x0000 +#define FFORMAT_NEW 0x0001 +#define FFORMAT_OLD 0x0002 + +/*****************************************************************************/ +MergeDataFile::MergeDataFile( const ByteString &rFileName, const ByteString& sFile ,BOOL bErrLog, +// CharSet aCharSet, BOOL bUTF8 , bool bCaseSensitive ) + CharSet aCharSet, bool bCaseSensitive ) + +/*****************************************************************************/ + : bErrorLog( bErrLog ) +{ + + SvFileStream aInputStream( String( rFileName, RTL_TEXTENCODING_ASCII_US ), STREAM_STD_READ ); + aInputStream.SetStreamCharSet( aCharSet ); + ByteString sLine; +// printf("\nReading localize.sdf ...\n"); + ByteString sTYP; + ByteString sGID; + ByteString sLID; + ByteString sPFO; + ByteString nLANG; + ByteString sTEXT; + ByteString sQHTEXT; + ByteString sTITLE; + ByteString sHACK("HACK"); + + const ByteString sEmpty(""); + + if( !aInputStream.IsOpen() ) { + printf("Warning : Can't open %s\n", rFileName.GetBuffer()); + //exit( -1 ); + return; + } + while ( !aInputStream.IsEof()) { + xub_StrLen nToks; + aInputStream.ReadLine( sLine ); + sLine = sLine.Convert( RTL_TEXTENCODING_MS_1252, aCharSet ); + + nToks = sLine.GetTokenCount( '\t' ); + if ( nToks == 15 ) { + // Skip all wrong filenames + ByteString filename = sLine.GetToken( 1 , '\t' ); + filename = filename.Copy( filename.SearchCharBackward( "\\" )+1 , filename.Len() ); + + if( sFile.Equals( sEmpty ) || ( !sFile.Equals( sEmpty ) && filename.Equals( sFile ) ) ) + { + xub_StrLen rIdx = 0; + sTYP = sLine.GetToken( 3, '\t', rIdx ); + sGID = sLine.GetToken( 0, '\t', rIdx ); // 4 + sLID = sLine.GetToken( 0, '\t', rIdx ); // 5 + sPFO = sLine.GetToken( 1, '\t', rIdx ); // 7 + sPFO = sHACK; + nLANG = sLine.GetToken( 1, '\t', rIdx ); // 9 + sTEXT = sLine.GetToken( 0, '\t', rIdx ); // 10 + + sQHTEXT = sLine.GetToken( 1, '\t', rIdx ); // 12 + sTITLE = sLine.GetToken( 0, '\t', rIdx ); // 13 + + nLANG.EraseLeadingAndTrailingChars(); + +#ifdef MERGE_SOURCE_LANGUAGES + if( true ){ +#else + if ( !nLANG.EqualsIgnoreCaseAscii("en-US") ){ +#endif + ByteStringHashMap::const_iterator lit; + lit = aLanguageMap.find (nLANG); + ByteString aLANG; + if (lit == aLanguageMap.end()) { + aLANG = nLANG; + aLanguageMap.insert( ByteStringHashMap::value_type( aLANG, aLANG ) ); + // Remember read languages for -l all switch + aLanguageList.push_back( nLANG ); + } else + aLANG = lit->first; + + InsertEntry( sTYP, sGID, sLID, sPFO, aLANG, sTEXT, sQHTEXT, sTITLE , filename , bCaseSensitive ); + } + } + } + else if ( nToks == 10 ) { + printf("ERROR: File format is obsolete and no longer supported!\n"); + } + } + aInputStream.Close(); +} +/*****************************************************************************/ +MergeDataFile::~MergeDataFile() +/*****************************************************************************/ +{ +} + +/*****************************************************************************/ +//void MergeDataFile::WriteErrorLog( const ByteString &rFileName ) +/*****************************************************************************/ +//{ +// DEAD +//} + +ByteString MergeDataFile::Dump(){ + ByteString sRet( "MergeDataFile\n" ); + + //sRet.Append( Export::DumpMap( "aLanguageSet" , aLanguageSet ) ); + //sRet.Append( Export::DumpMap( "aLanguageList" , aLanguageList ) ); + printf("MergeDataFile\n"); + MergeDataHashMap::const_iterator idbg; + for( idbg = aMap.begin() ; idbg != aMap.end(); ++idbg ){ + /*sRet.Append( "aMap[" ); + sRet.Append( idbg->first ); + sRet.Append( "]= " ); + sRet.Append( ((MergeData*) (idbg->second))->Dump() ); + sRet.Append("\n");*/ + + printf("aMap[ %s ] = ",idbg->first.GetBuffer()); + ((MergeData*) (idbg->second))->Dump(); + printf("\n"); + } + printf("\n"); + //sRet.Append("\n"); + return sRet; +} + +/*****************************************************************************/ +void MergeDataFile::WriteError( const ByteString &rLine ) +/*****************************************************************************/ +{ + if ( bErrorLog ) { + if ( !aErrLog.IsOpen()) + aErrLog.Open( String( sErrorLog, RTL_TEXTENCODING_ASCII_US ), STREAM_STD_WRITE | STREAM_TRUNC ); + aErrLog.WriteLine( rLine ); + } + else + fprintf( stderr, "%s\n", rLine.GetBuffer()); +} +std::vector<ByteString> MergeDataFile::GetLanguages(){ + return aLanguageList; +} + +/*****************************************************************************/ +MergeData *MergeDataFile::GetMergeData( ResData *pResData , bool bCaseSensitive ) +/*****************************************************************************/ +{ + ByteString sOldG = pResData->sGId; + ByteString sOldL = pResData->sId; + ByteString sGID = pResData->sGId; + ByteString sLID; + if ( !sGID.Len()) + sGID = pResData->sId; + else + sLID = pResData->sId; + pResData->sGId = sGID; + pResData->sId = sLID; + //printf("MergeData:: Search gid=%s lid=%s filename=%s \n", pResData->sGId.GetBuffer(),pResData->sId.GetBuffer(),pResData->sFilename.GetBuffer() ); + ByteString sKey = CreateKey( pResData->sResTyp , pResData->sGId , pResData->sId , pResData->sFilename , bCaseSensitive ); + + //printf("DBG: Searching [%s]\n",sKey.GetBuffer()); + if( aMap.find( sKey ) != aMap.end() ){ + pResData->sGId = sOldG; + pResData->sId = sOldL; + //printf("DBG: Found[%s]\n",sKey.GetBuffer()); + return aMap[ sKey ]; + } + //Dump(); + pResData->sGId = sOldG; + pResData->sId = sOldL; + //printf("DBG: Found[%s]\n",sKey.GetBuffer()); + return NULL; +} + + +/*****************************************************************************/ +PFormEntrys *MergeDataFile::GetPFormEntrys( ResData *pResData ) +/*****************************************************************************/ +{ + // search for requested PFormEntrys + MergeData *pData = GetMergeData( pResData ); + if ( pData ) + return pData->GetPFormEntrys( pResData ); + return NULL; +} + +/*****************************************************************************/ +PFormEntrys *MergeDataFile::GetPFormEntrysCaseSensitive( ResData *pResData ) +/*****************************************************************************/ +{ + // search for requested PFormEntrys + MergeData *pData = GetMergeData( pResData , true ); + if ( pData ) + return pData->GetPFormEntrys( pResData ); + return NULL; +} +/*****************************************************************************/ +void MergeDataFile::InsertEntry( + const ByteString &rTYP, const ByteString &rGID, + const ByteString &rLID, const ByteString &rPFO, + const ByteString &nLANG, const ByteString &rTEXT, + const ByteString &rQHTEXT, const ByteString &rTITLE , + const ByteString &rInFilename , bool bCaseSensitive + ) +/*****************************************************************************/ +{ + MergeData *pData; + + // uniquify the filename to save memory. + ByteStringHashMap::const_iterator fit = aFilenames.find (rInFilename); + ByteString aFilename; + if (fit == aFilenames.end()) { + aFilename = rInFilename; + aFilenames.insert (ByteStringHashMap::value_type (aFilename, aFilename)); + } else + aFilename = fit->first; + + // search for MergeData + + ByteString sKey = CreateKey( rTYP , rGID , rLID , aFilename , bCaseSensitive ); + MergeDataHashMap::const_iterator mit; + mit = aMap.find( sKey ); + if( mit != aMap.end() ){ + pData = mit->second; + }else{ + pData = new MergeData( rTYP, rGID, rLID, aFilename ); + aMap.insert( MergeDataHashMap::value_type( sKey, pData ) ); + } + + PFormEntrys *pFEntrys = 0; + + // search for PFormEntrys + + pFEntrys = pData->GetPFObject( rPFO ); + if( !pFEntrys ){ + // create new PFormEntrys, cause no one exists with current properties + pFEntrys = new PFormEntrys( rPFO ); + pData->Insert( rPFO , pFEntrys ); + } + + // finaly insert the cur string + + pFEntrys->InsertEntry( nLANG , rTEXT, rQHTEXT, rTITLE ); + + //printf("DBG: MergeDataFile::Insert[]=( sKey=%s,nLang=%s,rTEXT=%s)\n",sKey2.GetBuffer(),nLANG.GetBuffer(),rTEXT.GetBuffer()); +} +ByteString MergeDataFile::CreateKey( const ByteString& rTYP , const ByteString& rGID , const ByteString& rLID , const ByteString& rFilename , bool bCaseSensitive ){ + + ByteString sKey( rTYP ); + sKey.Append( '-' ); + sKey.Append( rGID ); + sKey.Append( '-' ); + sKey.Append( rLID ); + sKey.Append( '-' ); + sKey.Append( rFilename ); + + if( bCaseSensitive ) return sKey; // officecfg case sensitive identifier + else return sKey.ToUpperAscii(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/src_yy_wrapper.c b/l10ntools/source/src_yy_wrapper.c new file mode 100644 index 000000000000..974068de2d88 --- /dev/null +++ b/l10ntools/source/src_yy_wrapper.c @@ -0,0 +1,5 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +// Helper to suppress warnings in lex generated c code, see #i57362# +#include "src_yy.c" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/srciter.cxx b/l10ntools/source/srciter.cxx new file mode 100644 index 000000000000..eb5d78f775af --- /dev/null +++ b/l10ntools/source/srciter.cxx @@ -0,0 +1,141 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_l10ntools.hxx" + +#include "srciter.hxx" +#include <stdio.h> +#include <tools/fsys.hxx> + +// +// class SourceTreeIterator +// + +/*****************************************************************************/ +SourceTreeIterator::SourceTreeIterator( + const ByteString &rRootDirectory, const ByteString &rVersion , bool bLocal_in ) +/*****************************************************************************/ + : bInExecute( FALSE ) , bLocal( bLocal_in ) +{ + (void) rVersion ; + + if(!bLocal){ + rtl::OUString sRootDirectory( rRootDirectory.GetBuffer() , rRootDirectory.Len() , RTL_TEXTENCODING_UTF8 ); + aRootDirectory = transex::Directory( sRootDirectory ); + } +} + +/*****************************************************************************/ +SourceTreeIterator::~SourceTreeIterator() +/*****************************************************************************/ +{ +} + +/*****************************************************************************/ +void SourceTreeIterator::ExecuteDirectory( transex::Directory& aDirectory ) +/*****************************************************************************/ +{ + if ( bInExecute ) { + rtl::OUString sDirName = aDirectory.getDirectoryName(); + + static rtl::OUString WCARD1 ( RTL_CONSTASCII_USTRINGPARAM("unxlng") ); + static rtl::OUString WCARD2 ( RTL_CONSTASCII_USTRINGPARAM("unxsol") ); + static rtl::OUString WCARD3 ( RTL_CONSTASCII_USTRINGPARAM("wntmsc") ); + static rtl::OUString WCARD4 ( RTL_CONSTASCII_USTRINGPARAM("common") ); + static rtl::OUString WCARD5 ( RTL_CONSTASCII_USTRINGPARAM("unxmac") ); + static rtl::OUString WCARD6 ( RTL_CONSTASCII_USTRINGPARAM("unxubt") ); + static rtl::OUString WCARD7 ( RTL_CONSTASCII_USTRINGPARAM(".svn") ); + + + if( sDirName.indexOf( WCARD1 , 0 ) > -1 || + sDirName.indexOf( WCARD2 , 0 ) > -1 || + sDirName.indexOf( WCARD3 , 0 ) > -1 || + sDirName.indexOf( WCARD4 , 0 ) > -1 || + sDirName.indexOf( WCARD5 , 0 ) > -1 || + sDirName.indexOf( WCARD6 , 0 ) > -1 || + sDirName.indexOf( WCARD7 , 0 ) > -1 + ) return; + //printf("**** %s \n", OUStringToOString( sDirName , RTL_TEXTENCODING_UTF8 , sDirName.getLength() ).getStr() ); + + rtl::OUString sDirNameTmp = aDirectory.getFullName(); + ByteString sDirNameTmpB( rtl::OUStringToOString( sDirNameTmp , RTL_TEXTENCODING_UTF8 , sDirName.getLength() ).getStr() ); + +#ifdef WNT + sDirNameTmpB.Append( ByteString("\\no_localization") ); +#else + sDirNameTmpB.Append( ByteString("/no_localization") ); +#endif + //printf("**** %s \n", OUStringToOString( sDirNameTmp , RTL_TEXTENCODING_UTF8 , sDirName.getLength() ).getStr() ); + + DirEntry aDE( sDirNameTmpB.GetBuffer() ); + if( aDE.Exists() ) + { + //printf("#### no_localization file found ... skipping"); + return; + } + + aDirectory.setSkipLinks( bSkipLinks ); + aDirectory.readDirectory(); + OnExecuteDirectory( aDirectory.getFullName() ); + if ( aDirectory.getSubDirectories().size() ) + for ( ULONG i=0;i < aDirectory.getSubDirectories().size();i++ ) + ExecuteDirectory( aDirectory.getSubDirectories()[ i ] ); + } +} + +/*****************************************************************************/ +BOOL SourceTreeIterator::StartExecute() +/*****************************************************************************/ +{ + + bInExecute = TRUE; // FIXME + ExecuteDirectory( aRootDirectory ); + + if ( bInExecute ) { // FIXME + bInExecute = FALSE; + return TRUE; + } + return FALSE; +} + +/*****************************************************************************/ +void SourceTreeIterator::EndExecute() +/*****************************************************************************/ +{ + bInExecute = FALSE; +} + +/*****************************************************************************/ +void SourceTreeIterator::OnExecuteDirectory( const rtl::OUString &rDirectory ) +/*****************************************************************************/ +{ + fprintf( stdout, "%s\n", rtl::OUStringToOString( rDirectory, RTL_TEXTENCODING_UTF8, rDirectory.getLength() ).getStr() ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/srclex.l b/l10ntools/source/srclex.l new file mode 100644 index 000000000000..eb2b6af78b34 --- /dev/null +++ b/l10ntools/source/srclex.l @@ -0,0 +1,302 @@ + +%{ +/* + * lexer for parsing ressource source files (*.src) + * + */ + + +/* enlarge token buffer to tokenize whole strings */ +#undef YYLMAX +#define YYLMAX 64000 + +/* to enable debug output define LEXDEBUG */ +#define LEXDEBUG 1 +#ifdef LEXDEBUG +#define OUTPUT fprintf +#else +#define OUTPUT(Par1,Par2); +#endif + +/* table of possible token ids */ +#include "tokens.h" +#include <stdlib.h> +#include <stdio.h> + +#if defined __GNUC__ +#pragma GCC system_header +#elif defined __SINPRO_CC +#pragma disable_warn +#elif defined _MSC_VER +#pragma warning(push, 1) +#endif + +/* external functions (C++ code, declared as extren "C" */ +extern int WorkOnTokenSet( int, char* ); +extern int InitExport( char * , char * ); +extern int Parse( int nTyp, char *pTokenText ); +extern int EndExport(); +extern int SetError(); +extern int GetError(); +extern char *GetOutputFile( int argc, char* argv[]); +extern FILE *GetNextFile(); +extern int isQuiet(); +extern void Close(); +extern char* getFilename(); + +/* forwards */ +void YYWarning(); +%} + +%p 24000 +%e 1200 +%n 500 + +%% + +^[\t ]*"#pragma".* { + WorkOnTokenSet( PRAGMA, yytext ); +} + +^[ \t]*\n { + WorkOnTokenSet( EMPTYLINE, yytext ); +} + +[\t ]+ | +^[\t ]*"#include".* | +^[\t ]*"#undef".* | +"//".* | +";" | +"<" | +">" | +\n { + WorkOnTokenSet( IGNOREDTOKENS, yytext ); +} +"/*" { + char c1 = 0, c2 = input(); + char pChar[2]; + pChar[1] = 0x00; + pChar[0] = c2; + + WorkOnTokenSet( COMMEND, yytext ); + WorkOnTokenSet( COMMEND, pChar ); + for(;;) { + if ( c2 == EOF ) + break; + if ( c1 == '*' && c2 == '/' ) + break; + c1 = c2; + c2 = input(); + pChar[0] = c2; + WorkOnTokenSet( COMMEND, pChar ); + } +} + +^[\t ]*"#ifndef".+$ | +^[\t ]*"#ifdef".+$ | +^[\t ]*"#if".+$ | +^[\t ]*"#elif".*$ | +^[\t ]*"#else".*$ | +^[\t ]*"#endif".*$ { + WorkOnTokenSet( CONDITION, yytext ); +} + +[a-zA-Z]+[\t ]+[^={\n]+[\t ] { +/* defined Res */ + WorkOnTokenSet( DEFINEDRES, yytext ); +} + +[a-zA-Z]+[ \t]+[^={;\n]+\n[ \t]*"#".*\n[ \t]*"{" | +[a-zA-Z]+[ \t]+[^={;\n]+\n?([ \t]*"//".*\n)*[ \t]*"{" { +/* RESSOURCE // String TTT_XX ... */ + WorkOnTokenSet( RESSOURCE, yytext ); +} + +^[\t ]*[a-zA-Z_]+[\t ]*"\\"?[\t ]*\n?[ \t]*"{"[\t ]*"\\"? { +/* SMALRESSOURCE // String ... */ + WorkOnTokenSet( SMALRESSOURCE, yytext ); +} + +[\t ]*[a-zA-Z0-9_]+[ \t]*("["[ \t]*[a-zA-Z0-9_\-]+[ \t]*"]"[ \t]*)?=[ \t]*L?\".*\".*\n? { +/* TEXTLINE // TextTyp = "A Text" */ + WorkOnTokenSet( TEXTLINE, yytext ); +} + +[\t ]*[a-zA-Z0-9_]+[ \t]*("["[ \t]*[a-zA-Z0-9_\-]+[ \t]*"]"[ \t]*)?(\n[ \t]*)?=([ \t]*\n)?(([a-zA-Z0-9_]+)|(\".*\")|([ \t\n]*))*\".*\"(([a-zA-Z0-9_]+)|(\".*\")|([ \t\n]*))*; { +/* LONGTEXTLINE // TextTyp = "A Text" HHH_XXX "A Text" ZZZ_TTT ... */ + WorkOnTokenSet( LONGTEXTLINE, yytext ); +} + +\".*\" { +/* TEXT // "A Text" */ + WorkOnTokenSet( TEXT, yytext ); +} + +"{"[ \t]*\\? { +/* LEVELUP */ + WorkOnTokenSet( LEVELUP, yytext ); +} + +"}"[ \t]*;([ \t]*\\)? { +/* LEVELDOWN */ + WorkOnTokenSet( LEVELDOWN, yytext ); +} + +[a-zA-Z0-9_]+[ \t]*"="[ \t]*"MAP_APPFONT"[ \t]*"(".+")".* { +/* APPFONTMAPPING Typ = MAP_APPFONT( ... ) */ + WorkOnTokenSet( APPFONTMAPPING, yytext ); +} + +[ \t]*[a-zA-Z0-9_]+[ \t]*=[ \t]*[0123456789]{1,5}[ \t]*";"?\\? { +/* TEXTREFID // TextTyp = 12345 */ + WorkOnTokenSet( TEXTREFID, yytext ); +} + +[a-zA-Z0-9_]+[ \t]*"="[\t ]*([ \t]*"//".*\n)*.* | +[a-zA-Z0-9_]+[ \t]*"=".* { +/* ASSIGNMENT Typ = ... */ + WorkOnTokenSet( ASSIGNMENT, yytext ); +} + + + +[a-zA-Z0-9_]+[ \t]*("["[ \t]*[a-zA-Z0-9_\-]+[ \t]*"]"[ \t]*)?"="[ \t]*(\\[ \t]*)?\n?[ \t]*"{"[ \t]*(\\[ \t]*)?\n?[ \t]*"<" { +/* LISTASSIGNMENT Typ [ ... ] = ... */ + WorkOnTokenSet( LISTASSIGNMENT, yytext ); +} + +"StringList"+[ \t]*("["[ \t]*[a-zA-Z0-9_\-]+[ \t]*"]"[ \t]*)?"="[ \t]*(\\[ \t]*)?\n?[ \t]*"{"[ \t]*(\\[ \t]*)?\n?[ \t]* { +/* LISTASSIGNMENT Typ [ ... ] = ... */ + WorkOnTokenSet( LISTASSIGNMENT, yytext ); +} + +"UIEntries"[ \t]*("["[ \t]*[a-zA-Z0-9_\-]+[ \t]*"]"[ \t]*)?"="[ \t]*(\\[ \t]*)?\n?[ \t]*"{" { +/* UIENTRIES */ + WorkOnTokenSet( UIENTRIES, yytext ); +} + +"<"?[ \t]*L?\".*\".*">" { +/* LISTTEXT */ + WorkOnTokenSet( LISTTEXT, yytext ); +} + +[ \t]*"#define"[ \t]+[a-zA-Z0-9_]+.*"\\" { +/* RSCDEFINE #define ... */ + WorkOnTokenSet( RSCDEFINE, yytext ); +} + +[ \t]*"#define"[ \t]+[a-zA-Z0-9_]+.+ { +/* #define ... */ + WorkOnTokenSet( NORMDEFINE, yytext ); +} + +"\\" { +/* RSCDEFINELEND */ + WorkOnTokenSet( RSCDEFINELEND, yytext ); +} + +[a-zA-Z0-9_]+[ \t]*; { +/* allowed other tokens like "49 ;" or "SFX_... ;" */ + WorkOnTokenSet( ANYTOKEN, yytext ); +} + +. { + WorkOnTokenSet( UNKNOWNCHAR, yytext ); +/* YYWarning( "Unknown Char" ); */ +} + +"{"?[ \t]*\".*\"[ \t]*";"[ \t]*"}" { +/* _LISTTEXT */ + WorkOnTokenSet( _LISTTEXT, yytext ); +} + +%% + +/*****************************************************************************/ +int yywrap(void) +/*****************************************************************************/ +{ + FILE *pFile; + pFile = GetNextFile(); + if ( pFile ) { + yyin = pFile; + yylineno = 0; + return 0; + } + + /* end of input reached */ + return 1; +} + +/*****************************************************************************/ +void YYWarning( char *s ) +/*****************************************************************************/ +{ + /* write warning to stderr */ + fprintf( stderr, "Warning: \"%s\" in line %d: \"%s\"\n", s, yylineno, yytext ); +} + +/*****************************************************************************/ +void yyerror( char *s ) +/*****************************************************************************/ +{ + /* write error to stderr */ + fprintf( stderr, "Error: \"%s\" in line %d: \"%s\"\n", s, yylineno, yytext ); + SetError(); +} + +/*****************************************************************************/ +int +#ifdef WNT +_cdecl +#endif +main( int argc, char* argv[]) +/*****************************************************************************/ +{ + /* error level */ + int nRetValue = 0; + char *pOutput; + FILE *pFile; + + pOutput = GetOutputFile( argc, argv ); + + if ( !pOutput ) { + fprintf( stdout, "Syntax:TRANSEX[-p Prj][-r PrjRoot]-i FileIn...[-o FileOut][-m DataBase][-e][-b][-u][-L l1,l2,...]\n" ); + fprintf( stdout, " Prj: Project\n" ); + fprintf( stdout, " PrjRoot: Path to project root (..\\.. etc.)\n" ); + fprintf( stdout, " FileIn: Source files (*.src)\n" ); + fprintf( stdout, " FileOut: Destination file (*.*)\n" ); + fprintf( stdout, " DataBase: Mergedata (*.sdf)\n" ); + fprintf( stdout, " -QQ: quiet output\n" ); + fprintf( stdout, " -e: Disable writing errorlog\n" ); + fprintf( stdout, " -b: Break when Token \"HelpText\" found in source\n" ); + fprintf( stdout, " -u: [english] and [german] are allowed, Id is Taken from DataBase \n" ); + fprintf( stdout, " -NOUTF8: disable UTF8 as language independent encoding\n" ); + fprintf( stdout, " -L: Restrict the handled languages. l1,l2,... are elements of (de,en-US...)\n" ); + fprintf( stdout, " A fallback language can be defined like this: l1=f1.\n" ); + fprintf( stdout, " f1, f2,... are also elements of (de,en-US...)\n" ); + fprintf( stdout, " Example: -L de,es=en-US\n" ); + fprintf( stdout, " Restriction to de and es, en-US will be fallback for es\n" ); + return 1; + } + + InitExport( pOutput , getFilename() ); + pFile = GetNextFile(); + if ( !pFile ) + return 1; + + yyin = pFile; + + /* create global instance of class Export */ + + /* start parser */ + yylex(); + Close(); + + /* get error info. and end export */ + nRetValue = GetError(); + EndExport(); + + /* return error level */ + return nRetValue; +} diff --git a/l10ntools/source/tagtest.cxx b/l10ntools/source/tagtest.cxx new file mode 100644 index 000000000000..30cbdd190291 --- /dev/null +++ b/l10ntools/source/tagtest.cxx @@ -0,0 +1,1555 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_l10ntools.hxx" +#include <tools/string.hxx> +#include "tagtest.hxx" + +#if OSL_DEBUG_LEVEL > 1 +#include <stdio.h> +#endif + +#include "gsicheck.hxx" + +#define HAS_FLAG( nFlags, nFlag ) ( ( nFlags & nFlag ) != 0 ) +#define SET_FLAG( nFlags, nFlag ) ( nFlags |= nFlag ) +#define RESET_FLAG( nFlags, nFlag ) ( nFlags &= ~nFlag ) // ~ = Bitweises NOT + + + +TokenInfo::TokenInfo( TokenId pnId, USHORT nP, String paStr, ParserMessageList &rErrorList ) +: bClosed(FALSE) +, bCloseTag(FALSE) +, bIsBroken(FALSE) +, bHasBeenFixed(FALSE) +, bDone(FALSE) +, aTokenString( paStr ) +, nId( pnId ) +, nPos(nP) +{ + if ( nId == TAG_COMMONSTART || nId == TAG_COMMONEND ) + SplitTag( rErrorList ); +} + +enum tagcheck { TC_START, TC_HAS_TAG_NAME, TC_HAS_PROP_NAME_EQ, TC_HAS_PROP_NAME_EQ_SP, TC_HAS_PROP_NAME_SP, TC_INSIDE_STRING, TC_PROP_FINISHED, TC_CLOSED, TC_CLOSED_SPACE, TC_CLOSETAG, TC_CLOSETAG_HAS_TAG_NAME, TC_FINISHED, TC_ERROR }; + +/* + \< link href = \"text\" name = \"C\" \> +START ' ' -> HAS_TAG_NAME +START '/' -> CLOSED +START '/' -> CLOSETAG - no Portion (starting with /) +START '>' -> FINISHED +HAS_TAG_NAME '=' -> HAS_PROP_NAME_EQ +HAS_TAG_NAME ' ' -> HAS_PROP_NAME_SP +HAS_TAG_NAME '/' -> CLOSED +HAS_TAG_NAME '>' -> FINISHED +HAS_PROP_NAME_SP '=' -> HAS_PROP_NAME_EQ +HAS_PROP_NAME_EQ ' ' -> HAS_PROP_NAME_EQ_SP +HAS_PROP_NAME_EQ '"' -> INSIDE_STRING +HAS_PROP_NAME_EQ_SP '"' -> INSIDE_STRING +INSIDE_STRING ' ' -> INSIDE_STRING +INSIDE_STRING '=' -> INSIDE_STRING +INSIDE_STRING '>' -> INSIDE_STRING +INSIDE_STRING '"' -> PROP_FINISHED +PROP_FINISHED ' ' -> HAS_TAG_NAME +PROP_FINISHED '/' -> CLOSED +PROP_FINISHED '>' -> FINISHED +CLOSED ' ' -> CLOSED_SPACE +CLOSED '>' -> FINISHED +CLOSED_SPACE '>' -> FINISHED + +CLOSETAG ' ' -> CLOSETAG_HAS_TAG_NAME +CLOSETAG '>' -> FINISHED +CLOSETAG_HAS_TAG_NAME '>' -> FINISHED + +*/ +void TokenInfo::SplitTag( ParserMessageList &rErrorList ) +{ + USHORT nLastPos = 2; // skip initial \< + USHORT nCheckPos = nLastPos; + String aDelims( String::CreateFromAscii( " \\=>/" ) ); + String aPortion; + String aValue; // store the value of a property + ByteString aName; // store the name of a property/tag + BOOL bCheckName = FALSE; + BOOL bCheckEmpty = FALSE; + sal_Unicode cDelim; + tagcheck aState = TC_START; + + // skip blanks + while ( nLastPos < aTokenString.Len() && aTokenString.GetChar( nLastPos ) == ' ') + nLastPos++; + + nCheckPos = aTokenString.SearchChar( aDelims.GetBuffer(), nLastPos ); + while ( nCheckPos != STRING_NOTFOUND && !( aState == TC_FINISHED || aState == TC_ERROR ) ) + { + aPortion = aTokenString.Copy( nLastPos, nCheckPos-nLastPos ); + + if ( aTokenString.GetChar( nCheckPos ) == '\\' ) + nCheckPos++; + + cDelim = aTokenString.GetChar( nCheckPos ); + nCheckPos++; + + switch ( aState ) + { +// START ' ' -> HAS_TAG_NAME +// START '/' -> CLOSED +// START '>' -> FINISHED + case TC_START: + aTagName = aPortion; + switch ( cDelim ) + { + case ' ': aState = TC_HAS_TAG_NAME; + bCheckName = TRUE; + break; + case '/': + { + if ( aPortion.Len() == 0 ) + { + aState = TC_CLOSETAG; + } + else + { + aState = TC_CLOSED; + bCheckName = TRUE; + } + } + break; + case '>': aState = TC_FINISHED; + bCheckName = TRUE; + break; + default: aState = TC_ERROR; + } + break; + +// HAS_TAG_NAME '=' -> HAS_PROP_NAME_EQ +// HAS_TAG_NAME ' ' -> HAS_PROP_NAME_SP +// HAS_TAG_NAME '/' -> CLOSED +// HAS_TAG_NAME '>' -> FINISHED + case TC_HAS_TAG_NAME: + switch ( cDelim ) + { + case '=': aState = TC_HAS_PROP_NAME_EQ; + bCheckName = TRUE; + break; + case ' ': aState = TC_HAS_PROP_NAME_SP; + bCheckName = TRUE; + break; + case '/': aState = TC_CLOSED; + bCheckEmpty = TRUE; + break; + case '>': aState = TC_FINISHED; + bCheckEmpty = TRUE; + break; + default: aState = TC_ERROR; + } + break; + +// HAS_PROP_NAME_SP '=' -> HAS_PROP_NAME_EQ + case TC_HAS_PROP_NAME_SP: + switch ( cDelim ) + { + case '=': aState = TC_HAS_PROP_NAME_EQ; + bCheckEmpty = TRUE; + break; + default: aState = TC_ERROR; + } + break; + +// HAS_PROP_NAME_EQ ' ' -> HAS_PROP_NAME_EQ_SP +// HAS_PROP_NAME_EQ '"' -> INSIDE_STRING + case TC_HAS_PROP_NAME_EQ: + switch ( cDelim ) + { + case ' ': aState = TC_HAS_PROP_NAME_EQ_SP; + bCheckEmpty = TRUE; + break; + case '\"': aState = TC_INSIDE_STRING; + bCheckEmpty = TRUE; + aValue.Erase(); + break; + default: aState = TC_ERROR; + } + break; + +// HAS_PROP_NAME_EQ_SP '"' -> INSIDE_STRING + case TC_HAS_PROP_NAME_EQ_SP: + switch ( cDelim ) + { + case '\"': aState = TC_INSIDE_STRING; + bCheckEmpty = TRUE; + aValue.Erase(); + break; + default: aState = TC_ERROR; + } + break; + +// INSIDE_STRING * -> INSIDE_STRING +// INSIDE_STRING '"' -> PROP_FINISHED + case TC_INSIDE_STRING: + switch ( cDelim ) + { + case '\"': + { + aState = TC_PROP_FINISHED; + aValue += aPortion; + if ( aProperties.find( aName ) == aProperties.end() ) + { + if ( !IsPropertyValueValid( aName, aValue ) ) + { + rErrorList.AddError( 25, ByteString("Property '").Append(aName).Append("' has invalid value '").Append(ByteString( aValue, RTL_TEXTENCODING_UTF8 )).Append("' "), *this ); + bIsBroken = TRUE; + } + aProperties[ aName ] = aValue; + } + else + { + rErrorList.AddError( 25, ByteString("Property '").Append(aName).Append("' defined twice "), *this ); + bIsBroken = TRUE; + } + } + break; + default: + { + aState = TC_INSIDE_STRING; + aValue += aPortion; + aValue += cDelim; + } + } + break; + +// PROP_FINISHED ' ' -> HAS_TAG_NAME +// PROP_FINISHED '/' -> CLOSED +// PROP_FINISHED '>' -> FINISHED + case TC_PROP_FINISHED: + switch ( cDelim ) + { + case ' ': aState = TC_HAS_TAG_NAME; + bCheckEmpty = TRUE; + break; + case '/': aState = TC_CLOSED; + bCheckEmpty = TRUE; + break; + case '>': aState = TC_FINISHED; + bCheckEmpty = TRUE; + break; + default: aState = TC_ERROR; + } + break; + +// CLOSED ' ' -> CLOSED_SPACE +// CLOSED '>' -> FINISHED + case TC_CLOSED: + switch ( cDelim ) + { + case ' ': aState = TC_CLOSED_SPACE; + bCheckEmpty = TRUE; + bClosed = TRUE; + break; + case '>': aState = TC_FINISHED; + bCheckEmpty = TRUE; + break; + default: aState = TC_ERROR; + } + break; + +// CLOSED_SPACE '>' -> FINISHED + case TC_CLOSED_SPACE: + switch ( cDelim ) + { + case '>': aState = TC_FINISHED; + bCheckEmpty = TRUE; + break; + default: aState = TC_ERROR; + } + break; + +// CLOSETAG ' ' -> CLOSETAG_HAS_TAG_NAME +// CLOSETAG '>' -> FINISHED + case TC_CLOSETAG: + bCloseTag = TRUE; + switch ( cDelim ) + { + case ' ': aState = TC_CLOSETAG_HAS_TAG_NAME; + aTagName = aPortion; + bCheckName = TRUE; + break; + case '>': aState = TC_FINISHED; + aTagName = aPortion; + bCheckName = TRUE; + break; + default: aState = TC_ERROR; + } + break; + +// CLOSETAG_HAS_TAG_NAME '>' -> FINISHED + case TC_CLOSETAG_HAS_TAG_NAME: + switch ( cDelim ) + { + case '>': aState = TC_FINISHED; + bCheckEmpty = TRUE; + break; + default: aState = TC_ERROR; + } + break; + + + default: rErrorList.AddError( 99, "Internal error Parsing Tag ", *this ); + bIsBroken = TRUE; + + } + + if ( bCheckName ) + { + if ( aPortion.Len() == 0 ) + { + rErrorList.AddError( 25, "Tag/Property name missing ", *this ); + bIsBroken = TRUE; + } + else + { + aName = ByteString( aPortion, RTL_TEXTENCODING_UTF8 ); + // "a-zA-Z_-.0-9" + xub_StrLen nCount; + BOOL bBroken = FALSE; + const sal_Char* aBuf = aName.GetBuffer(); + for ( nCount = 0 ; !bBroken && nCount < aName.Len() ; nCount++ ) + { + bBroken = ! ( ( aBuf[nCount] >= 'a' && aBuf[nCount] <= 'z' ) + ||( aBuf[nCount] >= 'A' && aBuf[nCount] <= 'Z' ) + ||( aBuf[nCount] >= '0' && aBuf[nCount] <= '9' ) + ||( aBuf[nCount] == '_' ) + ||( aBuf[nCount] == '-' ) + ||( aBuf[nCount] == '.' ) + ); + } + + if ( bBroken ) + { + rErrorList.AddError( 25, "Found illegal character in Tag/Property name ", *this ); + bIsBroken = TRUE; + } + } + + bCheckName = FALSE; + } + + if ( bCheckEmpty ) + { + if ( aPortion.Len() ) + { + rErrorList.AddError( 25, ByteString("Found displaced characters '").Append(ByteString( aPortion, RTL_TEXTENCODING_UTF8 )).Append("' in Tag "), *this ); + bIsBroken = TRUE; + } + bCheckEmpty = FALSE; + } + + + nLastPos = nCheckPos; + + // skip further blanks + if ( cDelim == ' ' && aState != TC_INSIDE_STRING ) + while ( nLastPos < aTokenString.Len() && aTokenString.GetChar( nLastPos ) == ' ') + nLastPos++; + + nCheckPos = aTokenString.SearchChar( aDelims.GetBuffer(), nLastPos ); + } + if ( aState != TC_FINISHED ) + { + rErrorList.AddError( 25, "Parsing error in Tag ", *this ); + bIsBroken = TRUE; + } +} + +BOOL TokenInfo::IsPropertyRelevant( const ByteString &aName, const String &aValue ) const +{ + if ( aTagName.EqualsAscii( "alt" ) && aName.Equals( "xml-lang" ) ) + return FALSE; + if ( aTagName.EqualsAscii( "ahelp" ) && aName.Equals( "visibility" ) && aValue.EqualsAscii("visible") ) + return FALSE; + if ( aTagName.EqualsAscii( "image" ) && (aName.Equals( "width" ) || aName.Equals( "height" )) ) + return FALSE; + + return TRUE; +} + +BOOL TokenInfo::IsPropertyValueValid( const ByteString &aName, const String &aValue ) const +{ +/* removed due to i56740 + if ( aTagName.EqualsAscii( "switchinline" ) && aName.Equals( "select" ) ) + { + return aValue.EqualsAscii("sys") || + aValue.EqualsAscii("appl") || + aValue.EqualsAscii("distrib"); + } */ + if ( aTagName.EqualsAscii( "caseinline" ) && aName.Equals( "select" ) ) + { + return /*!aValue.EqualsAscii("OS2") && removed due to i56740 */ + !aValue.EqualsAscii(""); + } + + // we don't know any better so we assume it to be OK + return TRUE; +} + +BOOL TokenInfo::IsPropertyInvariant( const ByteString &aName, const String &aValue ) const +{ + if ( aTagName.EqualsAscii( "link" ) && aName.Equals( "name" ) ) + return FALSE; + if ( aTagName.EqualsAscii( "link" ) && aName.Equals( "href" ) ) + { // check for external reference + if ( aValue.Copy( 0, 5 ).EqualsIgnoreCaseAscii( "http:" ) + || aValue.Copy( 0, 6 ).EqualsIgnoreCaseAscii( "https:" ) + || aValue.Copy( 0, 4 ).EqualsIgnoreCaseAscii( "ftp:" ) ) + return FALSE; + else + return TRUE; + } + return TRUE; +} + +BOOL TokenInfo::IsPropertyFixable( const ByteString &aName ) const +{ + // name everything that is allowed to be fixed automatically here + if ( (aTagName.EqualsAscii( "ahelp" ) && aName.Equals( "hid" )) + || (aTagName.EqualsAscii( "link" ) && aName.Equals( "href" )) + || (aTagName.EqualsAscii( "alt" ) && aName.Equals( "id" )) + || (aTagName.EqualsAscii( "variable" ) && aName.Equals( "id" )) + || (aTagName.EqualsAscii( "image" ) && aName.Equals( "src" )) + || (aTagName.EqualsAscii( "image" ) && aName.Equals( "id" ) )) + return TRUE; + return FALSE; +} + +BOOL TokenInfo::MatchesTranslation( TokenInfo& rInfo, BOOL bGenErrors, ParserMessageList &rErrorList, BOOL bFixTags ) const +{ + // check if tags are equal + // check if all existing properties are in the translation as well and + // wether they have a matching content (the same in most cases) + + if ( nId != rInfo.nId ) + return FALSE; + + if ( !aTagName.Equals( rInfo.aTagName ) ) + return FALSE; + + // If one of the tags has formating errors already it does make no sense to check here, so return right away + if ( bGenErrors && ( bIsBroken || rInfo.bIsBroken ) ) + return TRUE; + + StringHashMap::const_iterator iProp; + for( iProp = aProperties.begin() ; iProp != aProperties.end(); ++iProp ) + { + if ( rInfo.aProperties.find( iProp->first ) != rInfo.aProperties.end() ) + { + if ( IsPropertyRelevant( iProp->first, iProp->second ) || IsPropertyRelevant( iProp->first, rInfo.aProperties.find( iProp->first )->second ) ) + { + if ( IsPropertyInvariant( iProp->first, iProp->second ) ) + { + if ( !rInfo.aProperties.find( iProp->first )->second.Equals( iProp->second ) ) + { + if ( bGenErrors ) + { + if ( bFixTags && IsPropertyFixable( iProp->first ) ) + { + rInfo.aProperties.find( iProp->first )->second = iProp->second; + rInfo.SetHasBeenFixed(); + rErrorList.AddWarning( 25, ByteString("Property '").Append(iProp->first).Append("': FIXED different value in Translation "), *this ); + } + else + rErrorList.AddError( 25, ByteString("Property '").Append(iProp->first).Append("': value different in Translation "), *this ); + } + else return FALSE; + } + } + } + } + else + { + if ( IsPropertyRelevant( iProp->first, iProp->second ) ) + { + if ( bGenErrors ) + rErrorList.AddError( 25, ByteString("Property '").Append(iProp->first).Append("' missing in Translation "), *this ); + else return FALSE; + } + } + } + for( iProp = rInfo.aProperties.begin() ; iProp != rInfo.aProperties.end(); ++iProp ) + { + if ( aProperties.find( iProp->first ) == aProperties.end() ) + { + if ( IsPropertyRelevant( iProp->first, iProp->second ) ) + { + if ( bGenErrors ) + rErrorList.AddError( 25, ByteString("Extra Property '").Append(iProp->first).Append("' in Translation "), rInfo ); + else return FALSE; + } + } + } + + // if we reach here eather + // the tags match completely or + // the tags match but not the properties and we generated errors for that + return TRUE; +} + +String TokenInfo::GetTagName() const +{ + return aTagName; +} + +String TokenInfo::MakeTag() const +{ + String aRet; + aRet.AppendAscii("\\<"); + if ( bCloseTag ) + aRet.AppendAscii("/"); + aRet.Append( GetTagName() ); + StringHashMap::const_iterator iProp; + + for( iProp = aProperties.begin() ; iProp != aProperties.end(); ++iProp ) + { + aRet.AppendAscii(" "); + aRet.Append( String( iProp->first, RTL_TEXTENCODING_UTF8 ) ); + aRet.AppendAscii("=\\\""); + aRet.Append( iProp->second ); + aRet.AppendAscii("\\\""); + } + if ( bClosed ) + aRet.AppendAscii("/"); + aRet.AppendAscii("\\>"); + return aRet; +} + + +void ParserMessageList::AddError( USHORT nErrorNr, ByteString aErrorText, const TokenInfo &rTag ) +{ + maList.push_back( new ParserError( nErrorNr, aErrorText, rTag ) ); +} + +void ParserMessageList::AddWarning( USHORT nErrorNr, ByteString aErrorText, const TokenInfo &rTag ) +{ + maList.push_back( new ParserWarning( nErrorNr, aErrorText, rTag ) ); +} + +BOOL ParserMessageList::HasErrors() +{ + for ( size_t i = 0, n = maList.size(); i < n; ++i ) + if ( maList[ i ]->IsError() ) + return TRUE; + return FALSE; +} + +void ParserMessageList::clear() +{ + for ( size_t i = 0, n = maList.size(); i < n; ++i ) + delete maList[ i ]; + maList.clear(); +} + +struct Tag +{ + String GetName() const { return String::CreateFromAscii( pName ); }; + const char* pName; + TokenId nTag; +}; + + +static const Tag aKnownTags[] = +{ +/* commenting oldstyle tags +// { "<#GROUP_FORMAT>", TAG_GROUP_FORMAT }, + { "<#BOLD>", TAG_BOLDON }, + { "<#/BOLD>", TAG_BOLDOFF }, + { "<#ITALIC>", TAG_ITALICON }, + { "<#/ITALIC>", TAG_ITALICOFF }, + { "<#UNDER>", TAG_UNDERLINEON }, + { "<#/UNDER>", TAG_UNDERLINEOFF }, + +// { "<#GROUP_NOTALLOWED>", TAG_GROUP_NOTALLOWED }, + { "<#HELPID>", TAG_HELPID }, + { "<#MODIFY>", TAG_MODIFY }, + { "<#REFNR>", TAG_REFNR }, + +// { "<#GROUP_STRUCTURE>", TAG_GROUP_STRUCTURE }, + { "<#NAME>", TAG_NAME }, + { "<#HREF>", TAG_HREF }, + { "<#AVIS>", TAG_AVIS }, + { "<#AHID>", TAG_AHID }, + { "<#AEND>", TAG_AEND }, + + { "<#TITEL>", TAG_TITEL }, + { "<#KEY>", TAG_KEY }, + { "<#INDEX>", TAG_INDEX }, + + { "<#REFSTART>", TAG_REFSTART }, + + { "<#GRAPHIC>", TAG_GRAPHIC }, + { "<#NEXTVERSION>", TAG_NEXTVERSION }, + + // { "<#GROUP_SYSSWITCH>", TAG_GROUP_SYSSWITCH }, + { "<#WIN>", TAG_WIN }, + { "<#UNIX>", TAG_UNIX }, + { "<#MAC>", TAG_MAC }, + { "<#OS2>", TAG_OS2 }, + +// { "<#GROUP_PROGSWITCH>", TAG_GROUP_PROGSWITCH }, + { "<#WRITER>", TAG_WRITER }, + { "<#CALC>", TAG_CALC }, + { "<#DRAW>", TAG_DRAW }, + { "<#IMPRESS>", TAG_IMPRESS }, + { "<#SCHEDULE>", TAG_SCHEDULE }, + { "<#IMAGE>", TAG_IMAGE }, + { "<#MATH>", TAG_MATH }, + { "<#CHART>", TAG_CHART }, + { "<#OFFICE>", TAG_OFFICE }, + */ +// { "<#TAG_GROUP_META>", TAG_GROUP_META }, + { "$[officefullname]", TAG_OFFICEFULLNAME }, + { "$[officename]", TAG_OFFICENAME }, + { "$[officepath]", TAG_OFFICEPATH }, + { "$[officeversion]", TAG_OFFICEVERSION }, + { "$[portalname]", TAG_PORTALNAME }, + { "$[portalfullname]", TAG_PORTALFULLNAME }, + { "$[portalpath]", TAG_PORTALPATH }, + { "$[portalversion]", TAG_PORTALVERSION }, + { "$[portalshortname]", TAG_PORTALSHORTNAME }, +/* commenting oldstyle tags +// { "<#TAG_GROUP_SINGLE>", TAG_GROUP_SINGLE }, + { "<#REFINSERT>", TAG_REFINSERT }, + +// { "<#GROUP_MULTI>", TAG_GROUP_MULTI }, + { "<#END>", TAG_END }, + { "<#ELSE>", TAG_ELSE }, + { "<#VERSIONEND>", TAG_VERSIONEND }, + { "<#ENDGRAPHIC>", TAG_ENDGRAPHIC },*/ + { "<Common Tag>", TAG_COMMONSTART }, + { "</Common Tag>", TAG_COMMONEND }, + + { "<no more tags>", TAG_NOMORETAGS }, + { "", TAG_UNKNOWN_TAG }, +}; + + +SimpleParser::SimpleParser() +: nPos( 0 ) +, aNextTag( TAG_NOMORETAGS, TOK_INVALIDPOS ) +{ +} + +void SimpleParser::Parse( String PaSource ) +{ + aSource = PaSource; + nPos = 0; + aLastToken.Erase(); + aNextTag = TokenInfo( TAG_NOMORETAGS, TOK_INVALIDPOS ); + aTokenList.clear(); +}; + +TokenInfo SimpleParser::GetNextToken( ParserMessageList &rErrorList ) +{ + TokenInfo aResult; + USHORT nTokenStartPos = 0; + if ( aNextTag.nId != TAG_NOMORETAGS ) + { + aResult = aNextTag; + aNextTag = TokenInfo( TAG_NOMORETAGS, TOK_INVALIDPOS ); + } + else + { + aLastToken = GetNextTokenString( rErrorList, nTokenStartPos ); + if ( aLastToken.Len() == 0 ) + return TokenInfo( TAG_NOMORETAGS, TOK_INVALIDPOS ); + + // do we have a \< ... \> style tag? + if ( aLastToken.Copy(0,2).EqualsAscii( "\\<" ) ) + { + // check for paired \" \" + bool bEven = true; + USHORT nQuotePos = 0; + USHORT nQuotedQuotesPos = aLastToken.SearchAscii( "\\\"" ); + USHORT nQuotedBackPos = aLastToken.SearchAscii( "\\\\" ); // this is only to kick out quoted backslashes + while ( nQuotedQuotesPos != STRING_NOTFOUND ) + { + if ( nQuotedBackPos <= nQuotedQuotesPos ) + nQuotePos = nQuotedBackPos+2; + else + { + nQuotePos = nQuotedQuotesPos+2; + bEven = !bEven; + } + nQuotedQuotesPos = aLastToken.SearchAscii( "\\\"", nQuotePos ); + nQuotedBackPos = aLastToken.SearchAscii( "\\\\", nQuotePos ); // this is only to kick out quoted backslashes + } + if ( !bEven ) + { + rErrorList.AddError( 24, "Missing quotes ( \\\" ) in Tag", TokenInfo( TAG_UNKNOWN_TAG, nTokenStartPos, aLastToken ) ); + } + + // check if we have an end-tag or a start-tag + USHORT nNonBlankStartPos,nNonBlankEndPos; + nNonBlankStartPos = 2; + while ( aLastToken.GetChar(nNonBlankStartPos) == ' ' ) + nNonBlankStartPos++; + if ( aLastToken.GetChar(nNonBlankStartPos) == '/' ) + aResult = TokenInfo( TAG_COMMONEND, nTokenStartPos, aLastToken, rErrorList ); + else + { + aResult = TokenInfo( TAG_COMMONSTART, nTokenStartPos, aLastToken, rErrorList ); + nNonBlankEndPos = aLastToken.Len() -3; + while ( aLastToken.GetChar(nNonBlankEndPos) == ' ' ) + nNonBlankEndPos--; + if ( aLastToken.GetChar( nNonBlankEndPos ) == '/' ) + aNextTag = TokenInfo( TAG_COMMONEND, nTokenStartPos, String::CreateFromAscii("\\</").Append(aResult.GetTagName()).AppendAscii("\\>"), rErrorList ); + } + } + else + { + USHORT i = 0; + while ( aKnownTags[i].nTag != TAG_UNKNOWN_TAG && + aLastToken != aKnownTags[i].GetName() ) + i++; + aResult = TokenInfo( aKnownTags[i].nTag, nTokenStartPos ); + } + } + + if ( aResult.nId == TAG_UNKNOWN_TAG ) + aResult = TokenInfo( TAG_UNKNOWN_TAG, nTokenStartPos, aLastToken ); + aTokenList.insert( aResult ); + return aResult; +} + +String SimpleParser::GetNextTokenString( ParserMessageList &rErrorList, USHORT &rTagStartPos ) +{ + USHORT nStyle2StartPos = aSource.SearchAscii( "$[", nPos ); + USHORT nStyle3StartPos = aSource.SearchAscii( "\\<", nPos ); + USHORT nStyle4StartPos = aSource.SearchAscii( "\\\\", nPos ); // this is only to kick out quoted backslashes + + rTagStartPos = 0; + + if ( STRING_NOTFOUND == nStyle2StartPos && STRING_NOTFOUND == nStyle3StartPos ) + return String(); // no more tokens + + if ( nStyle4StartPos < nStyle2StartPos && nStyle4StartPos <= nStyle3StartPos ) // <= to make sure \\ is always handled first + { // Skip quoted Backslash + nPos = nStyle4StartPos +2; + return GetNextTokenString( rErrorList, rTagStartPos ); + } + + if ( nStyle2StartPos < nStyle3StartPos ) + { // test for $[ ... ] style tokens + USHORT nEndPos = aSource.SearchAscii( "]", nStyle2StartPos); + if ( nEndPos == STRING_NOTFOUND ) + { // Token is incomplete. Skip start and search for better ones + nPos = nStyle2StartPos +2; + return GetNextTokenString( rErrorList, rTagStartPos ); + } + nPos = nEndPos; + rTagStartPos = nStyle2StartPos; + return aSource.Copy( nStyle2StartPos, nEndPos-nStyle2StartPos +1 ); + } + else + { // test for \< ... \> style tokens + USHORT nEndPos = aSource.SearchAscii( "\\>", nStyle3StartPos); + USHORT nQuotedBackPos = aSource.SearchAscii( "\\\\", nStyle3StartPos ); // this is only to kick out quoted backslashes + while ( nQuotedBackPos <= nEndPos && nQuotedBackPos != STRING_NOTFOUND ) + { + nEndPos = aSource.SearchAscii( "\\>", nQuotedBackPos +2); + nQuotedBackPos = aSource.SearchAscii( "\\\\", nQuotedBackPos +2 ); // this is only to kick out quoted backslashes + } + if ( nEndPos == STRING_NOTFOUND ) + { // Token is incomplete. Skip start and search for better ones + nPos = nStyle3StartPos +2; + ByteString sTmp( "Tag Start '\\<' without Tag End '\\>': " ); + rErrorList.AddError( 24, "Tag Start '\\<' without Tag End '\\>'", TokenInfo( TAG_UNKNOWN_TAG, nStyle3StartPos, aSource.Copy( nStyle3StartPos-10, 20 ) ) ); + return GetNextTokenString( rErrorList, rTagStartPos ); + } + // check for paired quoted " --> \"sometext\" + + nPos = nEndPos; + rTagStartPos = nStyle3StartPos; + return aSource.Copy( nStyle3StartPos, nEndPos-nStyle3StartPos +2 ); + } +} + +String SimpleParser::GetLexem( TokenInfo const &aToken ) +{ + if ( aToken.aTokenString.Len() ) + return aToken.aTokenString; + else + { + USHORT i = 0; + while ( aKnownTags[i].nTag != TAG_UNKNOWN_TAG && + aKnownTags[i].nTag != aToken.nId ) + i++; + + return aKnownTags[i].GetName(); + } +} + +TokenParser::TokenParser() +: pErrorList( NULL ) +{} + +void TokenParser::Parse( const String &aCode, ParserMessageList* pList ) +{ + pErrorList = pList; + + //Scanner initialisieren + aParser.Parse( aCode ); + + //erstes Symbol holen + aTag = aParser.GetNextToken( *pErrorList ); + + nPfCaseOptions = 0; + nAppCaseOptions = 0; + bPfCaseActive = FALSE; + bAppCaseActive = FALSE; + + nActiveRefTypes = 0; + + //Ausfuehren der Start-Produktion + Paragraph(); + + //Es wurde nicht die ganze Kette abgearbeitet, bisher ist aber + //kein Fehler aufgetreten + //=> es wurde ein einleitendes Tag vergessen + if ( aTag.nId != TAG_NOMORETAGS ) + { + switch ( aTag.nId ) + { + case TAG_END: + { + ParseError( 3, "Extra Tag <#END>. Switch or <#HREF> expected.", aTag ); + } + break; + case TAG_BOLDOFF: + { + ParseError( 4, "<#BOLD> expected before <#/BOLD>.", aTag ); + } + break; + case TAG_ITALICOFF: + { + ParseError( 5, "<#ITALIC> expected before <#/ITALIC>.", aTag ); + } + break; + case TAG_UNDERLINEOFF: + { + ParseError( 17, "<#UNDER> expected before <#/UNDER>.", aTag ); + } + break; + case TAG_AEND: + { + ParseError( 5, "Extra Tag <#AEND>. <#AVIS> or <#AHID> expected.", aTag ); + } + break; + case TAG_ELSE: + { + ParseError( 16, "Application-tag or platform-tag expected before <#ELSE>.", aTag ); + } + break; + case TAG_UNKNOWN_TAG: + { + ParseError( 6, "unknown Tag", aTag ); + } + break; + default: + { + ParseError( 6, "unexpected Tag", aTag ); + } + } + } + pErrorList = NULL; +} + +void TokenParser::Paragraph() +{ + switch ( aTag.nId ) + { + case TAG_GRAPHIC: + case TAG_NEXTVERSION: + { + TagRef(); + Paragraph(); + } + break; + case TAG_AVIS: + case TAG_AHID: + { + TagRef(); + Paragraph(); + } + break; + case TAG_HELPID: + { + SimpleTag(); + Paragraph(); + } + break; + case TAG_OFFICEFULLNAME: + case TAG_OFFICENAME: + case TAG_OFFICEPATH: + case TAG_OFFICEVERSION: + case TAG_PORTALNAME: + case TAG_PORTALFULLNAME: + case TAG_PORTALPATH: + case TAG_PORTALVERSION: + case TAG_PORTALSHORTNAME: + { + SimpleTag(); + Paragraph(); + } + break; + case TAG_REFINSERT: + { + SimpleTag(); + Paragraph(); + } + break; + case TAG_BOLDON: + case TAG_ITALICON: + case TAG_UNDERLINEON: + case TAG_COMMONSTART: + { + TagPair(); + Paragraph(); + } + break; + case TAG_HREF: + case TAG_NAME: + case TAG_KEY: + case TAG_INDEX: + case TAG_TITEL: + case TAG_REFSTART: + { + TagRef(); + Paragraph(); + } + break; + case TAG_OS2: + case TAG_WIN: + case TAG_UNIX: + case TAG_MAC: //... + { + if ( ! bPfCaseActive ) + { + //PfCases duerfen nicht verschachtelt sein: + bPfCaseActive = TRUE; + PfCase(); + + //So jetzt kann wieder ein PfCase kommen: + bPfCaseActive = FALSE; + Paragraph(); + } + } + break; + case TAG_WRITER: + case TAG_CALC: + case TAG_DRAW: + case TAG_IMPRESS: + case TAG_SCHEDULE: + case TAG_IMAGE: + case TAG_MATH: + case TAG_CHART: + case TAG_OFFICE: + { + if ( !bAppCaseActive ) + { + //AppCases duerfen nicht verschachtelt sein: + bAppCaseActive = TRUE; + AppCase(); + + //jetzt koennen wieder AppCases kommen: + bAppCaseActive = FALSE; + Paragraph(); + } + } + break; + + //Case TAG_BOLDOFF, TAG_ITALICOFF, TAG_BUNDERLINE, TAG_END + //nichts tun wg. epsilon-Prod. + } +} + +void TokenParser::PfCase() +{ + + //Produktion: + //PfCase -> PfCaseBegin Paragraph (PfCase | PfCaseEnd) + + PfCaseBegin(); + + //Jetzt ist eine PfCase-Produktion aktiv: + Paragraph(); + switch ( aTag.nId ) + { + case TAG_ELSE: + case TAG_END: + { + CaseEnd(); + } + break; + case TAG_OS2: + case TAG_WIN: + case TAG_UNIX: + case TAG_MAC: //First (PfBegin) + { + PfCase(); + } + break; + default: + ParseError( 8, "<#ELSE> or <#END> or platform-tag expected.", aTag ); + } + //Die gemerkten Tags wieder loeschen fuer naechstes PfCase: + nPfCaseOptions = 0; +} + +void TokenParser::PfCaseBegin() +{ + switch ( aTag.nId ) + { + case TAG_OS2: + case TAG_WIN: + case TAG_UNIX: + case TAG_MAC: + { + //Token darf noch nicht vorgekommen sein im + //aktuellen Plattform-Case: + if ( !HAS_FLAG( nPfCaseOptions, TAG_NOGROUP( aTag.nId ) ) ) + { + SET_FLAG( nPfCaseOptions, TAG_NOGROUP( aTag.nId ) ); + match( aTag, aTag ); + } + else { + ParseError( 9, "Tag defined twice in the same platform-case", aTag ); + } + } + } +} + +void TokenParser::AppCase() +{ + + //Produktion: + //AppCase -> AppCaseBegin Paragraph (AppCase | AppCaseEnd) + + + AppCaseBegin(); + + Paragraph(); + + switch ( aTag.nId ) + { + case TAG_ELSE: + case TAG_END: + { + CaseEnd(); + } + break; + case TAG_WRITER: + case TAG_DRAW: + case TAG_CALC: + case TAG_IMAGE: + case TAG_MATH: + case TAG_CHART: + case TAG_OFFICE: + case TAG_IMPRESS: + case TAG_SCHEDULE: //First (AppBegin) + { + AppCase(); + } + break; + default: + ParseError( 1, "<#ELSE> or <#END> or application-case-tag expected.", aTag ); + } + + //Die gemerkten Tags wieder loeschen fuer naechstes AppCase: + nAppCaseOptions = 0; +} + +void TokenParser::AppCaseBegin() +{ + switch ( aTag.nId ) + { + case TAG_WRITER: + case TAG_DRAW: + case TAG_CALC: + case TAG_IMAGE: + case TAG_MATH: + case TAG_CHART: + case TAG_OFFICE: + case TAG_IMPRESS: + case TAG_SCHEDULE: + { + //Token darf noch nicht vorgekommen sein im + //aktuellen Plattform-Case: + if ( !HAS_FLAG( nAppCaseOptions, TAG_NOGROUP( aTag.nId ) ) ) + { + SET_FLAG( nAppCaseOptions, TAG_NOGROUP( aTag.nId ) ); + match( aTag, aTag ); + } + else { + ParseError( 13, "Tag defined twice in the same application-case.", aTag ); + } + } + } +} + +void TokenParser::CaseEnd() +{ + //Produktion: + //CaseEnd -> <#ELSE> Paragraph <#END> | <#END> + + switch ( aTag.nId ) + { + case TAG_ELSE: + { + match( aTag, TAG_ELSE ); + Paragraph(); + match( aTag, TAG_END ); + } + break; + case TAG_END: + { + match( aTag, TAG_END ); + } + break; + default: + ParseError( 2, "<#ELSE> or <#END> expected.", aTag ); + } +} + +void TokenParser::SimpleTag() +{ + + switch ( aTag.nId ) + { + case TAG_HELPID: + { + match( aTag, TAG_HELPID ); + } + break; + case TAG_OFFICEFULLNAME: + case TAG_OFFICENAME: + case TAG_OFFICEPATH: + case TAG_OFFICEVERSION: + case TAG_PORTALNAME: + case TAG_PORTALFULLNAME: + case TAG_PORTALPATH: + case TAG_PORTALVERSION: + case TAG_PORTALSHORTNAME: + + case TAG_REFINSERT: + { + match( aTag, aTag ); + } + break; + default: + ParseError( 15, "[<#SimpleTag>] expected.", aTag ); + } +} + +void TokenParser::TagPair() +{ + switch ( aTag.nId ) + { + case TAG_BOLDON: + { + match( aTag, TAG_BOLDON ); + Paragraph(); + match( aTag, TAG_BOLDOFF ); + } + break; + case TAG_ITALICON: + { + match( aTag, TAG_ITALICON ); + Paragraph(); + match( aTag, TAG_ITALICOFF ); + } + break; + case TAG_UNDERLINEON: + { + match( aTag, TAG_UNDERLINEON ); + Paragraph(); + match( aTag, TAG_UNDERLINEOFF ); + } + break; + case TAG_COMMONSTART: + { + //remember tag so we can give the original tag in case of an error + TokenInfo aEndTag( aTag ); + aEndTag.nId = TAG_COMMONEND; + match( aTag, TAG_COMMONSTART ); + Paragraph(); + match( aTag, aEndTag ); + } + break; + default: + ParseError( 10, "<#BOLD>, <#ITALIC>, <#UNDER> expected.", aTag ); + } +} + + +void TokenParser::TagRef() +{ + switch ( aTag.nId ) + { + case TAG_GRAPHIC: + case TAG_NEXTVERSION: + { + if ( !HAS_FLAG( nActiveRefTypes, TAG_NOGROUP( aTag.nId ) ) ) + { + TokenId aThisToken = aTag.nId; + SET_FLAG( nActiveRefTypes, TAG_NOGROUP( aThisToken ) ); + match( aTag, aTag ); + Paragraph(); + if ( aThisToken == TAG_GRAPHIC ) + match( aTag, TAG_ENDGRAPHIC ); + else + match( aTag, TAG_VERSIONEND ); + // don't reset since alowed only once per paragraph + // RESET_FLAG( nActiveRefTypes, TAG_NOGROUP( aThisToken ) ); + } + else + { + ParseError( 11, "Tags <#GRAPHIC>,<#NEXTVERSION> allowed only once per paragraph at", aTag ); + } + } + break; + case TAG_AVIS: + case TAG_AHID: + { + if ( !HAS_FLAG( nActiveRefTypes, TAG_NOGROUP( aTag.nId ) ) ) + { + TokenId aThisToken = aTag.nId; + SET_FLAG( nActiveRefTypes, TAG_NOGROUP( aThisToken ) ); + match( aTag, aTag ); + Paragraph(); + match( aTag, TAG_AEND ); + RESET_FLAG( nActiveRefTypes, TAG_NOGROUP( aThisToken ) ); + } + else + { + ParseError( 11, "Nested <#AHID>,<#AVIS> not allowed.", aTag ); + } + } + break; + case TAG_HREF: + case TAG_NAME: + { + + } + // NOBREAK + case TAG_KEY: + case TAG_INDEX: + case TAG_TITEL: + case TAG_REFSTART: + { + if ( !HAS_FLAG( nActiveRefTypes, TAG_NOGROUP( aTag.nId ) ) ) + { + TokenId aThisToken = aTag.nId; + match( aTag, aTag ); + if ( aThisToken != TAG_NAME ) + { // TAG_NAME has no TAG_END + SET_FLAG( nActiveRefTypes, TAG_NOGROUP( aThisToken ) ); + Paragraph(); + match( aTag, TAG_END ); + RESET_FLAG( nActiveRefTypes, TAG_NOGROUP( aThisToken ) ); + } + } + else + { + ParseError( 11, "Nested <#HREF>,<#NAME> or <#KEY> not allowed.", aTag ); + } + } + break; + default: + ParseError( 12, "<#HREF>,<#NAME> or <#KEY> expected.", aTag ); + } +} + +BOOL TokenParser::match( const TokenInfo &aCurrentToken, const TokenId &aExpectedToken ) +{ + return match( aCurrentToken, TokenInfo( aExpectedToken, TOK_INVALIDPOS ) ); +} + +BOOL TokenParser::match( const TokenInfo &aCurrentToken, const TokenInfo &rExpectedToken ) +{ + TokenInfo aExpectedToken( rExpectedToken ); + if ( aCurrentToken.nId == aExpectedToken.nId ) + { + if ( ( aCurrentToken.nId == TAG_COMMONEND + && aCurrentToken.GetTagName().Equals( aExpectedToken.GetTagName() ) ) + || aCurrentToken.nId != TAG_COMMONEND ) + { + aTag = aParser.GetNextToken( *pErrorList ); + return TRUE; + } + } + + if ( aExpectedToken.nId == TAG_COMMONEND ) + { + aExpectedToken.aTokenString.Insert( String::CreateFromAscii( "Close tag for " ), 0 ); + } + + ByteString sTmp( "Expected Symbol" ); + if ( aCurrentToken.nId == TAG_NOMORETAGS ) + { + ParseError( 7, sTmp, aExpectedToken ); + } + else + { + sTmp += ": "; + sTmp += ByteString( aParser.GetLexem( aExpectedToken ), RTL_TEXTENCODING_UTF8 ); + sTmp += " near "; + ParseError( 7, sTmp, aCurrentToken ); + } + return FALSE; +} + +void TokenParser::ParseError( USHORT nErrNr, ByteString aErrMsg, const TokenInfo &rTag ) +{ + pErrorList->AddError( nErrNr, aErrMsg, rTag); + + // Das Fehlerhafte Tag ueberspringen + aTag = aParser.GetNextToken( *pErrorList ); +} + + +ParserMessage::ParserMessage( USHORT PnErrorNr, ByteString PaErrorText, const TokenInfo &rTag ) + : nErrorNr( PnErrorNr ) + , aErrorText( PaErrorText ) + , nTagBegin( 0 ) + , nTagLength( 0 ) +{ + String aLexem( SimpleParser::GetLexem( rTag ) ); + aErrorText.Append(": "); + aErrorText += ByteString( aLexem, RTL_TEXTENCODING_UTF8 ); + if ( rTag.nId == TAG_NOMORETAGS ) + aErrorText.Append(" at end of line "); + else if ( rTag.nPos != TOK_INVALIDPOS ) + { + aErrorText.Append(" at Position "); + aErrorText.Append( ByteString::CreateFromInt32( rTag.nPos ) ); + } + nTagBegin = rTag.nPos; + nTagLength = aLexem.Len(); +} + +ParserError::ParserError( USHORT ErrorNr, ByteString ErrorText, const TokenInfo &rTag ) +: ParserMessage( ErrorNr, ErrorText, rTag ) +{} + +ParserWarning::ParserWarning( USHORT ErrorNr, ByteString ErrorText, const TokenInfo &rTag ) +: ParserMessage( ErrorNr, ErrorText, rTag ) +{} + +BOOL LingTest::IsTagMandatory( TokenInfo const &aToken, TokenId &aMetaTokens ) +{ + TokenId aTokenId = aToken.nId; + TokenId aTokenGroup = TAG_GROUP( aTokenId ); + if ( TAG_GROUP_PROGSWITCH == aTokenGroup + || TAG_REFINSERT == aTokenId + || TAG_REFSTART == aTokenId + || TAG_NAME == aTokenId + || TAG_HREF == aTokenId + || TAG_AVIS == aTokenId + || TAG_AHID == aTokenId + || TAG_GRAPHIC == aTokenId + || TAG_NEXTVERSION == aTokenId + || ( TAG_GROUP_META == aTokenGroup && (aMetaTokens & aTokenId) == aTokenId ) ) + { + if ( TAG_GROUP_META == aTokenGroup ) + aMetaTokens |= aTokenId; + return TRUE; + } + else if ( TAG_COMMONSTART == aTokenId + || TAG_COMMONEND == aTokenId ) + { + String aTagName = aToken.GetTagName(); + return !(aTagName.EqualsIgnoreCaseAscii( "comment" ) + || aTagName.EqualsIgnoreCaseAscii( "bookmark_value" ) + || aTagName.EqualsIgnoreCaseAscii( "emph" ) + || aTagName.EqualsIgnoreCaseAscii( "item" ) + || aTagName.EqualsIgnoreCaseAscii( "br" ) ); + } + return FALSE; +} + +void LingTest::CheckTags( TokenList &aReference, TokenList &aTestee, BOOL bFixTags ) +{ + size_t i=0,j=0; + // Clean old Warnings + aCompareWarningList.clear(); + + /* in xml tags, do not require the following tags + comment + bookmark_value + emph + item + br + */ + + // filter uninteresting Tags + TokenId aMetaTokens = 0; + for ( i=0 ; i < aReference.size() ; i++ ) + { + if ( !IsTagMandatory( aReference[ i ], aMetaTokens ) ) + aReference[ i ].SetDone(); + } + + aMetaTokens = 0; + for ( i=0 ; i < aTestee.size() ; i++ ) + { + if ( !IsTagMandatory( aTestee[ i ], aMetaTokens ) ) + aTestee[ i ].SetDone(); + } + + // remove all matching tags + for ( i=0 ; i < aReference.size() ; i++ ) + { + if ( aReference[ i ].IsDone() ) + continue; + + BOOL bTagFound = FALSE; + for ( j=0 ; j < aTestee.size() && !bTagFound ; j++ ) + { + if ( aTestee[ j ].IsDone() ) + continue; + + if ( aReference[ i ].MatchesTranslation( aTestee[ j ], FALSE, aCompareWarningList ) ) + { + aReference[ i ].SetDone(); + aTestee[ j ].SetDone(); + bTagFound = TRUE; + } + } + } + + BOOL bCanFix = TRUE; + + if ( bFixTags ) + { + // we fix only if its a really simple case + USHORT nTagCount = 0; + for ( i=0 ; i < aReference.size() ; i++ ) + if ( !aReference[ i ].IsDone() ) + nTagCount++; + if ( nTagCount > 1 ) + bCanFix = FALSE; + + nTagCount = 0; + for ( i=0 ; i < aTestee.size() ; i++ ) + if ( !aTestee[ i ].IsDone() ) + nTagCount++; + if ( nTagCount > 1 ) + bCanFix = FALSE; + } + + // generate errors for tags that have differing attributes + for ( i=0 ; i < aReference.size() ; i++ ) + { + if ( aReference[ i ].IsDone() ) + continue; + + BOOL bTagFound = FALSE; + for ( j=0 ; j < aTestee.size() && !bTagFound ; j++ ) + { + if ( aTestee[ j ].IsDone() ) + continue; + + if ( aReference[ i ].MatchesTranslation( aTestee[ j ], TRUE, aCompareWarningList, bCanFix && bFixTags ) ) + { + aReference[ i ].SetDone(); + aTestee[ j ].SetDone(); + bTagFound = TRUE; + } + } + } + + // list remaining tags as errors + for ( i=0 ; i < aReference.size() ; i++ ) + { + if ( aReference[ i ].IsDone() ) + continue; + + aCompareWarningList.AddError( 20, "Missing Tag in Translation", aReference[ i ] ); + } + for ( i=0 ; i < aTestee.size() ; i++ ) + { + if ( aTestee[ i ].IsDone() ) + continue; + + aCompareWarningList.AddError( 21, "Extra Tag in Translation", aTestee[ i ] ); + } + + for ( i=0 ; i < aReference.size() ; i++ ) + aReference[ i ].SetDone( FALSE ); + + for ( i=0 ; i < aTestee.size() ; i++ ) + aTestee[ i ].SetDone( FALSE ); +} + +void LingTest::CheckReference( GSILine *aReference ) +{ + aReferenceParser.Parse( aReference->GetUText(), aReference->GetMessageList() ); +} + +void LingTest::CheckTestee( GSILine *aTestee, BOOL bHasSourceLine, BOOL bFixTags ) +{ + aFixedTestee = aTestee->GetUText(); + aTesteeParser.Parse( aFixedTestee, aTestee->GetMessageList() ); + + if ( bHasSourceLine ) + CheckTags( aReferenceParser.GetTokenList(), aTesteeParser.GetTokenList(), bFixTags ); + + if ( bFixTags ) + { + TokenList& aTesteeTokens = aTesteeParser.GetTokenList(); + BOOL bFixesDone = FALSE; + // count backwards to allow replacing from right to left + int i; + for ( i = aTesteeTokens.size() ; i > 0 ; ) + { + if ( aTesteeTokens[ --i ].HasBeenFixed() ) + { + bFixesDone = TRUE; + aFixedTestee.Replace( aTesteeTokens[ i ].nPos, aTesteeTokens[ i ].aTokenString.Len(), aTesteeTokens[ i ].MakeTag() ); + } + } + if ( bFixesDone ) + { + aTestee->SetUText( aFixedTestee ); + aTestee->SetFixed(); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/treeconfig.cxx b/l10ntools/source/treeconfig.cxx new file mode 100644 index 000000000000..9f02ff80ddc8 --- /dev/null +++ b/l10ntools/source/treeconfig.cxx @@ -0,0 +1,131 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +#include <vector> +#include <string> +#include <iostream> +#include "treeconfig.hxx" +#include "export.hxx" +#ifdef WNT +#include <direct.h> +#include <io.h> +#else +#include <dirent.h> +#endif +#include <sys/stat.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> + +using namespace std; + +namespace transex3 +{ + +bool Treeconfig::parseConfig(){ + + string source_config_file = string( static_cast<ByteString>( Export::GetEnv("SOURCE_ROOT_DIR") ).GetBuffer() ); + if( source_config_file.empty() ) + { + cerr << "Error: no suitable environment set?!?"; + exit( -1 ); + } + source_config_file += string("/source_config"); + if( isConfigFilePresent() ) + { + inireader.read( map , source_config_file ); + return true; + } + else return false; +} + +// ALWAYS add all repositories from source_config file to the container active_repos +// if a config_file is present ALWAYS return false +// if you are in the root of a repository also add it to the container active_repos +// if you are far inside a repository /my/path/ooo/sw/source then don't add it to the container but return true +// if you are in some misc place like /tmp then return true +// => the application can decide what to do in case the function returns true thus how to handle pwd() path +bool Treeconfig::getActiveRepositories( vector<string>& active_repos ){ + + bool isPresent = isConfigFilePresent(); + bool hasPath = false; + string pwd; + string guessedRepo; + Export::getCurrentDir( pwd ); + string source_root = Export::GetEnv( "SOURCE_ROOT_DIR" ); + string solarsrc = Export::GetEnv( "SOLARSRC" ); + string partial; + + // if we are inside of a repository root then active it otherwise let the app handle the return! + string::size_type pos = pwd.find_first_of( source_root ); + if( pos != string::npos && ( pos + source_root.length() +1 ) < pwd.length()){ // I am within SOURCE_ROOT_DIR + partial = pwd.substr( pos + source_root.length() +1 , pwd.length()); + string::size_type nextPart = partial.find_first_of( "/" ); + if( nextPart != string::npos ) + hasPath = true; + else + guessedRepo = partial; + } + else // I am NOT within SOURCE_ROOT_DIR + hasPath = true; + + if( isPresent ) + { + hasPath = false; // if config_file is present don't care about pwd + stringmap* repos = static_cast<stringmap*>( map[ string("repositories") ] ); + if( repos != 0 ) + { + for( stringmap::iterator iter = repos->begin() ; iter != repos->end() ; ++iter ) + { + if( static_cast<string>( iter->second ) == string( "active" ) ) + { + active_repos.push_back( iter->first ); + if( static_cast<string>( iter->first ) == guessedRepo ) + { + guessedRepo.clear(); // don't add double in case it is present in config_file + } + } + } + } + else + { + cerr << "Error: source_config files doesn't contain a 'repositories' section ?!?"; + exit( -1 ); + } + } + if( !guessedRepo.empty() ){ + active_repos.push_back( guessedRepo ); // add myrepo + } + return hasPath; // are we deep inside of a source tree or outside of SOURCE_ROOT_DIR? +} + +void Treeconfig::getCurrentDir( string& dir ) +{ + char buffer[64000]; + if( getcwd( buffer , sizeof( buffer ) ) == 0 ){ + cerr << "Error: getcwd failed!\n"; + exit( -1 ); + } + dir = string( buffer ); +} + +bool Treeconfig::isConfigFilePresent() +{ + string config_file = Export::GetEnv( "SOURCE_ROOT_DIR" ); + config_file += "/source_config"; + + struct stat status; + if( stat( config_file.c_str() , &status ) < 0 ) + { + return false; + } +#ifdef WNT + return ( status.st_mode & _S_IFREG ) && ( _access( config_file.c_str() , 4 ) >= 0 ) ; +#else + return ( status.st_mode & S_IFREG ) && ( access( config_file.c_str() , R_OK ) >= 0 ) ; +#endif +} + + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/utf8conv.cxx b/l10ntools/source/utf8conv.cxx new file mode 100644 index 000000000000..72dd18aa7398 --- /dev/null +++ b/l10ntools/source/utf8conv.cxx @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_l10ntools.hxx" +#include "utf8conv.hxx" + +// +// class UTF8Converter +// + +#define MAX_CONV_BUFFER_SIZE 0xFF00 + +#define TO_CVTFLAGS (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_MAPTOPRIVATE |\ + RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |\ + RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT) + +#define FROM_CVTFLAGS (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_DEFAULT |\ + RTL_UNICODETOTEXT_FLAGS_INVALID_DEFAULT |\ + RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE |\ + RTL_UNICODETOTEXT_FLAGS_PRIVATE_MAPTO0) + +/*****************************************************************************/ +void UTF8Converter::Convert( ByteString &rBuffer, + rtl_TextEncoding nSourceENC, rtl_TextEncoding nDestENC ) +/*****************************************************************************/ +{ + String sTemp( rBuffer, nSourceENC ); + rBuffer = ByteString( sTemp, nDestENC ); +} + +/*****************************************************************************/ +ByteString UTF8Converter::ConvertToUTF8( + const ByteString &rASCII, rtl_TextEncoding nEncoding ) +/*****************************************************************************/ +{ + ByteString sReturn( rASCII ); + Convert( sReturn, nEncoding, RTL_TEXTENCODING_UTF8 ); + return sReturn; +} + +/*****************************************************************************/ +ByteString UTF8Converter::ConvertFromUTF8( + const ByteString &rUTF8, rtl_TextEncoding nEncoding ) +/*****************************************************************************/ +{ + ByteString sReturn( rUTF8 ); + Convert( sReturn, RTL_TEXTENCODING_UTF8, nEncoding ); + return sReturn; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/wtranode.cxx b/l10ntools/source/wtranode.cxx new file mode 100644 index 000000000000..1a4e48fd6231 --- /dev/null +++ b/l10ntools/source/wtranode.cxx @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_l10ntools.hxx" + + +#include "wtranode.hxx" + + +// NOT FULLY DECLARED SERVICES + + +const ByteString sEmptyString(""); + + +WTT_Node::WTT_Node( UINT8 i_nValue, + WTT_Node * i_pDefaultBranch, + WTT_Node * i_pDefaultBranchForAlphas ) + : nValue(i_nValue), + eType(token_to_keep), + sReplaceString(sEmptyString), + // aBranches, + bIsOnDeleting(char(0)) +{ + int i = 0; + for ( ; i < C_BR_ALPHABASE; i++ ) + { + aBranches[i] = i_pDefaultBranch; + } // end for + for ( ; i < C_NR_OF_BRANCHES; i++ ) + { + aBranches[i] = i_pDefaultBranchForAlphas; + } +} + +void +WTT_Node::SetBranch( UINT8 i_cBranch, + WTT_Node * i_pNode ) +{ + if (i_cBranch < C_NR_OF_BRANCHES) + { + aBranches[i_cBranch] = i_pNode; + } +} + +void +WTT_Node::SetAsTokenToReplace(const ByteString & i_sReplaceString) +{ + sReplaceString = i_sReplaceString; + eType = token_to_replace; +} + +WTT_Node::~WTT_Node() +{ + // Delete the tree hanging below this node: + + bIsOnDeleting = TRUE; // Avoid double deleting of multiple used nodes. + + for (int i = 0; i < C_NR_OF_BRANCHES; i++) + { + if (aBranches[i] != 0 ? ! aBranches[i]->IsOnDeleting() : FALSE) + { + delete aBranches[i]; + } + } // end for +} + + + + + + + + + + + + + + + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/wtratree.cxx b/l10ntools/source/wtratree.cxx new file mode 100644 index 000000000000..26838e2fb29d --- /dev/null +++ b/l10ntools/source/wtratree.cxx @@ -0,0 +1,420 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_l10ntools.hxx" + + +#include "wtratree.hxx" + + + +/** @ATTENTION + For reasons of speed, class WordTransTree works with two simple + char arrays, sOutput and sInput, instead of secure containers or + streams. So be extremely careful, when changing this code!!! +**/ + + + +// NOT FULLY DECLARED SERVICES +#include <string.h> +#include <stdio.h> +#include <ctype.h> +#include "wtranode.hxx" + + +const BRANCH_T BR_END = 0; +const BRANCH_T BR_NONALPHA = 1; +const BRANCH_T BR_HOTKEY = 2; +const BRANCH_T BR_BACKSLASH = 3; +const BRANCH_T BR_ALPHABASE = 4; /// @ATTENTION All branches not valid for words must be smaller than this value! +const BRANCH_T BR_AE = 30; +const BRANCH_T BR_OE = 31; +const BRANCH_T BR_UE = 32; +const BRANCH_T BR_SZ = 33; +const BRANCH_T BR_MAX = 34; /// @ATTENTION Must be updated always! + +const BRANCH_T BR_START = 0; + + + + + +WordTransTree::WordTransTree(CharSet i_nWorkingCharSet) + : sInput(0), + nInputLength(0), + pInputEnd(0), + sOutput(0), + nOutputMaxLength(0), + dpParsingTreeTop(0), + pUnknownAlpha(0), + // cChar2Branch + c_AE(u_char('\xC4')), c_OE(u_char('\xD6')), c_UE(u_char('\xDC')), + c_ae(u_char('\xE4')), c_oe(u_char('\xF6')), c_ue(u_char('\xFC')), + pInputCurTokenStart(0), + pInputPosition(0), + pOutputPosition(0), + pCurParseNode(0), + eCurResult(OK), + cCurHotkey(0), + cCurHotkeySign(u_char('~')) +{ + // Initialize parsing tree: + pUnknownAlpha = new WTT_Node(BR_ALPHABASE,0,0); // This will be deleted as part of the parsing tree. + for ( UINT8 i = BR_ALPHABASE; i < C_NR_OF_BRANCHES; i++) + { + pUnknownAlpha->SetBranch(i,pUnknownAlpha); + } // end for + + dpParsingTreeTop = new WTT_Node(BR_START,0,pUnknownAlpha); + + WTT_Node * dpNonAlpha = new WTT_Node(BR_NONALPHA,0,0); + + dpNonAlpha->SetBranch(BR_NONALPHA,dpNonAlpha); + dpParsingTreeTop->SetBranch(BR_NONALPHA,dpNonAlpha); + + WTT_Node * dpBackslash = new WTT_Node(BR_BACKSLASH,dpNonAlpha,dpNonAlpha); + dpBackslash->SetBranch(BR_END,0); + + dpParsingTreeTop->SetBranch(BR_BACKSLASH,dpBackslash); + dpNonAlpha->SetBranch(BR_BACKSLASH,dpBackslash); + + + // Initialize character set: + SetCharSet(i_nWorkingCharSet); + + if (C_BR_ALPHABASE != BR_ALPHABASE || C_NR_OF_BRANCHES != BR_MAX) + { + fprintf(stderr, "Assertion failed: file %s line %d.", __FILE__, __LINE__); + exit(1); + } +} + +void +WordTransTree::SetCharSet(CharSet i_nWorkingCharSet) +{ + ByteString sConvert("\xC4\xD6\xDC\xE4\xF6\xFC\xDF"); + const u_char * pConvert = (const u_char * ) ( sConvert.Convert(RTL_TEXTENCODING_MS_1252, i_nWorkingCharSet).GetBuffer() ); + + INT16 i = 0; + for ( ; i < C_NR_OF_POSSIBLE_CHARS; ++i ) + { + cChar2Branch[i] = BR_NONALPHA; + } // end for + for ( i = 'a'; i <= 'z'; ++i ) + { + cChar2Branch[i] = BR_ALPHABASE + i - 'a'; + } // end for + for ( i = 'A'; i <= 'Z'; ++i ) + { + cChar2Branch[i] = BR_ALPHABASE + i - 'A'; + } // end for + cChar2Branch[pConvert[0]] = BR_AE; + cChar2Branch[pConvert[1]] = BR_OE; + cChar2Branch[pConvert[2]] = BR_UE; + cChar2Branch[pConvert[3]] = BR_AE; + cChar2Branch[pConvert[4]] = BR_OE; + cChar2Branch[pConvert[5]] = BR_UE; + cChar2Branch[pConvert[6]] = BR_SZ; + + cChar2Branch[u_char('~')] = BR_HOTKEY; + cChar2Branch[u_char('&')] = BR_HOTKEY; + + + c_AE = pConvert[0]; + c_OE = pConvert[1]; + c_UE = pConvert[2]; + c_ae = pConvert[3]; + c_oe = pConvert[4]; + c_ue = pConvert[5]; +} + +WordTransTree::~WordTransTree() +{ + delete dpParsingTreeTop; + if (sOutput != 0) + delete [] sOutput; +} + +void +WordTransTree::AddWordPair( const ByteString & i_sOldString, + const ByteString & i_sReplaceString ) +{ + if (i_sOldString.Len() == 0) + return; + + pCurParseNode = dpParsingTreeTop; + WTT_Node * pBranch = 0; + char cBranch = 0; + + for ( constr pOld = i_sOldString.GetBuffer(); + *pOld != 0; + pOld++ ) + { + cBranch = CalculateBranch(*pOld); + pBranch = pCurParseNode->GetNextNode(cBranch); + if (pBranch == 0 || pBranch == pUnknownAlpha) + { + pBranch = new WTT_Node(cBranch,0,pUnknownAlpha); + pCurParseNode->SetBranch(cBranch,pBranch); + } + pCurParseNode = pBranch; + } // end for + pCurParseNode->SetAsTokenToReplace(i_sReplaceString); +} + +void +WordTransTree::InitTransformation( const char * i_sInput, + UINT32 i_nInputLength, + UINT32 i_nOutputMaxLength ) +{ + sInput = (const u_char *)i_sInput; + nInputLength = i_nInputLength; + pInputEnd = &sInput[i_nInputLength]; + + pInputCurTokenStart = sInput; + pInputPosition = sInput; + + if (nOutputMaxLength < i_nOutputMaxLength) + { + if (sOutput != 0) + delete [] sOutput; + sOutput = new unsigned char[i_nOutputMaxLength]; + nOutputMaxLength = i_nOutputMaxLength; + } + pOutputPosition = sOutput; +} + +/** pInputCurTokenStart and CurParseNode are updated just when + starting this function. After its end they must not be changed + till this functon is called again. + Outside this function pInputPositon and pOutputPosition are both + on the first not transformed char in their respective array. +**/ +WordTransTree::E_Result +WordTransTree::TransformNextToken() +{ + pInputCurTokenStart = pInputPosition; + pCurParseNode = dpParsingTreeTop; + cCurHotkey = 0; + eCurResult = OK; + + WTT_Node * pBranch = 0; + UINT8 cBranch = 0; + + for ( pCurParseNode = dpParsingTreeTop; + pInputPosition != pInputEnd; + ++pInputPosition ) + { + cBranch = CalculateBranch(*pInputPosition); + pBranch = pCurParseNode->GetNextNode( cBranch ); + if (pBranch != 0) + { + pCurParseNode = pBranch; + } + else + { + if (cBranch == BR_HOTKEY) // current letter is '~' or '&'. + { + // Logic of the following. There are 9 possible cases - + // A = alphabetic letter, NA = non alphabetic, TB = token begin, + // Eot = end of text: + // 1. A~A set hotkey to following letter, continue + // 2. A~NA token end + // 3. A~Eot token end + // 4. NA~A token end + // 5. NA~NA continue + // 6. A~Eof continue + // 7. TB~A set hotkey to following letter, continue + // 8. TB~NA continue + // 9. TB~Eot continue + + // bNext and Prev are true, if there are alphabetic letters: + BOOL bNext = pInputPosition + 1 != pInputEnd + ? CalculateBranch(pInputPosition[1]) >= BR_ALPHABASE + : FALSE; + BOOL bPrev = pCurParseNode->Value() >= BR_ALPHABASE; + + if ( bNext && (bPrev || pCurParseNode == dpParsingTreeTop) ) + { // case 1. and 7. + Handle_Hotkey(); + continue; + } + else if (!bPrev && !bNext) + { // case 5.,6.,8.,9. + continue; + } + + // Case 2.,3.,4. : + // so this should be handled as an end of a token. + } + if (pCurParseNode->TokenType() == WTT_Node::token_to_keep) + { + Handle_TokenToKeep(); + return eCurResult; + } + else + { + Handle_TokenToTransform(); + return eCurResult; + } // endif (pCurParseNode->TokenType() == WTT_Node::token_to_keep) + } // endif (pBranch == 0) else + } // end for + + // If here, the text end is reached + if (pCurParseNode->TokenType() == WTT_Node::token_to_keep) + { + Handle_TokenToKeep(); + return eCurResult; + } + else + { + Handle_TokenToTransform(); + return eCurResult; + } +} + +ByteString +WordTransTree::CurReplacingString() const +{ + return pCurParseNode->ReplaceString(); +} + +void +WordTransTree::Handle_Hotkey() +{ + if (cCurHotkey == 0) // Avoid to replace the first found hotkey by + // a later one - though this shouldn't happen anyway. + { + cCurHotkey = (pInputPosition+1) != pInputEnd ? pInputPosition[1] : 0; + cCurHotkeySign = *pInputPosition; + } +} + +void +WordTransTree::Handle_TokenToKeep() +{ + UINT32 nTokenLength = pInputPosition-pInputCurTokenStart; + + memcpy(pOutputPosition,pInputCurTokenStart,nTokenLength); + + pOutputPosition += nTokenLength; + *pOutputPosition = '\0'; +} + +void +WordTransTree::Handle_TokenToTransform() +{ + BOOL bHaveHotkey = CalculateBranch(cCurHotkey) >= BR_ALPHABASE; + const ByteString & rReplace = pCurParseNode->ReplaceString(); + + // Find position of hotkey in replace-string: + USHORT nHotkeyPos = bHaveHotkey + ? rReplace.Search(char(cCurHotkey)) + : STRING_NOTFOUND; + if (nHotkeyPos == STRING_NOTFOUND && bHaveHotkey) + { + if (cCurHotkey < 128) + { + if (islower(cCurHotkey)) + nHotkeyPos = rReplace.Search(toupper(char(cCurHotkey))); + else + nHotkeyPos = rReplace.Search(tolower(char(cCurHotkey))); + } + else // cCurHotkey >= 128 + { + if (cCurHotkey == c_ae) + nHotkeyPos = rReplace.Search(char(c_AE)); + else if (cCurHotkey == c_oe) + nHotkeyPos = rReplace.Search(char(c_OE)); + else if (cCurHotkey == c_ue) + nHotkeyPos = rReplace.Search(char(c_UE)); + else if (cCurHotkey == c_AE) + nHotkeyPos = rReplace.Search(char(c_ae)); + else if (cCurHotkey == c_OE) + nHotkeyPos = rReplace.Search(char(c_oe)); + else if (cCurHotkey == c_UE) + nHotkeyPos = rReplace.Search(char(c_ue)); + } // endif (cCurHotkey < 128) else + + if (nHotkeyPos == STRING_NOTFOUND) + { + eCurResult = HOTKEY_LOST; + bHaveHotkey = FALSE; + } + } // endif (nHotkeyPos == STRING_NOT_FOUND && bHaveHotkey) + + + UINT32 nOutputTokenLength = rReplace.Len() + (bHaveHotkey ? 1 : 0); + + if (bHaveHotkey) + { + memcpy( pOutputPosition, + pCurParseNode->ReplaceString().GetBuffer(), + nHotkeyPos ); + *(pOutputPosition + nHotkeyPos) = cCurHotkeySign; + memcpy( pOutputPosition + nHotkeyPos + 1, + pCurParseNode->ReplaceString().GetBuffer() + nHotkeyPos, + nOutputTokenLength - nHotkeyPos - 1); + } + else + { + memcpy( pOutputPosition, + pCurParseNode->ReplaceString().GetBuffer(), + nOutputTokenLength ); + } + + // Convert first letter into upper if necessary: + u_char cInStart = CalculateBranch(*pInputCurTokenStart) == BR_HOTKEY + ? pInputCurTokenStart[1] + : pInputCurTokenStart[0] ; + u_char * pOutStart = nHotkeyPos == 0 + ? pOutputPosition + 1 + : pOutputPosition ; + if (isupper(cInStart) || cInStart > 127) + { // Possibly cInStart is upper character: + if (isupper(cInStart) || cInStart == c_AE || cInStart == c_OE || cInStart == c_UE) + { // Surely cInStart is upper character: + u_char cOutStart = *pOutStart; + if (cOutStart < 128) + *pOutStart = toupper(cOutStart); + else if (cOutStart == c_ae) + *pOutStart = c_AE; + else if (cOutStart == c_oe) + *pOutStart = c_OE; + else if (cOutStart == c_ue) + *pOutStart = c_UE; + } + } // endif (isupper(cInStart) || cInStart > 127) + + pOutputPosition += nOutputTokenLength; + *pOutputPosition = '\0'; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/xgfconv.cxx b/l10ntools/source/xgfconv.cxx new file mode 100644 index 000000000000..9e1b46d75cbb --- /dev/null +++ b/l10ntools/source/xgfconv.cxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +#include <stdio.h> + +#include "export.hxx" +#include "utf8conv.hxx" + +/*****************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_l10ntools.hxx" +#if defined(UNX) || defined(OS2) +int main( int argc, char *argv[] ) +#else +int _cdecl main( int argc, char *argv[] ) +#endif +/*****************************************************************************/ +{ + if ( argc != 3 ) { + fprintf( stderr, "xgfconv InputFile OutputFile\n" ); + return ( 5 ); + } + + ByteString sInput( argv[ 1 ] ); + ByteString sOutput( argv[ 2 ] ); + + SvFileStream aInput( String( sInput, RTL_TEXTENCODING_ASCII_US ), STREAM_STD_READ ); + if ( !aInput.IsOpen()) { + fprintf( stderr, "ERROR: Unable to open input file!\n" ); + return ( 5 ); + } + + SvFileStream aOutput( String( sOutput, RTL_TEXTENCODING_ASCII_US ), STREAM_STD_WRITE | STREAM_TRUNC ); + if ( !aOutput.IsOpen()) { + fprintf( stderr, "ERROR: Unable to open output file!\n" ); + aInput.Close(); + return ( 5 ); + } + + ByteString sLine; + BOOL bFirst = TRUE; + while ( !aInput.IsEof()) { + aInput.ReadLine( sLine ); + ByteString sLangId = sLine.GetToken( 0, '\t' ); + ByteString sFile = sLine.GetToken( 1, '\t' ); + ByteString sText = sLine.Copy( sLangId.Len() + sFile.Len() + 2 ); + + USHORT nLangId = sLangId.ToInt32(); + CharSet aCharSet = Export::GetCharSet( nLangId ); + if ( aCharSet != 0xFFFF && sText.Len()) { + sText = UTF8Converter::ConvertToUTF8( sText, aCharSet ); + ByteString sOutput = sFile; + sOutput += "\t"; + sOutput += sText; + if ( !bFirst ) { + ByteString sEmpty; + aOutput.WriteLine( sEmpty ); + } + else + bFirst = FALSE; + aOutput.Write( sOutput.GetBuffer(), sOutput.Len()); + } + } + aInput.Close(); + aOutput.Close(); + return ( 0 ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/xmlparse.cxx b/l10ntools/source/xmlparse.cxx new file mode 100644 index 000000000000..ca4ce009b771 --- /dev/null +++ b/l10ntools/source/xmlparse.cxx @@ -0,0 +1,1460 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_l10ntools.hxx" +#include <iterator> /* std::iterator*/ + +#include <stdio.h> +#include <sal/alloca.h> + +#include "xmlparse.hxx" +#include <fstream> +#include <iostream> +#include <osl/mutex.hxx> +#include <osl/thread.hxx> +#ifdef __MINGW32__ +#include <tools/prewin.h> +#include <tools/postwin.h> +#endif +using namespace std; +using namespace osl; + +// +// class XMLChildNode +// + +/*****************************************************************************/ +XMLChildNode::XMLChildNode( XMLParentNode *pPar ) +/*****************************************************************************/ + : pParent( pPar ) +{ + if ( pParent ) + pParent->AddChild( this ); +} + + +/*****************************************************************************/ +XMLChildNode::XMLChildNode( const XMLChildNode& obj) +/*****************************************************************************/ +: XMLNode(obj), + pParent(obj.pParent){} + +/*****************************************************************************/ +XMLChildNode& XMLChildNode::operator=(const XMLChildNode& obj){ +/*****************************************************************************/ + if(this != &obj){ + pParent=obj.pParent; + } + return *this; +} +// +// class XMLParentNode +// + + +/*****************************************************************************/ +XMLParentNode::~XMLParentNode() +/*****************************************************************************/ +{ + if( pChildList ){ + RemoveAndDeleteAllChilds(); + delete pChildList; + pChildList = NULL; + } + pChildList = NULL; +} +/*****************************************************************************/ +XMLParentNode::XMLParentNode( const XMLParentNode& obj) +/*****************************************************************************/ +: XMLChildNode( obj ) +{ + if( obj.pChildList ){ + pChildList=new XMLChildNodeList(); + XMLChildNode* pNode = NULL; + for ( size_t i = 0; i < obj.pChildList->size(); i++ ){ + pNode = (*obj.pChildList)[ i ]; + if( pNode != NULL){ + switch(pNode->GetNodeType()){ + case XML_NODE_TYPE_ELEMENT: + AddChild( new XMLElement( *static_cast<XMLElement* >(pNode) ) ); break; + case XML_NODE_TYPE_DATA: + AddChild( new XMLData ( *static_cast<XMLData* > (pNode) ) ); break; + case XML_NODE_TYPE_COMMENT: + AddChild( new XMLComment( *static_cast<XMLComment* >(pNode) ) ); break; + case XML_NODE_TYPE_DEFAULT: + AddChild( new XMLDefault( *static_cast<XMLDefault* >(pNode) ) ); break; + default: fprintf(stdout,"XMLParentNode::XMLParentNode( const XMLParentNode& obj) strange obj"); + } + } + } + }else pChildList = NULL; +} +/*****************************************************************************/ +XMLParentNode& XMLParentNode::operator=(const XMLParentNode& obj){ +/*****************************************************************************/ + if(this!=&obj){ + XMLChildNode::operator=(obj); + if( pChildList ){ + RemoveAndDeleteAllChilds(); + delete pChildList; + pChildList = NULL; + } + if( obj.pChildList ){ + pChildList=new XMLChildNodeList(); + for ( size_t i = 0; i < obj.pChildList->size(); i++ ) + AddChild( (*obj.pChildList)[ i ] ); + }else pChildList = NULL; + + } + return *this; +} +/*****************************************************************************/ +void XMLParentNode::AddChild( XMLChildNode *pChild ) +/*****************************************************************************/ +{ + if ( !pChildList ) + pChildList = new XMLChildNodeList(); + pChildList->push_back( pChild ); +} + +/*****************************************************************************/ +void XMLParentNode::AddChild( XMLChildNode *pChild , size_t pos ) +/*****************************************************************************/ +{ + if ( !pChildList ) + pChildList = new XMLChildNodeList(); + if ( pos < pChildList->size() ) + { + XMLChildNodeList::iterator it = pChildList->begin(); + ::std::advance( it, pos ); + pChildList->insert( it, pChild ); + } else { + pChildList->push_back( pChild ); + } +} + +/*****************************************************************************/ +int XMLParentNode::GetPosition( ByteString id ){ +/*****************************************************************************/ + XMLElement* a; + + static const ByteString sEnusStr = ByteString(String::CreateFromAscii(ENGLISH_US_ISO).ToLowerAscii() , RTL_TEXTENCODING_ASCII_US ).ToLowerAscii(); + static const ByteString sDeStr = ByteString(String::CreateFromAscii(GERMAN_ISO2).ToLowerAscii() , RTL_TEXTENCODING_ASCII_US ).ToLowerAscii(); + + if ( pChildList ){ + for ( size_t i = 0; i < pChildList->size(); i++ ) { + XMLChildNode *pChild = (*pChildList)[ i ]; + if ( pChild->GetNodeType() == XML_NODE_TYPE_ELEMENT ){ + a = static_cast<XMLElement* >(pChild); + ByteString elemid( a->GetId() ); + elemid.ToLowerAscii(); + if ( elemid.Equals( id.ToLowerAscii() ) ){ + ByteString elemLID( a->GetLanguageId() ); + elemLID.ToLowerAscii(); + if( elemLID.Equals( sEnusStr) ) { + return i; + } + else if( elemLID.Equals( sDeStr) ) { + return i; + } + } + } + } + } + return -1; +} + +/*****************************************************************************/ +size_t XMLParentNode::RemoveChild( XMLElement *pRefElement ) +/*****************************************************************************/ +{ + XMLElement* a; + if ( pChildList ){ + for ( size_t i = 0; i < pChildList->size(); i++ ) { + XMLChildNode *pChild = (*pChildList)[ i ]; + if ( pChild->GetNodeType() == XML_NODE_TYPE_ELEMENT ){ + a = static_cast<XMLElement* >(pChild); + ByteString elemid( a->GetId() ); + elemid.ToLowerAscii(); + ByteString elemLID( a->GetLanguageId() ); + elemLID.ToLowerAscii(); + ByteString pRefLID( pRefElement->GetLanguageId() ); + pRefLID.ToLowerAscii(); + if ( elemid.Equals(pRefElement->GetId()) + && elemLID.Equals( pRefLID ) ) + { + if( pRefElement->ToOString().compareTo( a->ToOString() )==0 ){ + XMLChildNodeList::iterator it = pChildList->begin(); + ::std::advance( it, i ); + pChildList->erase( it ); + delete a; // Test + return i; + } + } + } + + } + } + return -1; +} + +/*****************************************************************************/ +void XMLParentNode::RemoveAndDeleteAllChilds(){ +/*****************************************************************************/ + if ( pChildList ) { + for ( size_t i = 0; i < pChildList->size(); i++ ) + delete (*pChildList)[ i ]; + pChildList->clear(); + } +} + +/*****************************************************************************/ +XMLElement *XMLParentNode::GetChildElement( XMLElement *pRefElement ) +/*****************************************************************************/ +{ + for ( size_t i = 0; i < pChildList->size(); i++ ) { + XMLChildNode *pChild = (*pChildList)[ i ]; + if ( pChild->GetNodeType() == XML_NODE_TYPE_ELEMENT ) + if ((( XMLElement * ) pChild )->GetName() == + pRefElement->GetName()) + { + XMLAttributeList *pList = pRefElement->GetAttributeList(); + if ( !pList ) + return ( XMLElement * ) pChild; + + BOOL bMatch = FALSE; + for ( size_t j = 0; j < pList->size() && bMatch; j++ ) { + XMLAttribute *pAttribute = (*pList)[ j ]; + XMLAttribute *pCandidate = + (( XMLElement * ) pChild )->GetAttribute( + *pAttribute ); + if ( !pCandidate || !pAttribute->IsEqual( *pCandidate )) + bMatch = FALSE; + } + if ( bMatch ) + return ( XMLElement * ) pChild; + } + } + return NULL; +} + +// +// class XMLFile +// + +/*****************************************************************************/ +USHORT XMLFile::GetNodeType() +/*****************************************************************************/ +{ + return XML_NODE_TYPE_FILE; +} + +/*****************************************************************************/ +BOOL XMLFile::Write( ByteString &aFilename ) +/*****************************************************************************/ +{ + + if ( aFilename.Len()) { + // retry harder if there is a NFS problem, + for( int x = 1 ; x < 3 ; x++ ){ // this looks strange...yes! + ofstream aFStream( aFilename.GetBuffer() , ios::out | ios::trunc ); + + if( !aFStream ) // From time to time the stream can not be opened the first time on NFS volumes, + { // I wasn't able to track this down. I think this is an NFS issue ..... + TimeValue aTime; + aTime.Seconds = 3; + aTime.Nanosec = 0; + + osl::Thread::wait( aTime ); + } + else + { + // write out + Write( aFStream ); + aFStream.close(); + + // check! + DirEntry aTarget( aFilename ); + FileStat aFileStat( aTarget ); + + if( aFileStat.GetSize() < 1 ) + { + //retry + aTarget.Kill(); + } + else + { + //everything ok! + return true; + } + } + } + cerr << "ERROR: - helpex - Can't create file " << aFilename.GetBuffer() << "\nPossible reason: Disk full ? Mounted NFS volume broken ? Wrong permissions ?\n"; + exit( -1 ); + } + cerr << "ERROR: - helpex - Empty file name\n"; + exit( -1 ); +} + + + +void XMLFile::WriteString( ofstream &rStream, const String &sString ) +{ + ByteString sText( sString, RTL_TEXTENCODING_UTF8 ); + rStream << sText.GetBuffer(); +} + + +BOOL XMLFile::Write( ofstream &rStream , XMLNode *pCur ) +{ + XMLUtil& xmlutil = XMLUtil::Instance(); + (void) xmlutil; + + if ( !pCur ) + Write( rStream, this ); + else { + switch( pCur->GetNodeType()) { + case XML_NODE_TYPE_FILE: { + if( GetChildList()) + for ( size_t i = 0; i < GetChildList()->size(); i++ ) + Write( rStream, (*GetChildList())[ i ] ); + } + break; + case XML_NODE_TYPE_ELEMENT: { + XMLElement *pElement = ( XMLElement * ) pCur; + rStream << "<"; + WriteString( rStream, pElement->GetName()); + if ( pElement->GetAttributeList()) + for ( size_t j = 0; j < pElement->GetAttributeList()->size(); j++ ) { + rStream << " "; + String sData(* (*pElement->GetAttributeList())[ j ] ); + xmlutil.QuotHTML( sData ); + WriteString( rStream , sData ); + rStream << "=\""; + sData = (*pElement->GetAttributeList())[ j ]->GetValue(); + xmlutil.QuotHTML( sData ); + WriteString( rStream , sData ); + rStream << "\""; + } + if ( !pElement->GetChildList()) + rStream << "/>"; + else { + rStream << ">"; + for ( size_t k = 0; k < pElement->GetChildList()->size(); k++ ) + Write( rStream, (*pElement->GetChildList())[ k ] ); + rStream << "</"; + WriteString( rStream, pElement->GetName()); + rStream << ">"; + } + } + break; + case XML_NODE_TYPE_DATA: { + XMLData *pData = ( XMLData * ) pCur; + String sData( pData->GetData()); + xmlutil.QuotHTML( sData ); + WriteString( rStream, sData ); + } + break; + case XML_NODE_TYPE_COMMENT: { + XMLComment *pComment = ( XMLComment * ) pCur; + rStream << "<!--"; + WriteString( rStream, pComment->GetComment()); + rStream << "-->"; + } + break; + case XML_NODE_TYPE_DEFAULT: { + XMLDefault *pDefault = ( XMLDefault * ) pCur; + WriteString( rStream, pDefault->GetDefault()); + } + break; + } + } + return TRUE; +} + + +void XMLFile::Print( XMLNode *pCur, USHORT nLevel ) +{ + + if ( !pCur ) + Print( this ); + else { + switch( pCur->GetNodeType()) { + case XML_NODE_TYPE_FILE: { + if( GetChildList()) + for ( size_t i = 0; i < GetChildList()->size(); i++ ) + Print( (*GetChildList())[ i ] ); + } + break; + case XML_NODE_TYPE_ELEMENT: { + XMLElement *pElement = ( XMLElement * ) pCur; + + fprintf( stdout, "<%s", ByteString( pElement->GetName(), RTL_TEXTENCODING_UTF8 ).GetBuffer()); + if ( pElement->GetAttributeList()) + for ( size_t j = 0; j < pElement->GetAttributeList()->size(); j++ ){ + ByteString aAttrName( *(*pElement->GetAttributeList())[ j ], RTL_TEXTENCODING_UTF8 ); + if( !aAttrName.EqualsIgnoreCaseAscii( XML_LANG ) ) { + fprintf( stdout, " %s=\"%s\"", + aAttrName.GetBuffer(), + ByteString( (*pElement->GetAttributeList())[ j ]->GetValue(), + RTL_TEXTENCODING_UTF8 ).GetBuffer()); + } + } + if ( !pElement->GetChildList()) + fprintf( stdout, "/>" ); + else { + fprintf( stdout, ">" ); + for ( size_t k = 0; k < pElement->GetChildList()->size(); k++ ) + Print( (*pElement->GetChildList())[ k ], nLevel + 1 ); + fprintf( stdout, "</%s>", ByteString( pElement->GetName(), RTL_TEXTENCODING_UTF8 ).GetBuffer()); + } + } + break; + case XML_NODE_TYPE_DATA: { + XMLData *pData = ( XMLData * ) pCur; + String sData = pData->GetData(); + fprintf( stdout, "%s", ByteString( sData, RTL_TEXTENCODING_UTF8 ).GetBuffer()); + } + break; + case XML_NODE_TYPE_COMMENT: { + XMLComment *pComment = ( XMLComment * ) pCur; + fprintf( stdout, "<!--%s-->", ByteString( pComment->GetComment(), RTL_TEXTENCODING_UTF8 ).GetBuffer()); + } + break; + case XML_NODE_TYPE_DEFAULT: { + XMLDefault *pDefault = ( XMLDefault * ) pCur; + fprintf( stdout, "%s", ByteString( pDefault->GetDefault(), RTL_TEXTENCODING_UTF8 ).GetBuffer()); + } + break; + } + } +} +XMLFile::~XMLFile() +{ + if( XMLStrings != NULL ){ + XMLHashMap::iterator pos = XMLStrings->begin(); + for( ; pos != XMLStrings->end() ; ++pos ){ + delete pos->second; // Check and delete content also ? + } + delete XMLStrings; + XMLStrings = NULL; + } +} +/*****************************************************************************/ +XMLFile::XMLFile( const String &rFileName ) // the file name, empty if created from memory stream +/*****************************************************************************/ + : XMLParentNode( NULL ), + sFileName ( rFileName ), + ID ( "id" ), + OLDREF ( "oldref" ), + XML_LANG ( "xml-lang" ), + XMLStrings ( NULL ) + +{ + nodes_localize.insert( TagMap::value_type(ByteString(String::CreateFromAscii("bookmark"),RTL_TEXTENCODING_ASCII_US) , TRUE) ); + nodes_localize.insert( TagMap::value_type(ByteString(String::CreateFromAscii("variable"),RTL_TEXTENCODING_ASCII_US) , TRUE) ); + nodes_localize.insert( TagMap::value_type(ByteString(String::CreateFromAscii("paragraph"),RTL_TEXTENCODING_ASCII_US) , TRUE) ); + nodes_localize.insert( TagMap::value_type(ByteString(String::CreateFromAscii("alt"),RTL_TEXTENCODING_ASCII_US) , TRUE) ); + nodes_localize.insert( TagMap::value_type(ByteString(String::CreateFromAscii("caption"),RTL_TEXTENCODING_ASCII_US) , TRUE) ); + nodes_localize.insert( TagMap::value_type(ByteString(String::CreateFromAscii("title"),RTL_TEXTENCODING_ASCII_US) , TRUE) ); + nodes_localize.insert( TagMap::value_type(ByteString(String::CreateFromAscii("link"),RTL_TEXTENCODING_ASCII_US) , TRUE) ); +} +/*****************************************************************************/ +void XMLFile::Extract( XMLFile *pCur ) +/*****************************************************************************/ +{ + if( XMLStrings != NULL ) delete XMLStrings; // Elements ? + + XMLStrings = new XMLHashMap(); + if ( !pCur ) + SearchL10NElements( this ); + else { + if( pCur->GetNodeType()==XML_NODE_TYPE_FILE) { + SearchL10NElements(pCur); + } + } +} + +/*****************************************************************************/ +void XMLFile::View(){ +/*****************************************************************************/ + XMLElement* cur; + for(XMLHashMap::iterator pos=XMLStrings->begin(); pos!=XMLStrings->end();++pos){ + fprintf(stdout,"\nid=%s\n",(pos->first).GetBuffer()); + LangHashMap* elem=pos->second; + for(LangHashMap::iterator pos2=elem->begin(); pos2!=elem->end();++pos2){ + fprintf( stdout,"\nlanguage=%s\n",(pos2->first).GetBuffer() ); + cur=pos2->second; + fprintf(stdout,"\n%s\n",((XMLElement*)cur)->ToOString().getStr()); + + } + } +} + +/*****************************************************************************/ +void XMLFile::InsertL10NElement( XMLElement* pElement ){ +/*****************************************************************************/ + ByteString tmpStr,id,oldref,language(""); + LangHashMap* elem; + + if( pElement->GetAttributeList() != NULL ){ + for ( size_t j = 0; j < pElement->GetAttributeList()->size(); j++ ){ + tmpStr=ByteString( *(*pElement->GetAttributeList())[ j ], RTL_TEXTENCODING_UTF8 ); + if( tmpStr.CompareTo(ID)==COMPARE_EQUAL ){ // Get the "id" Attribute + id = ByteString( (*pElement->GetAttributeList())[ j ]->GetValue(),RTL_TEXTENCODING_UTF8 ); + } + if( tmpStr.CompareTo( XML_LANG ) == COMPARE_EQUAL ){ // Get the "xml-lang" Attribute + language = ByteString( (*pElement->GetAttributeList())[ j ]->GetValue(),RTL_TEXTENCODING_UTF8 ); + } + + } + }else{ + fprintf(stdout,"XMLFile::InsertL10NElement: No AttributeList found"); + fprintf(stdout,"++++++++++++++++++++++++++++++++++++++++++++++++++"); + Print( pElement , 0 ); + fprintf(stdout,"++++++++++++++++++++++++++++++++++++++++++++++++++"); + } + + XMLHashMap::iterator pos = XMLStrings->find( id ); + if( pos == XMLStrings->end() ){ // No instanze , create new one + elem = new LangHashMap(); + (*elem)[ language ]=pElement; + XMLStrings->insert( XMLHashMap::value_type( id , elem ) ); + order.push_back( id ); + }else{ // Already there + elem=pos->second; + if ( (*elem)[ language ] ) + { + fprintf(stdout,"Error: Duplicated entry. ID = %s LANG = %s in File %s\n", id.GetBuffer(), language.GetBuffer(), ByteString( sFullName,RTL_TEXTENCODING_ASCII_US ).GetBuffer() ); + exit( -1 ); + } + (*elem)[ language ]=pElement; + } +} +/*****************************************************************************/ +void XMLFile::showType(XMLParentNode* node){ +/*****************************************************************************/ + switch (node->GetNodeType()){ + case XML_NODE_TYPE_ELEMENT: fprintf(stdout,"ELEMENT\n") ;break; + case XML_NODE_TYPE_FILE: fprintf(stdout,"FILE\n") ;break; + case XML_NODE_TYPE_COMMENT: fprintf(stdout,"COMMENT\n") ;break; + case XML_NODE_TYPE_DATA: fprintf(stdout,"DATA\n") ;break; + case XML_NODE_TYPE_DEFAULT: fprintf(stdout,"DEFAULT\n") ;break; + default: break; + } +} +XMLFile::XMLFile() +/*****************************************************************************/ + : XMLParentNode( NULL ), + ID ( "id" ), + OLDREF ( "oldref" ), + XML_LANG ( "xml-lang" ), + XMLStrings ( NULL ){}; + + +XMLFile::XMLFile( const XMLFile& obj ) +/*****************************************************************************/ + : XMLParentNode( obj ), + sFileName ( obj.sFileName ), + ID ( "id" ), + OLDREF ( "oldref" ), + XML_LANG ( "xml-lang" ), + XMLStrings ( NULL ) +{ + if( this!=&obj ) + { + nodes_localize =obj.nodes_localize; + order =obj.order; + + } +} +/*****************************************************************************/ +XMLFile& XMLFile::operator=(const XMLFile& obj){ +/*****************************************************************************/ + if( this!=&obj ){ + + XMLParentNode::operator=(obj); + + nodes_localize =obj.nodes_localize; + order =obj.order; + + if( XMLStrings ) delete XMLStrings; + + if( obj.XMLStrings ) + { + XMLStrings = new XMLHashMap(); + for( XMLHashMap::iterator pos = obj.XMLStrings->begin() ; pos != obj.XMLStrings->end() ; ++pos ) + { + LangHashMap* elem=pos->second; + LangHashMap* newelem = new LangHashMap(); + for(LangHashMap::iterator pos2=elem->begin(); pos2!=elem->end();++pos2){ + (*newelem)[ pos2->first ] = new XMLElement( *pos2->second ); + printf("*"); + } + (*XMLStrings)[ pos->first ] = newelem; + } + } + } + printf("done!\n"); + return *this; +} + + +/*****************************************************************************/ +void XMLFile::SearchL10NElements( XMLParentNode *pCur , int pos) +/*****************************************************************************/ +{ + static const ByteString LOCALIZE("localize"); + static const ByteString THEID("id"); + bool bInsert = true; + if ( !pCur ) + SearchL10NElements( this ); + else { + switch( pCur->GetNodeType()) { + case XML_NODE_TYPE_FILE: { + XMLParentNode* pElement; + if( GetChildList()){ + for ( size_t i = 0; i < GetChildList()->size(); i++ ){ + pElement = (XMLParentNode*) (*GetChildList())[ i ]; + if( pElement->GetNodeType() == XML_NODE_TYPE_ELEMENT ) SearchL10NElements( pElement , i); + } + } + } + break; + case XML_NODE_TYPE_ELEMENT: { + XMLElement *pElement = ( XMLElement * ) pCur; + ByteString sName(pElement->GetName(),RTL_TEXTENCODING_ASCII_US); + ByteString language,tmpStrVal,oldref; + if ( pElement->GetAttributeList()){ + for ( size_t j = 0 , cnt = pElement->GetAttributeList()->size(); j < cnt && bInsert; j++ ){ + const ByteString tmpStr( *(*pElement->GetAttributeList())[ j ],RTL_TEXTENCODING_UTF8 ); + if( tmpStr.CompareTo(THEID)==COMPARE_EQUAL ){ // Get the "id" Attribute + tmpStrVal=ByteString( (*pElement->GetAttributeList())[ j ]->GetValue(),RTL_TEXTENCODING_UTF8 ); + } + if( tmpStr.CompareTo(LOCALIZE)==COMPARE_EQUAL ){ // Get the "localize" Attribute + bInsert=false; + } + if( tmpStr.CompareTo(XML_LANG)==COMPARE_EQUAL ){ // Get the "xml-lang" Attribute + language=ByteString( (*pElement->GetAttributeList())[ j ]->GetValue(),RTL_TEXTENCODING_UTF8 ); + } + if( tmpStr.CompareTo(OLDREF)==COMPARE_EQUAL ){ // Get the "oldref" Attribute + oldref=ByteString( (*pElement->GetAttributeList())[ j ]->GetValue(),RTL_TEXTENCODING_UTF8 ); + } + } + pElement->SetLanguageId ( language ); + pElement->SetId ( tmpStrVal.GetBuffer() ); + pElement->SetOldRef ( oldref ); + pElement->SetPos( pos ); + } + + if ( bInsert && ( nodes_localize.find( sName.ToLowerAscii() ) != nodes_localize.end() ) ) + InsertL10NElement(pElement); + else if ( bInsert && pElement->GetChildList() ){ + for ( size_t k = 0; k < pElement->GetChildList()->size(); k++ ) + SearchL10NElements( (XMLParentNode*)(*pElement->GetChildList())[ k ], k); + } + } + break; + case XML_NODE_TYPE_DATA: { + } + break; + case XML_NODE_TYPE_COMMENT: { + } + break; + case XML_NODE_TYPE_DEFAULT: { + } + break; + } + } +} + +/*****************************************************************************/ +bool XMLFile::CheckExportStatus( XMLParentNode *pCur ) +/*****************************************************************************/ +{ + static bool bStatusExport = true; + const ByteString LOCALIZE("localize"); + const ByteString STATUS("status"); + const ByteString PUBLISH("PUBLISH"); + const ByteString DEPRECATED("DEPRECATED"); + + const ByteString TOPIC("topic"); + bool bInsert = true; + if ( !pCur ) + CheckExportStatus( this ); + else { + switch( pCur->GetNodeType()) { + case XML_NODE_TYPE_FILE: { + XMLParentNode* pElement; + if( GetChildList()){ + for ( size_t i = 0; i < GetChildList()->size(); i++ ){ + pElement = (XMLParentNode*)(*GetChildList())[ i ]; + if( pElement->GetNodeType() == XML_NODE_TYPE_ELEMENT ) CheckExportStatus( pElement );//, i); + } + } + } + break; + case XML_NODE_TYPE_ELEMENT: { + XMLElement *pElement = ( XMLElement * ) pCur; + ByteString sName(pElement->GetName(),RTL_TEXTENCODING_ASCII_US); + if( sName.EqualsIgnoreCaseAscii( TOPIC ) ){ + if ( pElement->GetAttributeList()){ + for ( size_t j = 0 , cnt = pElement->GetAttributeList()->size(); j < cnt && bInsert; j++ ){ + const ByteString tmpStr( *(*pElement->GetAttributeList())[ j ],RTL_TEXTENCODING_UTF8 ); + if( tmpStr.EqualsIgnoreCaseAscii( STATUS ) ){ + ByteString tmpStrVal=ByteString( (*pElement->GetAttributeList())[ j ]->GetValue(),RTL_TEXTENCODING_UTF8 ); + if( !tmpStrVal.EqualsIgnoreCaseAscii( PUBLISH ) && + !tmpStrVal.EqualsIgnoreCaseAscii( DEPRECATED )){ + bStatusExport = false; + } + } + + } + } + } + else if ( pElement->GetChildList() ){ + for ( size_t k = 0; k < pElement->GetChildList()->size(); k++ ) + CheckExportStatus( (XMLParentNode*)(*pElement->GetChildList())[ k ] ); + } + } + break; + } + } + return bStatusExport; +} + +/*****************************************************************************/ +USHORT XMLElement::GetNodeType() +/*****************************************************************************/ +{ + return XML_NODE_TYPE_ELEMENT; +} + +/*****************************************************************************/ +XMLElement::XMLElement(const XMLElement& obj) +/*****************************************************************************/ + : + XMLParentNode ( obj ), + sElementName ( obj.sElementName ), + pAttributes ( NULL ), + project ( obj.project ), + filename ( obj.filename ), + id ( obj.id ), + sOldRef ( obj.sOldRef ), + resourceType ( obj.resourceType ), + languageId ( obj.languageId ), + nPos ( obj.nPos ) + +{ + if ( obj.pAttributes ){ + pAttributes = new XMLAttributeList(); + for ( size_t i = 0; i < obj.pAttributes->size(); i++ ) + AddAttribute( *(*obj.pAttributes)[ i ], (*obj.pAttributes)[ i ]->GetValue() ); + } +} + +/*****************************************************************************/ +XMLElement& XMLElement::operator=(const XMLElement& obj){ +/*****************************************************************************/ + if( this!=&obj ){ + XMLParentNode::operator=(obj); + sElementName =obj.sElementName; + project =obj.project; + filename =obj.filename; + id =obj.id; + sOldRef =obj.sOldRef; + resourceType =obj.resourceType; + languageId =obj.languageId; + nPos =obj.nPos; + + if ( pAttributes ){ + for ( size_t i = 0; i < pAttributes->size(); i++ ) + delete (*pAttributes)[ i ]; + delete pAttributes; + } + if ( obj.pAttributes ){ + pAttributes =new XMLAttributeList(); + for ( size_t i = 0; i < obj.pAttributes->size(); i++ ) + AddAttribute( *(*obj.pAttributes)[ i ], (*obj.pAttributes)[ i ]->GetValue() ); + } + } + return *this; +} + +/*****************************************************************************/ +void XMLElement::AddAttribute( const String &rAttribute, const String &rValue ) +/*****************************************************************************/ +{ + if ( !pAttributes ) + pAttributes = new XMLAttributeList(); + pAttributes->push_back( new XMLAttribute( rAttribute, rValue ) ); +} + +/*****************************************************************************/ +void XMLElement::ChangeLanguageTag( const String &rValue ){ +/*****************************************************************************/ + static const String rName = String::CreateFromAscii("xml-lang"); + SetLanguageId( ByteString(rValue,RTL_TEXTENCODING_UTF8) ); + if ( pAttributes ){ + for ( size_t i = 0; i < pAttributes->size(); i++ ){ + if ( *(*pAttributes)[ i ] == rName ){ + (*pAttributes)[ i ]->setValue(rValue); + } + } + } + XMLChildNode* pNode = NULL; + XMLElement* pElem = NULL; + XMLChildNodeList* pCList = GetChildList(); + + if( pCList != NULL ){ + for ( size_t i = 0; i < pCList->size(); i++ ){ + pNode = (*pCList)[ i ]; + if( pNode != NULL && pNode->GetNodeType() == XML_NODE_TYPE_ELEMENT ){ + pElem = static_cast< XMLElement* >(pNode); + pElem->ChangeLanguageTag( rValue ); + pElem->SetLanguageId( ByteString(rValue,RTL_TEXTENCODING_UTF8) ); + pElem = NULL; + pNode = NULL; + } + } + pCList = NULL; + } +} +/*****************************************************************************/ +XMLAttribute *XMLElement::GetAttribute( const String &rName ) +/*****************************************************************************/ +{ + if ( pAttributes ) + for ( size_t i = 0; i < pAttributes->size(); i++ ) + if ( *(*pAttributes)[ i ] == rName ) + return (*pAttributes)[ i ]; + + return NULL; +} + +/*****************************************************************************/ +XMLElement::~XMLElement() +/*****************************************************************************/ +{ + if ( pAttributes ) { + for ( size_t i = 0; i < pAttributes->size(); i++ ) + delete (*pAttributes)[ i ]; + + delete pAttributes; + pAttributes = NULL; + } +} +/*****************************************************************************/ +bool XMLElement::Equals(OUString refStr){ +/*****************************************************************************/ + return refStr.equals( ToOUString() ); +} + +/*****************************************************************************/ +OString XMLElement::ToOString(){ +/*****************************************************************************/ + OUString ouEmpty; + + OUStringBuffer* buffer = new OUStringBuffer(); + Print( this, *buffer , true ); + + OString result( (sal_Unicode* )buffer->getStr(), buffer->getLength() , RTL_TEXTENCODING_UTF8 ); + delete buffer; + return result; +} +/*****************************************************************************/ +OUString XMLElement::ToOUString(){ +/*****************************************************************************/ + OUStringBuffer* buffer = new OUStringBuffer(); + Print(this,*buffer,true); + OUString result=buffer->makeStringAndClear(); + String xy(result.getStr()); + result=OUString(xy); + delete buffer; + return result; +} +/*****************************************************************************/ +void XMLElement::Print(XMLNode *pCur, OUStringBuffer& buffer , bool rootelement ){ +/*****************************************************************************/ + //YD FIXME somewhere COMMENT is defined as 4! + static const String _COMMENT = String::CreateFromAscii("comment"); + static const OUString XML_LANG ( RTL_CONSTASCII_USTRINGPARAM("xml-lang") ); + + if(pCur!=NULL){ + if(rootelement){ + XMLElement *pElement = ( XMLElement * ) pCur; + if ( pElement->GetAttributeList()){ + if ( pElement->GetChildList()){ + XMLChildNode* tmp=NULL; + for ( size_t k = 0; k < pElement->GetChildList()->size(); k++ ){ + tmp = (*pElement->GetChildList())[ k ]; + Print( tmp, buffer , false); + } + } + } + } + else{ + + switch( pCur->GetNodeType()) { + case XML_NODE_TYPE_ELEMENT: { + XMLElement *pElement = ( XMLElement * ) pCur; + + if( !pElement->GetName().EqualsIgnoreCaseAscii( _COMMENT ) ){ + buffer.append( OUString(RTL_CONSTASCII_USTRINGPARAM("\\<")) ); + buffer.append( pElement->GetName() ); + if ( pElement->GetAttributeList()){ + for ( size_t j = 0; j < pElement->GetAttributeList()->size(); j++ ){ + + OUString aAttrName( *(*pElement->GetAttributeList())[ j ] ); + if( !aAttrName.equalsIgnoreAsciiCase( XML_LANG ) ) { + buffer.append( OUString(RTL_CONSTASCII_USTRINGPARAM(" ")) ); + buffer.append( aAttrName ); + buffer.append( OUString(RTL_CONSTASCII_USTRINGPARAM("=")) ); + buffer.append( OUString(RTL_CONSTASCII_USTRINGPARAM("\\\"")) ); + buffer.append( (*pElement->GetAttributeList())[ j ]->GetValue() ); + buffer.append( OUString(RTL_CONSTASCII_USTRINGPARAM("\\\"")) ); + } + } + } + if ( !pElement->GetChildList()) + buffer.append( OUString(RTL_CONSTASCII_USTRINGPARAM("/\\>")) ); + else { + buffer.append( OUString(RTL_CONSTASCII_USTRINGPARAM("\\>")) ); + XMLChildNode* tmp=NULL; + for ( size_t k = 0; k < pElement->GetChildList()->size(); k++ ){ + tmp = (*pElement->GetChildList())[ k ]; + Print( tmp, buffer , false); + } + buffer.append( OUString(RTL_CONSTASCII_USTRINGPARAM("\\</")) ); + buffer.append( pElement->GetName() ); + buffer.append( OUString(RTL_CONSTASCII_USTRINGPARAM("\\>")) ); + } + } + } + break; + case XML_NODE_TYPE_DATA: { + XMLData *pData = ( XMLData * ) pCur; + String sData = pData->GetData(); + buffer.append( sData ); + } + break; + case XML_NODE_TYPE_COMMENT: { + XMLComment *pComment = ( XMLComment * ) pCur; + buffer.append( OUString(RTL_CONSTASCII_USTRINGPARAM("<!--")) ); + buffer.append( pComment->GetComment() ); + buffer.append( OUString(RTL_CONSTASCII_USTRINGPARAM("-->")) ); + } + break; + case XML_NODE_TYPE_DEFAULT: { + XMLDefault *pDefault = ( XMLDefault * ) pCur; + buffer.append( pDefault->GetDefault() ); + } + break; + } + } + }else { + fprintf(stdout,"\n#+------Error: NULL Pointer in XMLELement::Print------+#\n"); + return; + } +} + + +// +// class XMLData +// +/*****************************************************************************/ +XMLData::XMLData(const XMLData& obj) +/*****************************************************************************/ + : XMLChildNode( obj ), + sData( obj.sData ) , + isNewCreated ( obj.isNewCreated ){} + +/*****************************************************************************/ +XMLData& XMLData::operator=(const XMLData& obj){ +/*****************************************************************************/ + if( this!=&obj ){ + XMLChildNode::operator=( obj ); + sData = obj.sData; + isNewCreated = obj.isNewCreated; + } + return *this; +} +/*****************************************************************************/ +void XMLData::AddData( const String &rData) { +/*****************************************************************************/ + sData += rData; +} + +/*****************************************************************************/ +USHORT XMLData::GetNodeType() +/*****************************************************************************/ +{ + return XML_NODE_TYPE_DATA; +} + +// +// class XMLComment +// + +/*****************************************************************************/ +USHORT XMLComment::GetNodeType() +/*****************************************************************************/ +{ + return XML_NODE_TYPE_COMMENT; +} +/*****************************************************************************/ +XMLComment::XMLComment(const XMLComment& obj) +/*****************************************************************************/ + : XMLChildNode( obj ), + sComment( obj.sComment ){} + +/*****************************************************************************/ +XMLComment& XMLComment::operator=(const XMLComment& obj){ +/*****************************************************************************/ + if( this!=&obj ){ + XMLChildNode::operator=( obj ); + sComment = obj.sComment; + } + return *this; +} + +// +// class XMLDefault +// + +/*****************************************************************************/ +USHORT XMLDefault::GetNodeType() +/*****************************************************************************/ +{ + return XML_NODE_TYPE_DEFAULT; +} +/*****************************************************************************/ +XMLDefault::XMLDefault(const XMLDefault& obj) +/*****************************************************************************/ + : XMLChildNode( obj ), + sDefault( obj.sDefault){} + +/*****************************************************************************/ +XMLDefault& XMLDefault::operator=(const XMLDefault& obj){ +/*****************************************************************************/ + if( this!=&obj ){ + XMLChildNode::operator=( obj ); + sDefault = obj.sDefault; + } + return *this; +} + + +// +// class SimpleXMLParser +// + +#define XML_CHAR_TO_OUSTRING(x) OStringToOUString(OString(x), RTL_TEXTENCODING_UTF8) +#define XML_CHAR_N_TO_OUSTRING(x,n) OStringToOUString(OString(x,n), RTL_TEXTENCODING_UTF8 ) + + +/*****************************************************************************/ +SimpleXMLParser::SimpleXMLParser() +/*****************************************************************************/ + : pXMLFile( NULL ) +{ + aParser = XML_ParserCreate( NULL ); + XML_SetUserData( aParser, this ); + XML_SetElementHandler( aParser, (XML_StartElementHandler) StartElementHandler, (XML_EndElementHandler) EndElementHandler ); + XML_SetCharacterDataHandler( aParser, (XML_CharacterDataHandler) CharacterDataHandler ); + XML_SetCommentHandler( aParser, (XML_CommentHandler) CommentHandler ); + XML_SetDefaultHandler( aParser, (XML_DefaultHandler) DefaultHandler ); +} + +/*****************************************************************************/ +SimpleXMLParser::~SimpleXMLParser() +/*****************************************************************************/ +{ + XML_ParserFree( aParser ); +} + +/*****************************************************************************/ +void SimpleXMLParser::StartElementHandler( + void *userData, const XML_Char *name, const XML_Char **atts ) +/*****************************************************************************/ +{ + (( SimpleXMLParser * ) userData )->StartElement( name, atts ); +} + + +/*****************************************************************************/ +void SimpleXMLParser::EndElementHandler( + void *userData, const XML_Char *name ) +/*****************************************************************************/ +{ + (( SimpleXMLParser * ) userData )->EndElement( name ); +} + +/*****************************************************************************/ +void SimpleXMLParser::CharacterDataHandler( + void *userData, const XML_Char *s, int len ) +/*****************************************************************************/ +{ + (( SimpleXMLParser * ) userData )->CharacterData( s, len ); +} + +/*****************************************************************************/ +void SimpleXMLParser::CommentHandler( + void *userData, const XML_Char *data ) +/*****************************************************************************/ +{ + (( SimpleXMLParser * ) userData )->Comment( data ); +} + +/*****************************************************************************/ +void SimpleXMLParser::DefaultHandler( + void *userData, const XML_Char *s, int len ) +/*****************************************************************************/ +{ + (( SimpleXMLParser * ) userData )->Default( s, len ); +} + +/*****************************************************************************/ +void SimpleXMLParser::StartElement( + const XML_Char *name, const XML_Char **atts ) +/*****************************************************************************/ +{ + String sElementName = String( XML_CHAR_TO_OUSTRING( name )); + XMLElement *pElement = new XMLElement( sElementName, ( XMLParentNode * ) pCurNode ); + pCurNode = pElement; + pCurData = NULL; + + int i = 0; + while( atts[i] ) { + pElement->AddAttribute( + String( XML_CHAR_TO_OUSTRING( atts[ i ] )), + String( XML_CHAR_TO_OUSTRING( atts[ i + 1 ] ))); + i += 2; + } +} + +/*****************************************************************************/ +void SimpleXMLParser::EndElement( const XML_Char *name ) +/*****************************************************************************/ +{ + // This variable is not used at all, but the the sax C interface can't be changed + // To prevent warnings this dummy assignment is used + // +++ + (void) name; + + pCurNode = pCurNode->GetParent(); + pCurData = NULL; +} + +/*****************************************************************************/ +void SimpleXMLParser::CharacterData( + const XML_Char *s, int len ) +/*****************************************************************************/ +{ + if ( !pCurData ){ + String x=String( XML_CHAR_N_TO_OUSTRING( s, len )); + XMLUtil::UnQuotHTML(x); + pCurData = new XMLData( x , pCurNode ); + }else{ + String x=String( XML_CHAR_N_TO_OUSTRING( s, len )); + XMLUtil::UnQuotHTML(x); + pCurData->AddData( x ); + + } +} + +/*****************************************************************************/ +void SimpleXMLParser::Comment( + const XML_Char *data ) +/*****************************************************************************/ +{ + pCurData = NULL; + new XMLComment( String( XML_CHAR_TO_OUSTRING( data )), pCurNode ); +} + +/*****************************************************************************/ +void SimpleXMLParser::Default( + const XML_Char *s, int len ) +/*****************************************************************************/ +{ + pCurData = NULL; + new XMLDefault( + String( XML_CHAR_N_TO_OUSTRING( s, len )), pCurNode ); +} + +/*****************************************************************************/ +XMLFile *SimpleXMLParser::Execute( const String &rFullFileName , const String &rFileName, XMLFile* pXMLFileIn ) +/*****************************************************************************/ +{ +// printf("DBG: SimpleXMLParser::Execute( %s )", ByteString( rFileName , RTL_TEXTENCODING_ASCII_US ).GetBuffer() ); + aErrorInformation.eCode = XML_ERROR_NONE; + aErrorInformation.nLine = 0; + aErrorInformation.nColumn = 0; + aErrorInformation.sMessage = String::CreateFromAscii( "ERROR: Unable to open file " ); + aErrorInformation.sMessage += rFileName; + + SvFileStream aStream( rFileName, STREAM_STD_READ ); + + if ( !aStream.IsOpen()) + return NULL; + + SvMemoryStream aMemStream; + aStream >> aMemStream; + aMemStream.Seek( 0 ); + + aStream.Close(); + + pXMLFile = pXMLFileIn; + pXMLFile->SetName( rFileName ); + pXMLFile->SetFullName( rFullFileName ); + + return Execute( &aMemStream ); +} + +/*****************************************************************************/ +XMLFile *SimpleXMLParser::Execute( SvMemoryStream *pStream ) +/*****************************************************************************/ +{ + if ( !pXMLFile ) + pXMLFile = new XMLFile( String()); + + pCurNode = pXMLFile; + pCurData = NULL; + + ULONG nPos = pStream->Tell(); + pStream->Seek( STREAM_SEEK_TO_END ); + + aErrorInformation.eCode = XML_ERROR_NONE; + aErrorInformation.nLine = 0; + aErrorInformation.nColumn = 0; + if ( pXMLFile->GetName().Len()) { + aErrorInformation.sMessage = String::CreateFromAscii( "File " ); + aErrorInformation.sMessage += pXMLFile->GetName(); + aErrorInformation.sMessage += String::CreateFromAscii( " parsed succesfully" ); + } + else + aErrorInformation.sMessage = String::CreateFromAscii( "XML-File parsed successfully" ); + + if ( !XML_Parse( + aParser, ( char * ) pStream->GetData() + nPos, pStream->Tell() - nPos, TRUE )) + { + aErrorInformation.eCode = XML_GetErrorCode( aParser ); + aErrorInformation.nLine = XML_GetErrorLineNumber( aParser ); + aErrorInformation.nColumn = XML_GetErrorColumnNumber( aParser ); + + aErrorInformation.sMessage = String::CreateFromAscii( "ERROR: " ); + if ( pXMLFile->GetName().Len()) + aErrorInformation.sMessage += pXMLFile->GetName(); + else + aErrorInformation.sMessage += String::CreateFromAscii( "XML-File" ); + aErrorInformation.sMessage += String::CreateFromAscii( " (" ); + aErrorInformation.sMessage += String::CreateFromInt64( aErrorInformation.nLine ); + aErrorInformation.sMessage += String::CreateFromAscii( "," ); + aErrorInformation.sMessage += String::CreateFromInt64( aErrorInformation.nColumn ); + aErrorInformation.sMessage += String::CreateFromAscii( "): " ); + + switch( aErrorInformation.eCode ) { + case XML_ERROR_NO_MEMORY: aErrorInformation.sMessage += String::CreateFromAscii( "No memory" ); break; + case XML_ERROR_SYNTAX: aErrorInformation.sMessage += String::CreateFromAscii( "Syntax" ); break; + case XML_ERROR_NO_ELEMENTS: aErrorInformation.sMessage += String::CreateFromAscii( "No elements" ); break; + case XML_ERROR_INVALID_TOKEN: aErrorInformation.sMessage += String::CreateFromAscii( "Invalid token" ); break; + case XML_ERROR_UNCLOSED_TOKEN: aErrorInformation.sMessage += String::CreateFromAscii( "Unclosed token" ); break; + case XML_ERROR_PARTIAL_CHAR: aErrorInformation.sMessage += String::CreateFromAscii( "Partial char" ); break; + case XML_ERROR_TAG_MISMATCH: aErrorInformation.sMessage += String::CreateFromAscii( "Tag mismatch" ); break; + case XML_ERROR_DUPLICATE_ATTRIBUTE: aErrorInformation.sMessage += String::CreateFromAscii( "Dublicat attribute" ); break; + case XML_ERROR_JUNK_AFTER_DOC_ELEMENT: aErrorInformation.sMessage += String::CreateFromAscii( "Junk after doc element" ); break; + case XML_ERROR_PARAM_ENTITY_REF: aErrorInformation.sMessage += String::CreateFromAscii( "Param entity ref" ); break; + case XML_ERROR_UNDEFINED_ENTITY: aErrorInformation.sMessage += String::CreateFromAscii( "Undefined entity" ); break; + case XML_ERROR_RECURSIVE_ENTITY_REF: aErrorInformation.sMessage += String::CreateFromAscii( "Recursive entity ref" ); break; + case XML_ERROR_ASYNC_ENTITY: aErrorInformation.sMessage += String::CreateFromAscii( "Async_entity" ); break; + case XML_ERROR_BAD_CHAR_REF: aErrorInformation.sMessage += String::CreateFromAscii( "Bad char ref" ); break; + case XML_ERROR_BINARY_ENTITY_REF: aErrorInformation.sMessage += String::CreateFromAscii( "Binary entity" ); break; + case XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF: aErrorInformation.sMessage += String::CreateFromAscii( "Attribute external entity ref" ); break; + case XML_ERROR_MISPLACED_XML_PI: aErrorInformation.sMessage += String::CreateFromAscii( "Misplaced xml pi" ); break; + case XML_ERROR_UNKNOWN_ENCODING: aErrorInformation.sMessage += String::CreateFromAscii( "Unknown encoding" ); break; + case XML_ERROR_INCORRECT_ENCODING: aErrorInformation.sMessage += String::CreateFromAscii( "Incorrect encoding" ); break; + case XML_ERROR_UNCLOSED_CDATA_SECTION: aErrorInformation.sMessage += String::CreateFromAscii( "Unclosed cdata section" ); break; + case XML_ERROR_EXTERNAL_ENTITY_HANDLING: aErrorInformation.sMessage += String::CreateFromAscii( "External entity handling" ); break; + case XML_ERROR_NOT_STANDALONE: aErrorInformation.sMessage += String::CreateFromAscii( "Not standalone" ); break; + case XML_ERROR_NONE: break; + default: + break; + + } + delete pXMLFile; + pXMLFile = NULL; + } + pStream->Seek( nPos ); + + return pXMLFile; +} + +/*****************************************************************************/ +void XMLUtil::QuotHTML( String &rString ) +/*****************************************************************************/ +{ + OUStringBuffer sReturn; + static const String LT(String::CreateFromAscii("<")); + static const String QLT(String::CreateFromAscii("<")); + static const String GT(String::CreateFromAscii(">")); + static const String QGT(String::CreateFromAscii(">")); + static const String QUOT(String::CreateFromAscii("\\")); + static const String QQUOT(String::CreateFromAscii(""")); + static const String APOS(String::CreateFromAscii("\"")); + static const String QAPOS(String::CreateFromAscii("'")); + static const String AMP(String::CreateFromAscii("&")); + static const String QAMP(String::CreateFromAscii("&")); + static const String SLASH(String::CreateFromAscii("\\")); + + for ( USHORT i = 0; i < rString.Len(); i++) { + if ( i < rString.Len()) { + switch ( rString.GetChar( i )) { + case '\\': if( i+1 <= rString.Len() ){ + switch( rString.GetChar( i+1 ) ){ + case '<': sReturn.append( LT );i++;break; + case '>': sReturn.append( GT );i++;break; + case '\\': sReturn.append( QUOT );i++;break; + case '\"': sReturn.append( APOS );i++;break; + //case '\'': sReturn += "\'";i++;break; + //case '&' : sRetrun += "&";i++;break; + default: sReturn.append( SLASH );break; + + } + } + break; + + case '<': + sReturn.append( QLT ); + break; + + case '>': + sReturn.append( QGT ); + break; + + case '\"': + sReturn.append( QQUOT ); + break; + +/* case '\'': + sReturn += "'"; + break; +*/ + case '&': + if ( + ( ( i + 4 ) < rString.Len()) && + ( String( rString.Copy( i, 5 ) ).Equals( QAMP ) ) + ) + sReturn.append( rString.GetChar( i ) ); + else + sReturn.append( QAMP ); + break; + + default: + sReturn.append( rString.GetChar( i ) ); + break; + } + } + } + rString = String( sReturn.makeStringAndClear() ); +} + +void XMLUtil::UnQuotHTML( String &rString ){ + UnQuotData( rString ); +} + +void XMLUtil::UnQuotData( String &rString_in ){ + ByteString sReturn; + ByteString sString( rString_in , RTL_TEXTENCODING_UTF8 ); + while ( sString.Len()) { + if ( sString.Copy( 0, 1 ) == "\\" ) { + sReturn += "\\\\"; + sString.Erase( 0, 1 ); + } + else if ( sString.Copy( 0, 5 ) == "&" ) { + sReturn += "&"; + sString.Erase( 0, 5 ); + } + else if ( sString.Copy( 0, 4 ) == "<" ) { + sReturn += "<"; + sString.Erase( 0, 4 ); + } + else if ( sString.Copy( 0, 4 ) == ">" ) { + sReturn += ">"; + sString.Erase( 0, 4 ); + } + else if ( sString.Copy( 0, 6 ) == """ ) { + sReturn += "\""; + sString.Erase( 0, 6 ); + } + else if ( sString.Copy( 0, 6 ) == "'" ) { + sReturn += "\'"; + sString.Erase( 0, 6 ); + } + else { + sReturn += sString.GetChar( 0 ); + sString.Erase( 0, 1 ); + } + } + rString_in = String(sReturn , RTL_TEXTENCODING_UTF8 ); + + +} + +XMLUtil::XMLUtil(){ +} + + +/*****************************************************************************/ +void XMLUtil::dump(){ +/*****************************************************************************/ + int cnt=1; + printf("size=%lu\n",static_cast<unsigned long>(lMap.size())); + for(HashMap::iterator pos = lMap.begin(); pos != lMap.end() ; ++pos){ + fprintf(stdout,"key=%s , value=%d , no=%d\n",pos->first.GetBuffer(),pos->second,cnt++); + } +} +/*****************************************************************************/ +XMLUtil& XMLUtil::Instance(){ +/*****************************************************************************/ + static XMLUtil instance; + return instance; +} +/*****************************************************************************/ +XMLUtil::~XMLUtil(){} +/*****************************************************************************/ +/*****************************************************************************/ +ByteString XMLUtil::GetIsoLangByIndex( USHORT nIndex ) +/*****************************************************************************/ +{ + if(nIndex > 0 && MAX_LANGUAGES >= nIndex ) + return isoArray[nIndex]; + return ""; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/xrm_yy_wrapper.c b/l10ntools/source/xrm_yy_wrapper.c new file mode 100644 index 000000000000..2724ad0797ba --- /dev/null +++ b/l10ntools/source/xrm_yy_wrapper.c @@ -0,0 +1,5 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +// Helper to suppress warnings in lex generated c code, see #i57362# +#include "xrm_yy.c" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/xrmlex.l b/l10ntools/source/xrmlex.l new file mode 100644 index 000000000000..6229525d7e84 --- /dev/null +++ b/l10ntools/source/xrmlex.l @@ -0,0 +1,224 @@ +%{ +/* + * lexer for parsing xml-property source files (*.xml) + * + */ + + +/* enlarge token buffer to tokenize whole strings */ +#undef YYLMAX +#define YYLMAX 64000 + +/* to enable debug output define LEXDEBUG */ +#define LEXDEBUG 1 +#ifdef LEXDEBUG +#define OUTPUT fprintf +#else +#define OUTPUT(Par1,Par2); +#endif + +/* table of possible token ids */ +#include "tokens.h" +#include <stdlib.h> +#include <stdio.h> + +#if defined __GNUC__ +#pragma GCC system_header +#elif defined __SINPRO_CC +#pragma disable_warn +#elif defined _MSC_VER +#pragma warning(push, 1) +#endif + +/* external functions (C++ code, declared as extren "C" */ +extern int WorkOnTokenSet( int, char* ); +extern int Argument( char * ); +extern int InitXrmExport( char * , char * ); +extern int EndXrmExport(); +extern int GetError(); +extern int SetError(); +extern char *GetOutputFile( int argc, char* argv[]); +extern FILE *GetXrmFile(); +extern int isQuiet(); +extern void removeTempFile(); +extern char* getFilename(); + +/* forwards */ +void YYWarning(); + +int bText=0; +%} + +%p 24000 +%e 1200 +%n 500 + +%% + +"<p "[^\>]*xml:lang[^\>]*\> { + WorkOnTokenSet( XRM_TEXT_START , yytext ); +} + +"</p>" { + WorkOnTokenSet( XRM_TEXT_END, yytext ); +} + +"<h1 "[^\>]*xml:lang[^\>]*\> { + WorkOnTokenSet( XRM_TEXT_START , yytext ); +} + +"</h1>" { + WorkOnTokenSet( XRM_TEXT_END, yytext ); +} +"<h2 "[^\>]*xml:lang[^\>]*\> { + WorkOnTokenSet( XRM_TEXT_START , yytext ); +} + +"</h2>" { + WorkOnTokenSet( XRM_TEXT_END, yytext ); +} +"<h3 "[^\>]*xml:lang[^\>]*\> { + WorkOnTokenSet( XRM_TEXT_START , yytext ); +} + +"</h3>" { + WorkOnTokenSet( XRM_TEXT_END, yytext ); +} +"<h4 "[^\>]*xml:lang[^\>]*\> { + WorkOnTokenSet( XRM_TEXT_START , yytext ); +} + +"</h4>" { + WorkOnTokenSet( XRM_TEXT_END, yytext ); +} +"<h5 "[^\>]*xml:lang[^\>]*\> { + WorkOnTokenSet( XRM_TEXT_START , yytext ); +} + +"</h5>" { + WorkOnTokenSet( XRM_TEXT_END, yytext ); +} + + + + + + +"<!--" { + char c1 = 0, c2 = 0, c3 = input(); + char pChar[2]; + pChar[1] = 0x00; + pChar[0] = c3; + + WorkOnTokenSet( COMMEND, yytext ); + WorkOnTokenSet( COMMEND, pChar ); + + for(;;) { + if ( c3 == EOF ) + break; + if ( c1 == '-' && c2 == '-' && c3 == '>' ) + break; + c1 = c2; + c2 = c3; + c3 = input(); + pChar[0] = c3; + WorkOnTokenSet( COMMEND, pChar ); + } +} + +.|\n { + if ( bText == 1 ) + WorkOnTokenSet( XML_TEXTCHAR, yytext ); + else + WorkOnTokenSet( UNKNOWNCHAR, yytext ); +} + + +%% + +/*****************************************************************************/ +int yywrap(void) +/*****************************************************************************/ +{ + return 1; +} + +/*****************************************************************************/ +void YYWarning( char *s ) +/*****************************************************************************/ +{ + /* write warning to stderr */ + fprintf( stderr, + "Warning: \"%s\" in line %d: \"%s\"\n", s, yylineno, yytext ); +} + +/*****************************************************************************/ +#ifdef GCC +void yyerror ( char *s, ... ) +#else +void yyerror ( char *s ) +#endif +/*****************************************************************************/ +{ + /* write error to stderr */ + fprintf( stderr, + "Error: \"%s\" in line %d: \"%s\"\n", s, yylineno, yytext ); + SetError(); +} + +/*****************************************************************************/ +int +#ifdef WNT +_cdecl +#endif +main( int argc, char* argv[]) +/*****************************************************************************/ +{ + /* error level */ + int nRetValue = 0; + char *pOutput; + FILE *pFile; + + pOutput = GetOutputFile( argc, argv ); + + if ( !pOutput ) { + fprintf( stdout, "Syntax: XRMEX[-p Prj][-r PrjRoot]-i FileIn [-o FileOut][-m DataBase][-e][-b][-u][-NOUTF8][-L l1,l2,...]\n" ); + fprintf( stdout, " Prj: Project\n" ); + fprintf( stdout, " PrjRoot: Path to project root (..\\.. etc.)\n" ); + fprintf( stdout, " FileIn: Source files (*.src)\n" ); + fprintf( stdout, " FileOut: Destination file (*.*)\n" ); + fprintf( stdout, " DataBase: Mergedata (*.sdf)\n" ); + fprintf( stdout, " -e: Disable writing errorlog\n" ); + fprintf( stdout, " -b: Break when Token \"HelpText\" found in source\n" ); + fprintf( stdout, " -u: [english] and [german] are allowed, Id is Taken from DataBase \n" ); + fprintf( stdout, " -NOUTF8: disable UTF8 as language independent encoding\n" ); + fprintf( stdout, " -L: Restrict the handled languages. l1,l2,... are elements of (de,en-US,es...)\n" ); + fprintf( stdout, " A fallback language can be defined like this: l1=f1.\n" ); + fprintf( stdout, " f1, f2,... are also elements of (de,en-US,es...)\n" ); + fprintf( stdout, " Example: -L en-US,es=de\n" ); + fprintf( stdout, " Restriction to es and en-US, de will be fallback for 99\n" ); +// fprintf( stdout, " -ISO99: IsoCode is the full qualified ISO language code for language 99" ); + return 1; + } + pFile = GetXrmFile(); + InitXrmExport( pOutput , getFilename() ); + + if ( !pFile ) + return 1; + + yyin = pFile; + + /* create global instance of class XmlExport */ + //InitXrmExport( pOutput ); + + /* start parser */ + yylex(); + + /* get error info. and end export */ + nRetValue = GetError(); + EndXrmExport(); + + removeTempFile(); + /* return error level */ + return nRetValue; +} diff --git a/l10ntools/source/xrmmerge.cxx b/l10ntools/source/xrmmerge.cxx new file mode 100644 index 000000000000..d62eacb05578 --- /dev/null +++ b/l10ntools/source/xrmmerge.cxx @@ -0,0 +1,733 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_l10ntools.hxx" +#include <stdio.h> +#include <tools/string.hxx> +#include <tools/fsys.hxx> + +// local includes +#include "export.hxx" +#include "xrmmerge.hxx" +#include "utf8conv.hxx" +#include "tokens.h" +#include <iostream> +#include <vector> + +using namespace std; + +extern "C" { int yyerror( char * ); } +extern "C" { int YYWarning( char * ); } + +// defines to parse command line +#define STATE_NON 0x0001 +#define STATE_INPUT 0x0002 +#define STATE_OUTPUT 0x0003 +#define STATE_PRJ 0x0004 +#define STATE_ROOT 0x0005 +#define STATE_MERGESRC 0x0006 +#define STATE_ERRORLOG 0x0007 +#define STATE_UTF8 0x000B +#define STATE_LANGUAGES 0x000C +#define STATE_ISOCODE99 0x000D + +// set of global variables +BOOL bEnableExport; +BOOL bMergeMode; +BOOL bErrorLog; +BOOL bUTF8; +ByteString sPrj; +ByteString sPrjRoot; +ByteString sInputFileName; +ByteString sActFileName; +ByteString sOutputFile; +ByteString sMergeSrc; +String sUsedTempFile; +XRMResParser *pParser = NULL; + +extern "C" { +// the whole interface to lexer is in this extern "C" section + +/*****************************************************************************/ +extern char *GetOutputFile( int argc, char* argv[]) +/*****************************************************************************/ +{ + bEnableExport = FALSE; + bMergeMode = FALSE; + bErrorLog = TRUE; + bUTF8 = TRUE; + sPrj = ""; + sPrjRoot = ""; + sInputFileName = ""; + sActFileName = ""; + Export::sLanguages = ""; + USHORT nState = STATE_NON; + BOOL bInput = FALSE; + + // parse command line + for( int i = 1; i < argc; i++ ) { + if ( ByteString( argv[ i ] ).ToUpperAscii() == "-I" ) { + nState = STATE_INPUT; // next token specifies source file + } + else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-O" ) { + nState = STATE_OUTPUT; // next token specifies the dest file + } + else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-P" ) { + nState = STATE_PRJ; // next token specifies the cur. project + } + else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-R" ) { + nState = STATE_ROOT; // next token specifies path to project root + } + else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-M" ) { + nState = STATE_MERGESRC; // next token specifies the merge database + } + else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-E" ) { + nState = STATE_ERRORLOG; + bErrorLog = FALSE; + } + else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-UTF8" ) { + nState = STATE_UTF8; + bUTF8 = TRUE; + } + else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-NOUTF8" ) { + nState = STATE_UTF8; + bUTF8 = FALSE; + } + else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-L" ) { + nState = STATE_LANGUAGES; + } + else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-ISO99" ) { + nState = STATE_ISOCODE99; + } + else { + switch ( nState ) { + case STATE_NON: { + return NULL; // no valid command line + } + case STATE_INPUT: { + sInputFileName = argv[ i ]; + bInput = TRUE; // source file found + } + break; + case STATE_OUTPUT: { + sOutputFile = argv[ i ]; // the dest. file + } + break; + case STATE_PRJ: { + sPrj = ByteString( argv[ i ]); + } + break; + case STATE_ROOT: { + sPrjRoot = ByteString( argv[ i ]); // path to project root + } + break; + case STATE_MERGESRC: { + sMergeSrc = ByteString( argv[ i ]); + bMergeMode = TRUE; // activate merge mode, cause merge database found + } + break; + case STATE_LANGUAGES: { + Export::sLanguages = ByteString( argv[ i ]); + } + break; + } + } + } + + if ( bInput ) { + // command line is valid + bEnableExport = TRUE; + char *pReturn = new char[ sOutputFile.Len() + 1 ]; + strcpy( pReturn, sOutputFile.GetBuffer()); // #100211# - checked + return pReturn; + } + + // command line is not valid + return NULL; +} +void removeTempFile(){ + if( !sUsedTempFile.EqualsIgnoreCaseAscii( "" ) ){ + DirEntry aTempFile( sUsedTempFile ); + aTempFile.Kill(); + } +} +/*****************************************************************************/ +int InitXrmExport( char *pOutput , char* pFilename) +/*****************************************************************************/ +{ + // instanciate Export + ByteString sOutput( pOutput ); + ByteString sFilename( pFilename ); + Export::InitLanguages( false ); + + if ( bMergeMode ) + pParser = new XRMResMerge( sMergeSrc, sOutputFile, sFilename ); + else if ( sOutputFile.Len()) { + pParser = new XRMResExport( sOutputFile, sPrj, sActFileName ); + } + + return 1; +} + +/*****************************************************************************/ +int EndXrmExport() +/*****************************************************************************/ +{ + delete pParser; + return 1; +} +extern const char* getFilename() +{ + return sInputFileName.GetBuffer(); +} +/*****************************************************************************/ +extern FILE *GetXrmFile() +/*****************************************************************************/ +{ + FILE *pFile = 0; + // look for valid filename + if ( sInputFileName.Len()) { + if( Export::fileHasUTF8ByteOrderMarker( sInputFileName ) ){ + DirEntry aTempFile = Export::GetTempFile(); + DirEntry aSourceFile( String( sInputFileName , RTL_TEXTENCODING_ASCII_US ) ); + aSourceFile.CopyTo( aTempFile , FSYS_ACTION_COPYFILE ); + String sTempFile = aTempFile.GetFull(); + Export::RemoveUTF8ByteOrderMarkerFromFile( ByteString( sTempFile , RTL_TEXTENCODING_ASCII_US ) ); + pFile = fopen( ByteString( sTempFile , RTL_TEXTENCODING_ASCII_US ).GetBuffer(), "r" ); + sUsedTempFile = sTempFile; + }else{ + // able to open file? + pFile = fopen( sInputFileName.GetBuffer(), "r" ); + sUsedTempFile = String::CreateFromAscii(""); + } + if ( !pFile ){ + fprintf( stderr, "Error: Could not open file %s\n", + sInputFileName.GetBuffer()); + } + else { + // this is a valid file which can be opened, so + // create path to project root + DirEntry aEntry( String( sInputFileName, RTL_TEXTENCODING_ASCII_US )); + aEntry.ToAbs(); + ByteString sFullEntry( aEntry.GetFull(), RTL_TEXTENCODING_ASCII_US ); + aEntry += DirEntry( String( "..", RTL_TEXTENCODING_ASCII_US )); + aEntry += DirEntry( sPrjRoot ); + ByteString sPrjEntry( aEntry.GetFull(), RTL_TEXTENCODING_ASCII_US ); + + // create file name, beginnig with project root + // (e.g.: source\ui\src\menue.src) + sActFileName = sFullEntry.Copy( sPrjEntry.Len() + 1 ); + + + sActFileName.SearchAndReplaceAll( "/", "\\" ); + + return pFile; + } + } + // this means the file could not be opened + return NULL; +} + +/*****************************************************************************/ +int WorkOnTokenSet( int nTyp, char *pTokenText ) +/*****************************************************************************/ +{ + //printf("Typ = %d , text = '%s'\n",nTyp , pTokenText ); + pParser->Execute( nTyp, pTokenText ); + + return 1; +} + +/*****************************************************************************/ +int SetError() +/*****************************************************************************/ +{ + pParser->SetError(); + return 1; +} +} + +extern "C" { +/*****************************************************************************/ +int GetError() +/*****************************************************************************/ +{ + return pParser->GetError(); +} +} + +// +// class XRMResParser +// + + +/*****************************************************************************/ +XRMResParser::XRMResParser() +/*****************************************************************************/ + : bError( FALSE ), + bText( FALSE ) +{ + aLanguages = Export::GetLanguages(); +} + +/*****************************************************************************/ +XRMResParser::~XRMResParser() +/*****************************************************************************/ +{ +} + +/*****************************************************************************/ +int XRMResParser::Execute( int nToken, char * pToken ) +/*****************************************************************************/ +{ + ByteString rToken( pToken ); + + switch ( nToken ) { + case XRM_README_START: + sLID = ""; + sGID = GetAttribute( rToken, "name" ); + break; + + case XRM_README_END: + sGID = ""; + break; + + case XRM_SECTION_START: + sLID = ""; + sGID += "."; + sGID += GetAttribute( rToken, "id" ); + //sLocalized = "1"; + + //sLocalized = "X:"; + sLocalized = true; + break; + + case XRM_SECTION_END: + sGID = sGID.GetToken( 0, '.' ); + break; + + case XRM_PARAGRAPH_START: + sLID = ""; + sGID += "."; + sGID += GetAttribute( rToken, "id" ); +// if ( GetAttribute( rToken, "localized" ) == "false" ) +// sLocalized += "0"; +// sLocalized = false; +// else +// sLocalized += "1"; + sLocalized = true; + break; + + case XRM_PARAGRAPH_END: { + if ( sLID.Len()) + EndOfText( sCurrentOpenTag, sCurrentCloseTag ); + ByteString sTmp = sGID; + sGID = ""; + for ( USHORT i = 0; i + 1 < sTmp.GetTokenCount( '.' ); i++ ) { + if ( sGID.Len()) + sGID += "."; + sGID += sTmp.GetToken( i, '.' ); + } + //sLocalized = sLocalized.Copy( 0, sLocalized.Len() - 1 ); + } + break; + + case XRM_TEXT_START:{ + //printf("->XRM_TEXT_START\n"); + ByteString sNewLID = GetAttribute( rToken, "id" ); + if ( sNewLID != sLID ) { + //EndOfText( sCurrentOpenTag, sCurrentCloseTag ); + sLID = sNewLID; + } + bText = TRUE; + sCurrentText = ""; + sCurrentOpenTag = rToken; + Output( rToken ); + //printf("<-XRM_TEXT_START\n"); + } + break; + + case XRM_TEXT_END: { + sCurrentCloseTag = rToken; + //printf("->XRM_TEXT_END\n"); + ByteString sLang = GetAttribute( sCurrentOpenTag, "xml:lang" ); + WorkOnText( sCurrentOpenTag, sCurrentText ); + Output( sCurrentText ); + EndOfText( sCurrentOpenTag, sCurrentCloseTag );// <--- + bText = FALSE; + rToken = ByteString(""); + sCurrentText = ByteString(""); + //printf("<-XRM_TEXT_END"); + } + break; + + case XRM_LIST_START: + sLID = ""; + break; + + case XRM_LIST_END: + if ( sLID.Len()) + EndOfText( sCurrentOpenTag, sCurrentCloseTag ); + break; + + default: + if ( bText ) { + sCurrentText += rToken; + } + break; + } + + if ( !bText ) + { + Output( rToken ); + } + return 0; +} + +/*****************************************************************************/ +ByteString XRMResParser::GetAttribute( const ByteString &rToken, const ByteString &rAttribute ) +/*****************************************************************************/ +{ + ByteString sTmp( rToken ); + sTmp.SearchAndReplaceAll( "\t", " " ); + + ByteString sSearch( " " ); + sSearch += rAttribute; + sSearch += "="; + USHORT nPos = sTmp.Search( sSearch ); + + if ( nPos != STRING_NOTFOUND ) { + sTmp = sTmp.Copy( nPos ); + ByteString sId = sTmp.GetToken( 1, '\"' ); + return sId; + } + return ""; +} + + +/*****************************************************************************/ +void XRMResParser::Error( const ByteString &rError ) +/*****************************************************************************/ +{ + yyerror(( char * ) rError.GetBuffer()); +} + +/*****************************************************************************/ +void XRMResParser::ConvertStringToDBFormat( ByteString &rString ) +/*****************************************************************************/ +{ + ByteString sResult; + do { + sResult = rString; + rString.EraseLeadingChars( _LF ); + // rString.EraseLeadingChars( ' ' ); + rString.EraseLeadingChars( '\t' ); + // rString.EraseTrailingChars( ' ' ); + rString.EraseTrailingChars( '\t' ); + } while ( sResult != rString ); + + rString.SearchAndReplaceAll( "\t", "\\t" ); +} + +/*****************************************************************************/ +void XRMResParser::ConvertStringToXMLFormat( ByteString &rString ) +/*****************************************************************************/ +{ + rString.SearchAndReplaceAll( "\\t", "\t" ); +} + + + +// +// class XRMResOutputParser +// + +/*****************************************************************************/ +XRMResOutputParser::XRMResOutputParser ( const ByteString &rOutputFile ) +/*****************************************************************************/ +{ + aLanguages = Export::GetLanguages(); + pOutputStream = + new SvFileStream( + String( rOutputFile, RTL_TEXTENCODING_ASCII_US ), + STREAM_STD_WRITE | STREAM_TRUNC + ); + pOutputStream->SetStreamCharSet( RTL_TEXTENCODING_UTF8 ); + if ( !pOutputStream->IsOpen()) { + ByteString sError( "Unable to open output file: " ); + sError += rOutputFile; + Error( sError ); + delete pOutputStream; + pOutputStream = NULL; + } +} + +/*****************************************************************************/ +XRMResOutputParser::~XRMResOutputParser() +/*****************************************************************************/ +{ + if ( pOutputStream ) { + pOutputStream->Close(); + delete pOutputStream; + } +} + +// +// class XMLResExport +// + +/*****************************************************************************/ +XRMResExport::XRMResExport( + const ByteString &rOutputFile, const ByteString &rProject, + const ByteString &rFilePath ) +/*****************************************************************************/ + : XRMResOutputParser( rOutputFile ), + pResData( NULL ), + sPrj( rProject ), + sPath( rFilePath ) +{ + aLanguages = Export::GetLanguages(); +} + +/*****************************************************************************/ +XRMResExport::~XRMResExport() +/*****************************************************************************/ +{ + delete pResData; +} + +void XRMResExport::Output( const ByteString& rOutput ) +{ + // Dummy to suppress warnings caused by poor class design + (void) rOutput; +} + +/*****************************************************************************/ +void XRMResExport::WorkOnText( + const ByteString &rOpenTag, + ByteString &rText +) +/*****************************************************************************/ +{ + ByteString sLang( GetAttribute( rOpenTag, "xml:lang" )); + + if ( !pResData ) { + ByteString sPlatform( "" ); + pResData = new ResData( sPlatform, GetGID() ); + pResData->sId = GetLID(); + } + + pResData->sText[ sLang ] = rText; + ConvertStringToDBFormat( pResData->sText[ sLang ] ); +} + +/*****************************************************************************/ +void XRMResExport::EndOfText( + const ByteString &rOpenTag, + const ByteString &rCloseTag +) +/*****************************************************************************/ +{ + + (void) rOpenTag; // FIXME + (void) rCloseTag; // FIXME + + if ( pResData && pOutputStream ) { + + char cSearch = 0x00; + ByteString sSearch( cSearch ); + + // if ( !pResData->sText[ ByteString("en-US") ].Len() ) + // pResData->sText[ ByteString("en-US") ] = pResData->sText[ ByteString("de") ]; + + Export::FillInFallbacks( pResData ); + + ByteString sTimeStamp( Export::GetTimeStamp()); + ByteString sCur; + for( unsigned int n = 0; n < aLanguages.size(); n++ ){ + sCur = aLanguages[ n ]; + + ByteString sAct = pResData->sText[ sCur ]; + //Export::UnquotHTML( sAct ); + sAct.EraseAllChars( 0x0A ); + + ByteString sOutput( sPrj ); sOutput += "\t"; + sOutput += sPath; + sOutput += "\t0\t"; + sOutput += "readmeitem\t"; + sOutput += pResData->sId; + // USE LID AS GID OR MERGE DON'T WORK + //sOutput += pResData->sGId; + sOutput += "\t"; + sOutput += pResData->sId; + sOutput += "\t\t\t0\t"; + sOutput += sCur; + sOutput += "\t"; + + sOutput += sAct; sOutput += "\t\t\t\t"; + sOutput += sTimeStamp; + + sOutput.SearchAndReplaceAll( sSearch, "_" ); + //if( !sCur.EqualsIgnoreCaseAscii("de") ||( sCur.EqualsIgnoreCaseAscii("de") && !Export::isMergingGermanAllowed( sPrj ) ) ) + if( sAct.Len() > 1 ) + pOutputStream->WriteLine( sOutput ); + } + } + delete pResData; + pResData = NULL; +} + +// +// class XRMResMerge +// + +/*****************************************************************************/ +XRMResMerge::XRMResMerge( + const ByteString &rMergeSource, const ByteString &rOutputFile, + ByteString &rFilename) +/*****************************************************************************/ + : XRMResOutputParser( rOutputFile ), + pMergeDataFile( NULL ), + sFilename( rFilename ) , + pResData( NULL ) +{ + if ( rMergeSource.Len()) + pMergeDataFile = new MergeDataFile( + rMergeSource, sInputFileName , bErrorLog, RTL_TEXTENCODING_MS_1252);//, bUTF8 ); + if( Export::sLanguages.EqualsIgnoreCaseAscii("ALL") ){ + Export::SetLanguages( pMergeDataFile->GetLanguages() ); + aLanguages = pMergeDataFile->GetLanguages(); + } + else aLanguages = Export::GetLanguages(); +} + +/*****************************************************************************/ +XRMResMerge::~XRMResMerge() +/*****************************************************************************/ +{ + delete pMergeDataFile; + delete pResData; +} + +/*****************************************************************************/ +void XRMResMerge::WorkOnText( + const ByteString &rOpenTag, + ByteString &rText +) +/*****************************************************************************/ +{ + ByteString sLang( GetAttribute( rOpenTag, "xml:lang" )); + + if ( pMergeDataFile ) { + if ( !pResData ) { + ByteString sPlatform( "" ); +// pResData = new ResData( sPlatform, GetGID() , sFilename ); + pResData = new ResData( sPlatform, GetLID() , sFilename ); + pResData->sId = GetLID(); + + pResData->sResTyp = "readmeitem"; + } + + PFormEntrys *pEntrys = pMergeDataFile->GetPFormEntrys( pResData ); + if ( pEntrys ) { + ByteString sContent; + if ( Export::isAllowed( sLang ) && + ( pEntrys->GetText( + sContent, STRING_TYP_TEXT, sLang )) && + ( sContent != "-" ) && ( sContent.Len())) + + { + rText = sContent; + ConvertStringToXMLFormat( rText ); + //Export::QuotHTMLXRM( rText ); + } + } + } +} + +/*****************************************************************************/ +void XRMResMerge::Output( const ByteString& rOutput ) +/*****************************************************************************/ +{ + //printf("W: %s\n",rOutput.GetBuffer()); + if ( pOutputStream && rOutput.Len() > 0 ) + pOutputStream->Write( rOutput.GetBuffer(), rOutput.Len()); +} + +/*****************************************************************************/ +void XRMResMerge::EndOfText( + const ByteString &rOpenTag, + const ByteString &rCloseTag +) +/*****************************************************************************/ +{ + + Output( rCloseTag ); + if ( pMergeDataFile && pResData ) { + PFormEntrys *pEntrys = pMergeDataFile->GetPFormEntrys( pResData ); + if ( pEntrys ) { + ByteString sCur; + for( unsigned int n = 0; n < aLanguages.size(); n++ ){ + sCur = aLanguages[ n ]; + ByteString sContent; + if ( !sCur.EqualsIgnoreCaseAscii("en-US") && + ( pEntrys->GetText( + sContent, STRING_TYP_TEXT, sCur, TRUE )) && + ( sContent != "-" ) && ( sContent.Len())) + { + ByteString sText( sContent ); + //Export::QuotHTMLXRM( sText ); + + ByteString sAdditionalLine( "\t" ); + sAdditionalLine += rOpenTag; + ByteString sSearch = "xml:lang=\""; + ByteString sReplace( sSearch ); + + sSearch += GetAttribute( rOpenTag, "xml:lang" ); + sReplace += sCur; + + sAdditionalLine.SearchAndReplace( sSearch, sReplace ); + + sAdditionalLine += sText; + sAdditionalLine += rCloseTag; + sAdditionalLine += "\n"; + + for ( USHORT i = 0; i + 1 < GetGID().GetTokenCount( '.' ); i++ ) + sAdditionalLine += "\t"; + + Output( sAdditionalLine ); + } + } + } + } + delete pResData; + pResData = NULL; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |