summaryrefslogtreecommitdiff
path: root/l10ntools/source/po.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'l10ntools/source/po.cxx')
-rw-r--r--l10ntools/source/po.cxx869
1 files changed, 869 insertions, 0 deletions
diff --git a/l10ntools/source/po.cxx b/l10ntools/source/po.cxx
new file mode 100644
index 000000000000..1be60ecaf312
--- /dev/null
+++ b/l10ntools/source/po.cxx
@@ -0,0 +1,869 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <rtl/ustring.hxx>
+
+#include <cstring>
+#include <ctime>
+#include <cassert>
+
+#include <vector>
+#include <string>
+
+#include <boost/crc.hpp>
+#include <unicode/regex.h>
+
+#include "po.hxx"
+
+#define POESCAPED OString("\\n\\t\\r\\\\\\\"")
+#define POUNESCAPED OString("\n\t\r\\\"")
+
+using namespace U_ICU_NAMESPACE;
+
+//Class GenPoEntry
+
+class GenPoEntry
+{
+private:
+
+ OString m_sExtractCom;
+ OString m_sReference;
+ OString m_sMsgCtxt;
+ OString m_sMsgId;
+ OString m_sMsgStr;
+ bool m_bFuzzy;
+ bool m_bNull;
+
+public:
+
+ GenPoEntry();
+ virtual ~GenPoEntry();
+ //Default copy constructor and copy operator work well
+
+ virtual OString getExtractCom() const { return m_sExtractCom; }
+ virtual OString getReference() const { return m_sReference; }
+ virtual OString getMsgCtxt() const { return m_sMsgCtxt; }
+ virtual OString getMsgId() const { return m_sMsgId; }
+ virtual OString getMsgStr() const { return m_sMsgStr; }
+ virtual bool isFuzzy() const { return m_bFuzzy; }
+ virtual bool isNull() const { return m_bNull; }
+
+ virtual void setExtractCom(const OString& rExtractCom);
+ virtual void setReference(const OString& rReference);
+ virtual void setMsgCtxt(const OString& rMsgCtxt);
+ virtual void setMsgId(const OString& rMsgId);
+ virtual void setMsgStr(const OString& rMsgStr);
+ virtual void setFuzzy(const bool bFuzzy);
+
+ virtual void writeToFile(std::ofstream& rOFStream) const;
+ virtual void readFromFile(std::ifstream& rIFStream);
+};
+
+namespace
+{
+ //Escape text
+ static OString lcl_EscapeText(const OString& rText,
+ const OString& rUnEscaped= POUNESCAPED,
+ const OString& rEscaped = POESCAPED)
+ {
+ assert( rEscaped.getLength() == 2*rUnEscaped.getLength() );
+ OString sResult = rText;
+ int nCount = 0;
+ for(sal_Int32 nIndex=0; nIndex<rText.getLength(); ++nIndex)
+ {
+ sal_Int32 nActChar = rUnEscaped.indexOf(rText[nIndex]);
+ if(nActChar!=-1)
+ sResult = sResult.replaceAt((nIndex)+(nCount++),1,
+ rEscaped.copy(2*nActChar,2));
+ }
+ return sResult;
+ }
+
+ //Unescape text
+ static OString lcl_UnEscapeText(const OString& rText,
+ const OString& rEscaped = POESCAPED,
+ const OString& rUnEscaped = POUNESCAPED)
+ {
+ assert( rEscaped.getLength() == 2*rUnEscaped.getLength() );
+ OString sResult = rText;
+ int nCount = 0;
+ for(sal_Int32 nIndex=0; nIndex<rText.getLength()-1; ++nIndex)
+ {
+ sal_Int32 nActChar = rEscaped.indexOf(rText.copy(nIndex,2));
+ if(nActChar % 2 == 0)
+ sResult = sResult.replaceAt((nIndex++)-(nCount++),2,
+ rUnEscaped.copy(nActChar/2,1));
+ }
+ return sResult;
+ }
+
+ //Convert a normal string to msg/po output string
+ static OString lcl_GenMsgString(const OString& rString)
+ {
+ if ( rString.isEmpty() )
+ return "\"\"";
+
+ OString sResult = "\"" + lcl_EscapeText(rString) + "\"";
+ sal_Int32 nIndex = 0;
+ while((nIndex=sResult.indexOf("\\n",nIndex))!=-1)
+ {
+ if( sResult.copy(nIndex-1,3)!="\\\\n" &&
+ nIndex!=sResult.getLength()-3)
+ {
+ sResult = sResult.replaceAt(nIndex,2,"\\n\"\n\"");
+ }
+ ++nIndex;
+ }
+
+ if ( sResult.indexOf('\n') != -1 )
+ return "\"\"\n" + sResult;
+
+ return sResult;
+ }
+
+ //Convert msg string to normal form
+ static OString lcl_GenNormString(const OString& rString)
+ {
+ return lcl_UnEscapeText(rString.copy(1,rString.getLength()-2));
+ }
+}
+
+//Default constructor
+GenPoEntry::GenPoEntry()
+ : m_sExtractCom( OString() )
+ , m_sReference( OString() )
+ , m_sMsgCtxt( OString() )
+ , m_sMsgId( OString() )
+ , m_sMsgStr( OString() )
+ , m_bFuzzy( false )
+ , m_bNull( false )
+{
+}
+
+//Destructor
+GenPoEntry::~GenPoEntry()
+{
+}
+
+//Set class members
+void GenPoEntry::setExtractCom(const OString& rExtractCom)
+{
+ m_sExtractCom = rExtractCom;
+}
+
+void GenPoEntry::setReference(const OString& rReference)
+{
+ m_sReference = rReference;
+}
+
+void GenPoEntry::setMsgCtxt(const OString& rMsgCtxt)
+{
+ m_sMsgCtxt = rMsgCtxt;
+}
+
+void GenPoEntry::setMsgId(const OString& rMsgId)
+{
+ m_sMsgId = rMsgId;
+}
+
+void GenPoEntry::setMsgStr(const OString& rMsgStr)
+{
+ m_sMsgStr = rMsgStr;
+}
+
+void GenPoEntry::setFuzzy(const bool bFuzzy)
+{
+ m_bFuzzy = bFuzzy;
+}
+
+//Write to file
+void GenPoEntry::writeToFile(std::ofstream& rOFStream) const
+{
+ if ( rOFStream.tellp() != 0 )
+ rOFStream << std::endl;
+ if ( !m_sExtractCom.isEmpty() )
+ rOFStream
+ << "#. "
+ << m_sExtractCom.replaceAll("\n","\n#. ").getStr() << std::endl;
+ if ( !m_sReference.isEmpty() )
+ rOFStream << "#: " << m_sReference.getStr() << std::endl;
+ if ( m_bFuzzy )
+ rOFStream << "#, fuzzy" << std::endl;
+ if ( !m_sMsgCtxt.isEmpty() )
+ rOFStream << "msgctxt "
+ << lcl_GenMsgString(m_sReference+"\n"+m_sMsgCtxt).getStr()
+ << std::endl;
+ rOFStream << "msgid "
+ << lcl_GenMsgString(m_sMsgId).getStr() << std::endl;
+ rOFStream << "msgstr "
+ << lcl_GenMsgString(m_sMsgStr).getStr() << std::endl;
+}
+
+//Read from file
+void GenPoEntry::readFromFile(std::ifstream& rIFStream)
+{
+ *this = GenPoEntry();
+ if( rIFStream.eof() )
+ {
+ m_bNull = true;
+ return;
+ }
+ OString* pLastMsg = 0;
+ std::string sTemp;
+ getline(rIFStream,sTemp);
+ while(!rIFStream.eof())
+ {
+ OString sLine = OString(sTemp.data(),sTemp.length());
+ if (sLine.startsWith("#. "))
+ {
+ if( !m_sExtractCom.isEmpty() )
+ {
+ m_sExtractCom += "\n";
+ }
+ m_sExtractCom += sLine.copy(3);
+ }
+ else if (sLine.startsWith("#: "))
+ {
+ m_sReference = sLine.copy(3);
+ }
+ else if (sLine.startsWith("#, fuzzy"))
+ {
+ m_bFuzzy = true;
+ }
+ else if (sLine.startsWith("msgctxt "))
+ {
+ m_sMsgCtxt = lcl_GenNormString(sLine.copy(8));
+ pLastMsg = &m_sMsgCtxt;
+ }
+ else if (sLine.startsWith("msgid "))
+ {
+ m_sMsgId = lcl_GenNormString(sLine.copy(6));
+ pLastMsg = &m_sMsgId;
+ }
+ else if (sLine.startsWith("msgstr "))
+ {
+ m_sMsgStr = lcl_GenNormString(sLine.copy(7));
+ pLastMsg = &m_sMsgStr;
+ }
+ else if (sLine.startsWith("\"") && pLastMsg)
+ {
+ if (pLastMsg != &m_sMsgCtxt || sLine != "\"" + m_sReference + "\\n\"")
+ {
+ *pLastMsg += lcl_GenNormString(sLine);
+ }
+ }
+ else
+ break;
+ getline(rIFStream,sTemp);
+ }
+ }
+
+//Class PoEntry
+
+namespace
+{
+ //Generate KeyId
+ static OString lcl_GenKeyId(const OString& rGenerator)
+ {
+ boost::crc_32_type aCRC32;
+ aCRC32.process_bytes(rGenerator.getStr(), rGenerator.getLength());
+ sal_uInt32 nCRC = aCRC32.checksum();
+ //Use all readable ASCII charachter exclude xml special tags: ",',&,<,>
+ const OString sSymbols = "!#$%()*+,-./0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
+ char sKeyId[5];
+ for( short nKeyInd = 0; nKeyInd < 4; ++nKeyInd )
+ {
+ sKeyId[nKeyInd] = sSymbols[(nCRC & 255) % 89];
+ nCRC >>= 8;
+ }
+ sKeyId[4] = '\0';
+ return OString(sKeyId);
+ }
+
+ //Split string at the delimiter char
+ static void lcl_SplitAt(const OString& rSource, const sal_Char nDelimiter,
+ std::vector<OString>& o_vParts)
+ {
+ o_vParts.resize( 0 );
+ sal_Int32 nActIndex = 0;
+ sal_Int32 nLastSplit = 0;
+ while( nActIndex < rSource.getLength() )
+ {
+ if ( rSource[nActIndex] == nDelimiter )
+ {
+ o_vParts.push_back(
+ rSource.copy(nLastSplit,nActIndex-nLastSplit));
+ nLastSplit = nActIndex+1;
+ }
+ ++nActIndex;
+ }
+ o_vParts.push_back(rSource.copy(nLastSplit));
+ }
+
+ //Unescape sdf string
+ static OString lcl_UnEscapeSDFText(
+ const OString& rText,const bool bHelpText = false )
+ {
+ if ( bHelpText )
+ return lcl_UnEscapeText(rText,"\\<\\>\\\"\\\\","<>\"\\");
+ else
+ return lcl_UnEscapeText(rText,"\\n\\t\\r","\n\t\r");
+ }
+
+ //Find all special tag in a string using a regular expression
+ static void lcl_FindAllTag(
+ const OString& rText,std::vector<OString>& o_vFoundTags )
+ {
+
+ UErrorCode nIcuErr = U_ZERO_ERROR;
+ sal_uInt32 nSearchFlags = UREGEX_DOTALL | UREGEX_CASE_INSENSITIVE;
+ OUString sLocaleText( OStringToOUString(rText,RTL_TEXTENCODING_UTF8) );
+ OUString sPattern( "<[/]??[a-z_-]+?(?:| +[a-z]+?=\".*?\") *[/]??>" );
+ UnicodeString sSearchPat(
+ reinterpret_cast<const UChar*>(
+ sPattern.getStr()), sPattern.getLength() );
+ UnicodeString sSource(
+ reinterpret_cast<const UChar*>(
+ sLocaleText.getStr()), sLocaleText.getLength() );
+
+ RegexMatcher aRegexMatcher( sSearchPat, nSearchFlags, nIcuErr );
+ aRegexMatcher.reset( sSource );
+ int64_t nStartPos = 0;
+ while( aRegexMatcher.find(nStartPos, nIcuErr) &&
+ nIcuErr == U_ZERO_ERROR )
+ {
+ UnicodeString sMatch =
+ aRegexMatcher.group(nIcuErr);
+ o_vFoundTags.push_back(
+ OUStringToOString(
+ OUString(
+ reinterpret_cast<const sal_Unicode*>(
+ sMatch.getBuffer()),sMatch.length()),
+ RTL_TEXTENCODING_UTF8));
+ nStartPos = aRegexMatcher.start(nIcuErr)+1;
+ }
+ }
+
+ //Escape special tags
+ static OString lcl_EscapeTags( const OString& rText )
+ {
+ typedef std::vector<OString> StrVec_t;
+ const OString vInitializer[] = {
+ "ahelp", "link", "item", "emph", "defaultinline",
+ "switchinline", "caseinline", "variable",
+ "bookmark_value", "image", "embedvar", "alt" };
+ const StrVec_t vTagsForEscape( vInitializer,
+ vInitializer + sizeof(vInitializer) / sizeof(vInitializer[0]) );
+ StrVec_t vFoundTags;
+ lcl_FindAllTag(rText,vFoundTags);
+ OString sResult = rText;
+ for(StrVec_t::const_iterator pFound = vFoundTags.begin();
+ pFound != vFoundTags.end(); ++pFound)
+ {
+ bool bEscapeThis = false;
+ for(StrVec_t::const_iterator pEscape = vTagsForEscape.begin();
+ pEscape != vTagsForEscape.end(); ++pEscape)
+ {
+ if (pFound->startsWith("<" + *pEscape) ||
+ *pFound == "</" + *pEscape + ">")
+ {
+ bEscapeThis = true;
+ break;
+ }
+ }
+ if( bEscapeThis || *pFound=="<br/>" ||
+ *pFound =="<help-id-missing/>")
+ {
+ OString sToReplace = "\\<" +
+ pFound->copy(1,pFound->getLength()-2).
+ replaceAll("\"","\\\"") + "\\>";
+ sResult = sResult.replaceAll(*pFound, sToReplace);
+ }
+ }
+ return sResult;
+ }
+
+ //Escape to get sdf/merge string
+ static OString lcl_EscapeSDFText(
+ const OString& rText,const bool bHelpText = false )
+ {
+ if ( bHelpText )
+ return lcl_EscapeTags(rText.replaceAll("\\","\\\\"));
+ else
+ return lcl_EscapeText(rText,"\n\t\r","\\n\\t\\r");
+ }
+}
+
+//Default constructor
+PoEntry::PoEntry()
+ : m_pGenPo( 0 )
+ , m_bIsInitialized( false )
+{
+}
+
+//Construct PoEntry from sdfline
+PoEntry::PoEntry(const OString& rSDFLine, const TYPE eType)
+ : m_pGenPo( 0 )
+ , m_bIsInitialized( false )
+{
+ std::vector<OString> vParts;
+ lcl_SplitAt(rSDFLine,'\t',vParts);
+ if( vParts.size()!=15 ||
+ vParts[SOURCEFILE].isEmpty() ||
+ vParts[GROUPID].isEmpty() ||
+ vParts[RESOURCETYPE].isEmpty() ||
+ vParts[eType].isEmpty() ||
+ vParts[HELPTEXT].getLength() == 4 )
+ {
+ throw INVALIDSDFLINE;
+ }
+
+ m_pGenPo = new GenPoEntry();
+ m_pGenPo->setReference(vParts[SOURCEFILE].
+ copy(vParts[SOURCEFILE].lastIndexOf("\\")+1));
+
+ OString sMsgCtxt =
+ vParts[GROUPID] + "\n" +
+ (vParts[LOCALID].isEmpty() ? "" : vParts[LOCALID] + "\n") +
+ vParts[RESOURCETYPE];
+ switch(eType){
+ case TTEXT:
+ sMsgCtxt += ".text"; break;
+ case TQUICKHELPTEXT:
+ sMsgCtxt += ".quickhelptext"; break;
+ case TTITLE:
+ sMsgCtxt += ".title"; break;
+ /*Default case is unneeded because the type of eType has
+ only three element*/
+ }
+ m_pGenPo->setExtractCom(
+ ( !vParts[HELPTEXT].isEmpty() ? vParts[HELPTEXT] + "\n" : "" ) +
+ lcl_GenKeyId(
+ vParts[SOURCEFILE] + sMsgCtxt + vParts[eType] ) );
+ m_pGenPo->setMsgCtxt(sMsgCtxt);
+ m_pGenPo->setMsgId(
+ lcl_UnEscapeSDFText(
+ vParts[eType],vParts[SOURCEFILE].endsWith(".xhp")));
+ m_bIsInitialized = true;
+}
+
+//Destructor
+PoEntry::~PoEntry()
+{
+ delete m_pGenPo;
+}
+
+//Copy constructor
+PoEntry::PoEntry( const PoEntry& rPo )
+ : m_pGenPo( rPo.m_pGenPo ? new GenPoEntry( *(rPo.m_pGenPo) ) : 0 )
+ , m_bIsInitialized( rPo.m_bIsInitialized )
+{
+}
+
+//Copy operator
+PoEntry& PoEntry::operator=(const PoEntry& rPo)
+{
+ if( this == &rPo )
+ {
+ return *this;
+ }
+ if( rPo.m_pGenPo )
+ {
+ if( m_pGenPo )
+ {
+ *m_pGenPo = *(rPo.m_pGenPo);
+ }
+ else
+ {
+ m_pGenPo = new GenPoEntry( *(rPo.m_pGenPo) );
+ }
+ }
+ else
+ {
+ delete m_pGenPo;
+ m_pGenPo = 0;
+ }
+ m_bIsInitialized = rPo.m_bIsInitialized;
+ return *this;
+}
+
+//Get name of file from which entry is extracted
+OString PoEntry::getSourceFile() const
+{
+ assert( m_bIsInitialized );
+ return m_pGenPo->getReference();
+}
+
+//Get groupid
+OString PoEntry::getGroupId() const
+{
+ assert( m_bIsInitialized );
+ return m_pGenPo->getMsgCtxt().getToken(0,'\n');
+}
+
+//Get localid
+OString PoEntry::getLocalId() const
+{
+ assert( m_bIsInitialized );
+ const OString sMsgCtxt = m_pGenPo->getMsgCtxt();
+ if (sMsgCtxt.indexOf('\n')==sMsgCtxt.lastIndexOf('\n'))
+ return OString();
+ else
+ return sMsgCtxt.getToken(1,'\n');
+}
+
+//Get the type of component from which entry is extracted
+OString PoEntry::getResourceType() const
+{
+ assert( m_bIsInitialized );
+ const OString sMsgCtxt = m_pGenPo->getMsgCtxt();
+ if (sMsgCtxt.indexOf('\n')==sMsgCtxt.lastIndexOf('\n'))
+ return sMsgCtxt.getToken(1,'\n').getToken(0,'.');
+ else
+ return sMsgCtxt.getToken(2,'\n').getToken(0,'.');
+}
+
+//Get the type of entry
+PoEntry::TYPE PoEntry::getType() const
+{
+ assert( m_bIsInitialized );
+ const OString sMsgCtxt = m_pGenPo->getMsgCtxt();
+ const OString sType = sMsgCtxt.copy( sMsgCtxt.lastIndexOf('.') + 1 );
+ assert(
+ (sType == "text" || sType == "quickhelptext" || sType == "title") );
+ if ( sType == "text" )
+ return TTEXT;
+ else if ( sType == "quickhelptext" )
+ return TQUICKHELPTEXT;
+ else
+ return TTITLE;
+}
+
+//Check wheather entry is fuzzy
+bool PoEntry::isFuzzy() const
+{
+ assert( m_bIsInitialized );
+ return m_pGenPo->isFuzzy();
+}
+
+//Get keyid
+OString PoEntry::getKeyId() const
+{
+ assert( m_bIsInitialized );
+ const OString sExtractCom = m_pGenPo->getExtractCom();
+ if( sExtractCom.indexOf("\n") == -1 )
+ {
+ return sExtractCom;
+ }
+ else
+ {
+ return sExtractCom.getToken(1,'\n');
+ }
+}
+
+
+//Get translation string in sdf/merge format
+OString PoEntry::getMsgId() const
+{
+ assert( m_bIsInitialized );
+ return
+ lcl_EscapeSDFText(
+ m_pGenPo->getMsgId(), getSourceFile().endsWith(".xhp") );
+}
+
+//Get translated string in sdf/merge format
+OString PoEntry::getMsgStr() const
+{
+ assert( m_bIsInitialized );
+ return
+ lcl_EscapeSDFText(
+ m_pGenPo->getMsgStr(), getSourceFile().endsWith(".xhp") );
+
+}
+
+//Set translated string when input is in sdf format
+void PoEntry::setMsgStr(const OString& rMsgStr)
+{
+ assert( m_bIsInitialized );
+ m_pGenPo->setMsgStr(
+ lcl_UnEscapeSDFText(
+ rMsgStr,getSourceFile().endsWith(".xhp")));
+}
+
+//Set fuzzy flag
+void PoEntry::setFuzzy(const bool bFuzzy)
+{
+ assert( m_bIsInitialized );
+ m_pGenPo->setFuzzy(bFuzzy);
+}
+
+//Check whether po-s belong to the same localization component
+bool PoEntry::IsInSameComp(const PoEntry& rPo1,const PoEntry& rPo2)
+{
+ assert( rPo1.m_bIsInitialized && rPo2.m_bIsInitialized );
+ return ( rPo1.getSourceFile() == rPo2.getSourceFile() &&
+ rPo1.getGroupId() == rPo2.getGroupId() &&
+ rPo1.getLocalId() == rPo2.getLocalId() &&
+ rPo1.getResourceType() == rPo2.getResourceType() );
+}
+
+//Class PoHeader
+
+namespace
+{
+ //Get actual time in "YEAR-MO-DA HO:MI+ZONE" form
+ static OString lcl_GetTime()
+ {
+ time_t aNow = time(NULL);
+ struct tm* pNow = localtime(&aNow);
+ char pBuff[50];
+ strftime( pBuff, sizeof pBuff, "%Y-%m-%d %H:%M%z", pNow );
+ return pBuff;
+ }
+
+ static OString lcl_ReplaceAttribute(
+ const OString& rSource, const OString& rOld, const OString& rNew )
+ {
+ const sal_Int32 nFirstIndex =
+ rSource.indexOf( rOld ) + rOld.getLength()+2;
+ const sal_Int32 nCount =
+ rSource.indexOf( "\n", nFirstIndex ) - nFirstIndex;
+ return rSource.replaceFirst( rSource.copy(nFirstIndex, nCount), rNew );
+ }
+}
+
+//Default Constructor
+PoHeader::PoHeader()
+ : m_pGenPo( 0 )
+ , m_bIsInitialized( false )
+{
+}
+
+//Template Constructor
+PoHeader::PoHeader( const OString& rExtSrc )
+ : m_pGenPo( new GenPoEntry() )
+ , m_bIsInitialized( false )
+{
+ m_pGenPo->setExtractCom("extracted from " + rExtSrc);
+ m_pGenPo->setMsgStr(
+ OString("Project-Id-Version: PACKAGE VERSION\n"
+ "Report-Msgid-Bugs-To: https://bugs.freedesktop.org/enter_bug.cgi?"
+ "product=LibreOffice&bug_status=UNCONFIRMED&component=UI\n"
+ "POT-Creation-Date: ") + lcl_GetTime() +
+ OString("\nPO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+ "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+ "Language-Team: LANGUAGE <LL@li.org>\n"
+ "MIME-Version: 1.0\n"
+ "Content-Type: text/plain; charset=UTF-8\n"
+ "Content-Transfer-Encoding: 8bit\n"
+ "X-Generator: LibreOffice\n"
+ "X-Accelerator-Marker: ~\n"));
+ m_bIsInitialized = true;
+}
+
+
+//Constructor for old headers to renew po files
+PoHeader::PoHeader( std::ifstream& rOldPo )
+ : m_pGenPo( new GenPoEntry() )
+ , m_bIsInitialized( false )
+{
+ assert( rOldPo.is_open() );
+ m_pGenPo->readFromFile( rOldPo );
+
+ const OString sExtractCom = m_pGenPo->getExtractCom();
+ m_pGenPo->setExtractCom(
+ sExtractCom.copy( 0, sExtractCom.getLength() - 3 ) );
+
+ OString sMsgStr = m_pGenPo->getMsgStr();
+ sMsgStr =
+ lcl_ReplaceAttribute( sMsgStr, "Report-Msgid-Bugs-To",
+ "https://bugs.freedesktop.org/enter_bug.cgi?product="
+ "LibreOffice&bug_status=UNCONFIRMED&component=UI" );
+ sMsgStr =
+ lcl_ReplaceAttribute( sMsgStr, "X-Generator", "LibreOffice" );
+ sMsgStr =
+ lcl_ReplaceAttribute( sMsgStr, "X-Accelerator-Marker", "~" );
+ m_pGenPo->setMsgStr( sMsgStr );
+ m_bIsInitialized = true;
+}
+
+PoHeader::~PoHeader()
+{
+ delete m_pGenPo;
+}
+
+//Get the language of header
+OString PoHeader::getLanguage() const
+{
+ assert( m_bIsInitialized );
+ const OString sLang = "Language: ";
+ const OString sMsgStr = m_pGenPo->getMsgStr();
+ const sal_Int32 nFirstIndex = sMsgStr.indexOf(sLang)+sLang.getLength();
+ const sal_Int32 nCount = sMsgStr.indexOf('\n',nFirstIndex)-nFirstIndex;
+ if( nFirstIndex == sLang.getLength()-1 || nCount == -nFirstIndex-1 )
+ {
+ throw NOLANG;
+ }
+ return sMsgStr.copy( nFirstIndex, nCount );
+}
+
+//Class PoOfstream
+
+PoOfstream::PoOfstream()
+ : m_aOutPut()
+ , m_bIsAfterHeader( false )
+{
+}
+
+PoOfstream::~PoOfstream()
+{
+ if( isOpen() )
+ {
+ close();
+ }
+}
+
+void PoOfstream::open(const OString& rFileName)
+{
+ assert( !isOpen() );
+ m_aOutPut.open( rFileName.getStr(),
+ std::ios_base::out | std::ios_base::trunc );
+ m_bIsAfterHeader = false;
+}
+
+void PoOfstream::close()
+{
+ assert( isOpen() );
+ m_aOutPut.close();
+}
+
+void PoOfstream::writeHeader(const PoHeader& rPoHeader)
+{
+ assert( isOpen() && !m_bIsAfterHeader && rPoHeader.m_bIsInitialized );
+ rPoHeader.m_pGenPo->writeToFile( m_aOutPut );
+ m_bIsAfterHeader = true;
+}
+
+void PoOfstream::writeEntry( const PoEntry& rPoEntry )
+{
+ assert( isOpen() && m_bIsAfterHeader && rPoEntry.m_bIsInitialized );
+ rPoEntry.m_pGenPo->writeToFile( m_aOutPut );
+}
+
+//Class PoIfstream
+
+PoIfstream::PoIfstream()
+ : m_aInPut()
+ , m_bIsAfterHeader( false )
+ , m_bEof( false )
+{
+}
+
+PoIfstream::~PoIfstream()
+{
+ if( isOpen() )
+ {
+ close();
+ }
+}
+
+void PoIfstream::open( const OString& rFileName )
+{
+ assert( !isOpen() );
+ m_aInPut.open( rFileName.getStr(), std::ios_base::in );
+ m_bIsAfterHeader = false;
+ m_bEof = false;
+}
+
+void PoIfstream::close()
+{
+ assert( isOpen() );
+ m_aInPut.close();
+}
+
+void PoIfstream::readHeader( PoHeader& rPoHeader )
+{
+ assert( isOpen() && !eof() && !m_bIsAfterHeader );
+ GenPoEntry aGenPo;
+ aGenPo.readFromFile( m_aInPut );
+ if( !aGenPo.getExtractCom().isEmpty() &&
+ aGenPo.getMsgId().isEmpty() &&
+ !aGenPo.getMsgStr().isEmpty() )
+ {
+ if( rPoHeader.m_pGenPo )
+ {
+ *(rPoHeader.m_pGenPo) = aGenPo;
+ }
+ else
+ {
+ rPoHeader.m_pGenPo = new GenPoEntry( aGenPo );
+ }
+ rPoHeader.m_bIsInitialized = true;
+ m_bIsAfterHeader = true;
+ }
+ else
+ {
+ throw INVALIDHEADER;
+ }
+}
+
+void PoIfstream::readEntry( PoEntry& rPoEntry )
+{
+ assert( isOpen() && !eof() && m_bIsAfterHeader );
+ GenPoEntry aGenPo;
+ aGenPo.readFromFile( m_aInPut );
+ if( aGenPo.isNull() )
+ {
+ m_bEof = true;
+ rPoEntry = PoEntry();
+ }
+ else
+ {
+ const OString sMsgCtxt = aGenPo.getMsgCtxt();
+ const sal_Int32 nFirstEndLine = sMsgCtxt.indexOf('\n');
+ const sal_Int32 nLastEndLine = sMsgCtxt.lastIndexOf('\n');
+ const sal_Int32 nLastDot = sMsgCtxt.lastIndexOf('.');
+ const OString sType = sMsgCtxt.copy( nLastDot + 1 );
+ if( !aGenPo.getReference().isEmpty() &&
+ nFirstEndLine > 0 &&
+ (nLastEndLine == nFirstEndLine ||
+ nLastEndLine == sMsgCtxt.indexOf('\n',nFirstEndLine+1)) &&
+ nLastDot - nLastEndLine > 1 &&
+ (sType == "text" || sType == "quickhelptext" || sType == "title")&&
+ !aGenPo.getMsgId().isEmpty() )
+ {
+ if( rPoEntry.m_pGenPo )
+ {
+ *(rPoEntry.m_pGenPo) = aGenPo;
+ }
+ else
+ {
+ rPoEntry.m_pGenPo = new GenPoEntry( aGenPo );
+ }
+ const OString sExtractCom = aGenPo.getExtractCom();
+ if( sExtractCom.isEmpty() ||
+ ( sExtractCom.getLength() != 4 &&
+ sExtractCom.indexOf("\n") == -1 ) )
+ {
+ aGenPo.setExtractCom(
+ ( !sExtractCom.isEmpty() ? sExtractCom + "\n" : "" ) +
+ lcl_GenKeyId(
+ aGenPo.getReference() + sMsgCtxt +
+ aGenPo.getMsgId() ) );
+ }
+ rPoEntry.m_bIsInitialized = true;
+ }
+ else
+ {
+ throw INVALIDENTRY;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */