LCOV - code coverage report
Current view: top level - libreoffice/l10ntools/source - po.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 376 0.0 %
Date: 2012-12-17 Functions: 0 64 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  */
       9             : 
      10             : #include <rtl/ustring.hxx>
      11             : 
      12             : #include <cstring>
      13             : #include <ctime>
      14             : #include <cassert>
      15             : 
      16             : #include <vector>
      17             : #include <string>
      18             : 
      19             : #include <boost/crc.hpp>
      20             : #include <unicode/regex.h>
      21             : 
      22             : #include "po.hxx"
      23             : 
      24             : #define POESCAPED OString("\\n\\t\\r\\\\\\\"")
      25             : #define POUNESCAPED OString("\n\t\r\\\"")
      26             : 
      27             : using namespace U_ICU_NAMESPACE;
      28             : 
      29             : /** Container of po entry
      30             : 
      31             :     Provide all file operations related to LibreOffice specific
      32             :     po entry and store it's attributes.
      33             : */
      34           0 : class GenPoEntry
      35             : {
      36             : private:
      37             : 
      38             :     OString    m_sExtractCom;
      39             :     OString    m_sReference;
      40             :     OString    m_sMsgCtxt;
      41             :     OString    m_sMsgId;
      42             :     OString    m_sMsgStr;
      43             :     bool       m_bFuzzy;
      44             :     bool       m_bNull;
      45             : 
      46             : public:
      47             : 
      48             :                         GenPoEntry();
      49             :     virtual             ~GenPoEntry();
      50             :                         //Default copy constructor and copy operator work well
      51             : 
      52           0 :     virtual OString     getExtractCom() const   { return m_sExtractCom; }
      53           0 :     virtual OString     getReference() const    { return m_sReference; }
      54           0 :     virtual OString     getMsgCtxt() const      { return m_sMsgCtxt; }
      55           0 :     virtual OString     getMsgId() const        { return m_sMsgId; }
      56           0 :     virtual OString     getMsgStr() const       { return m_sMsgStr; }
      57           0 :     virtual bool        isFuzzy() const         { return m_bFuzzy; }
      58           0 :     virtual bool        isNull() const          { return m_bNull; }
      59             : 
      60           0 :     virtual void        setExtractCom(const OString& rExtractCom)
      61             :                         {
      62           0 :                             m_sExtractCom = rExtractCom;
      63           0 :                         }
      64           0 :     virtual void        setReference(const OString& rReference)
      65             :                         {
      66           0 :                             m_sReference = rReference;
      67           0 :                         }
      68           0 :     virtual void        setMsgCtxt(const OString& rMsgCtxt)
      69             :                         {
      70           0 :                             m_sMsgCtxt = rMsgCtxt;
      71           0 :                         }
      72           0 :     virtual void        setMsgId(const OString& rMsgId)
      73             :                         {
      74           0 :                             m_sMsgId = rMsgId;
      75           0 :                         }
      76           0 :     virtual void        setMsgStr(const OString& rMsgStr)
      77             :                         {
      78           0 :                             m_sMsgStr = rMsgStr;
      79           0 :                         }
      80           0 :     virtual void        setFuzzy(const bool bFuzzy)
      81             :                         {
      82           0 :                             m_bFuzzy = bFuzzy;
      83           0 :                         }
      84             : 
      85             :     virtual void        writeToFile(std::ofstream& rOFStream) const;
      86             :     virtual void        readFromFile(std::ifstream& rIFStream);
      87             : };
      88             : 
      89             : namespace
      90             : {
      91             :     //Escape text
      92           0 :     static OString lcl_EscapeText(const OString& rText,
      93             :                            const OString& rUnEscaped= POUNESCAPED,
      94             :                            const OString& rEscaped = POESCAPED)
      95             :     {
      96             :         assert( rEscaped.getLength() == 2*rUnEscaped.getLength() );
      97           0 :         OString sResult = rText;
      98           0 :         int nCount = 0;
      99           0 :         for(sal_Int32 nIndex=0; nIndex<rText.getLength(); ++nIndex)
     100             :         {
     101           0 :             sal_Int32 nActChar = rUnEscaped.indexOf(rText[nIndex]);
     102           0 :             if(nActChar!=-1)
     103             :                 sResult = sResult.replaceAt((nIndex)+(nCount++),1,
     104           0 :                                             rEscaped.copy(2*nActChar,2));
     105             :         }
     106           0 :         return sResult;
     107             :     }
     108             : 
     109             :     //Unescape text
     110           0 :     static OString lcl_UnEscapeText(const OString& rText,
     111             :                              const OString& rEscaped = POESCAPED,
     112             :                              const OString& rUnEscaped = POUNESCAPED)
     113             :     {
     114             :         assert( rEscaped.getLength() == 2*rUnEscaped.getLength() );
     115           0 :         OString sResult = rText;
     116           0 :         int nCount = 0;
     117           0 :         for(sal_Int32 nIndex=0; nIndex<rText.getLength()-1; ++nIndex)
     118             :         {
     119           0 :             sal_Int32 nActChar = rEscaped.indexOf(rText.copy(nIndex,2));
     120           0 :             if(nActChar % 2 == 0)
     121             :                 sResult = sResult.replaceAt((nIndex++)-(nCount++),2,
     122           0 :                                             rUnEscaped.copy(nActChar/2,1));
     123             :         }
     124           0 :         return sResult;
     125             :     }
     126             : 
     127             :     //Convert a normal string to msg/po output string
     128           0 :     static OString lcl_GenMsgString(const OString& rString)
     129             :     {
     130           0 :         if ( rString.isEmpty() )
     131           0 :             return "\"\"";
     132             : 
     133           0 :         OString sResult = "\"" + lcl_EscapeText(rString) + "\"";
     134           0 :         sal_Int32 nIndex = 0;
     135           0 :         while((nIndex=sResult.indexOf("\\n",nIndex))!=-1)
     136             :         {
     137           0 :             if( sResult.copy(nIndex-1,3)!="\\\\n" &&
     138           0 :                 nIndex!=sResult.getLength()-3)
     139             :             {
     140           0 :                sResult = sResult.replaceAt(nIndex,2,"\\n\"\n\"");
     141             :             }
     142           0 :             ++nIndex;
     143             :         }
     144             : 
     145           0 :         if ( sResult.indexOf('\n') != -1 )
     146           0 :             return "\"\"\n" +  sResult;
     147             : 
     148           0 :         return sResult;
     149             :     }
     150             : 
     151             :     //Convert msg string to normal form
     152           0 :     static OString lcl_GenNormString(const OString& rString)
     153             :     {
     154           0 :         return lcl_UnEscapeText(rString.copy(1,rString.getLength()-2));
     155             :     }
     156             : }
     157             : 
     158             : //Default constructor
     159           0 : GenPoEntry::GenPoEntry()
     160             :     : m_sExtractCom( OString() )
     161             :     , m_sReference( OString() )
     162             :     , m_sMsgCtxt( OString() )
     163             :     , m_sMsgId( OString() )
     164             :     , m_sMsgStr( OString() )
     165             :     , m_bFuzzy( false )
     166           0 :     , m_bNull( false )
     167             : {
     168           0 : }
     169             : 
     170             : //Destructor
     171           0 : GenPoEntry::~GenPoEntry()
     172             : {
     173           0 : }
     174             : 
     175             : //Write to file
     176           0 : void GenPoEntry::writeToFile(std::ofstream& rOFStream) const
     177             : {
     178           0 :     if ( rOFStream.tellp() != std::ofstream::pos_type( 0 ))
     179           0 :         rOFStream << std::endl;
     180           0 :     if ( !m_sExtractCom.isEmpty() )
     181             :         rOFStream
     182           0 :             << "#. "
     183           0 :             << m_sExtractCom.replaceAll("\n","\n#. ").getStr() << std::endl;
     184           0 :     if ( !m_sReference.isEmpty() )
     185           0 :         rOFStream << "#: " << m_sReference.getStr() << std::endl;
     186           0 :     if ( m_bFuzzy )
     187           0 :         rOFStream << "#, fuzzy" << std::endl;
     188           0 :     if ( !m_sMsgCtxt.isEmpty() )
     189           0 :         rOFStream << "msgctxt "
     190           0 :                   << lcl_GenMsgString(m_sReference+"\n"+m_sMsgCtxt).getStr()
     191           0 :                   << std::endl;
     192           0 :     rOFStream << "msgid "
     193           0 :               << lcl_GenMsgString(m_sMsgId).getStr() << std::endl;
     194           0 :     rOFStream << "msgstr "
     195           0 :               << lcl_GenMsgString(m_sMsgStr).getStr() << std::endl;
     196           0 : }
     197             : 
     198             : //Read from file
     199           0 : void GenPoEntry::readFromFile(std::ifstream& rIFStream)
     200             : {
     201           0 :     *this = GenPoEntry();
     202           0 :     if( rIFStream.eof() )
     203             :     {
     204           0 :         m_bNull = true;
     205           0 :         return;
     206             :     }
     207           0 :     OString* pLastMsg = 0;
     208           0 :     std::string sTemp;
     209           0 :     getline(rIFStream,sTemp);
     210           0 :     while(!rIFStream.eof())
     211             :     {
     212           0 :         OString sLine = OString(sTemp.data(),sTemp.length());
     213           0 :         if (sLine.startsWith("#. "))
     214             :         {
     215           0 :             if( !m_sExtractCom.isEmpty() )
     216             :             {
     217           0 :                 m_sExtractCom += "\n";
     218             :             }
     219           0 :             m_sExtractCom += sLine.copy(3);
     220             :         }
     221           0 :         else if (sLine.startsWith("#: "))
     222             :         {
     223           0 :             m_sReference = sLine.copy(3);
     224             :         }
     225           0 :         else if (sLine.startsWith("#, fuzzy"))
     226             :         {
     227           0 :             m_bFuzzy = true;
     228             :         }
     229           0 :         else if (sLine.startsWith("msgctxt "))
     230             :         {
     231           0 :             m_sMsgCtxt = lcl_GenNormString(sLine.copy(8));
     232           0 :             pLastMsg = &m_sMsgCtxt;
     233             :         }
     234           0 :         else if (sLine.startsWith("msgid "))
     235             :         {
     236           0 :             m_sMsgId = lcl_GenNormString(sLine.copy(6));
     237           0 :             pLastMsg = &m_sMsgId;
     238             :         }
     239           0 :         else if (sLine.startsWith("msgstr "))
     240             :         {
     241           0 :             m_sMsgStr = lcl_GenNormString(sLine.copy(7));
     242           0 :             pLastMsg = &m_sMsgStr;
     243             :         }
     244           0 :         else if (sLine.startsWith("\"") && pLastMsg)
     245             :         {
     246           0 :             if (pLastMsg != &m_sMsgCtxt || sLine != "\"" + m_sReference + "\\n\"")
     247             :             {
     248           0 :                 *pLastMsg += lcl_GenNormString(sLine);
     249             :             }
     250             :         }
     251             :         else
     252             :             break;
     253           0 :         getline(rIFStream,sTemp);
     254           0 :     }
     255             :  }
     256             : 
     257             : //Class PoEntry
     258             : 
     259             : namespace
     260             : {
     261             :     //Generate KeyId
     262           0 :     static OString lcl_GenKeyId(const OString& rGenerator)
     263             :     {
     264           0 :         boost::crc_32_type aCRC32;
     265           0 :         aCRC32.process_bytes(rGenerator.getStr(), rGenerator.getLength());
     266           0 :         sal_uInt32 nCRC = aCRC32.checksum();
     267             :         //Use all readable ASCII character exclude xml special tags: ",',&,<,>
     268           0 :         const OString sSymbols = "!#$%()*+,-./0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
     269             :         char sKeyId[5];
     270           0 :         for( short nKeyInd = 0; nKeyInd < 4; ++nKeyInd )
     271             :         {
     272           0 :             sKeyId[nKeyInd] = sSymbols[(nCRC & 255) % 89];
     273           0 :             nCRC >>= 8;
     274             :         }
     275           0 :         sKeyId[4] = '\0';
     276           0 :         return OString(sKeyId);
     277             :     }
     278             : 
     279             :     //Split string at the delimiter character
     280           0 :     static void lcl_SplitAt(const OString& rSource, const sal_Char nDelimiter,
     281             :                      std::vector<OString>& o_vParts)
     282             :     {
     283           0 :         o_vParts.resize( 0 );
     284           0 :         sal_Int32 nActIndex = 0;
     285           0 :         sal_Int32 nLastSplit = 0;
     286           0 :         while( nActIndex < rSource.getLength() )
     287             :         {
     288           0 :             if ( rSource[nActIndex] == nDelimiter )
     289             :             {
     290             :                 o_vParts.push_back(
     291           0 :                     rSource.copy(nLastSplit,nActIndex-nLastSplit));
     292           0 :                 nLastSplit = nActIndex+1;
     293             :             }
     294           0 :             ++nActIndex;
     295             :         }
     296           0 :         o_vParts.push_back(rSource.copy(nLastSplit));
     297           0 :     }
     298             : 
     299             :     //Unescape sdf string
     300           0 :     static OString lcl_UnEscapeSDFText(
     301             :         const OString& rText,const bool bHelpText = false )
     302             :     {
     303           0 :         if ( bHelpText )
     304           0 :             return lcl_UnEscapeText(rText,"\\<\\>\\\"\\\\","<>\"\\");
     305             :         else
     306           0 :             return lcl_UnEscapeText(rText,"\\n\\t\\r","\n\t\r");
     307             :     }
     308             : 
     309             :     //Find all special tag in a string using a regular expression
     310           0 :     static void lcl_FindAllTag(
     311             :         const OString& rText,std::vector<OString>& o_vFoundTags )
     312             :     {
     313             : 
     314           0 :         UErrorCode nIcuErr = U_ZERO_ERROR;
     315           0 :         sal_uInt32 nSearchFlags = UREGEX_DOTALL | UREGEX_CASE_INSENSITIVE;
     316           0 :         OUString sLocaleText( OStringToOUString(rText,RTL_TEXTENCODING_UTF8) );
     317           0 :         OUString sPattern("<[/]\?\?[a-z_-]+?(?:| +[a-z]+?=\".*?\") *[/]\?\?>");
     318             :         UnicodeString sSearchPat(
     319             :             reinterpret_cast<const UChar*>(
     320           0 :                 sPattern.getStr()), sPattern.getLength() );
     321             :         UnicodeString sSource(
     322             :             reinterpret_cast<const UChar*>(
     323           0 :                 sLocaleText.getStr()), sLocaleText.getLength() );
     324             : 
     325           0 :         RegexMatcher aRegexMatcher( sSearchPat, nSearchFlags, nIcuErr );
     326           0 :         aRegexMatcher.reset( sSource );
     327           0 :         int64_t nStartPos = 0;
     328           0 :         while( aRegexMatcher.find(nStartPos, nIcuErr) &&
     329             :             nIcuErr == U_ZERO_ERROR )
     330             :         {
     331             :             UnicodeString sMatch =
     332           0 :                 aRegexMatcher.group(nIcuErr);
     333             :             o_vFoundTags.push_back(
     334             :                 OUStringToOString(
     335             :                     OUString(
     336             :                         reinterpret_cast<const sal_Unicode*>(
     337           0 :                             sMatch.getBuffer()),sMatch.length()),
     338           0 :                     RTL_TEXTENCODING_UTF8));
     339           0 :             nStartPos = aRegexMatcher.start(nIcuErr)+1;
     340           0 :         }
     341           0 :     }
     342             : 
     343             :     //Escape special tags
     344           0 :     static OString lcl_EscapeTags( const OString& rText )
     345             :     {
     346             :         typedef std::vector<OString> StrVec_t;
     347             :         const OString vInitializer[] = {
     348             :             "ahelp", "link", "item", "emph", "defaultinline",
     349             :             "switchinline", "caseinline", "variable",
     350           0 :             "bookmark_value", "image", "embedvar", "alt" };
     351             :         const StrVec_t vTagsForEscape( vInitializer,
     352           0 :             vInitializer + sizeof(vInitializer) / sizeof(vInitializer[0]) );
     353           0 :         StrVec_t vFoundTags;
     354           0 :         lcl_FindAllTag(rText,vFoundTags);
     355           0 :         OString sResult = rText;
     356           0 :         for(StrVec_t::const_iterator pFound  = vFoundTags.begin();
     357           0 :             pFound != vFoundTags.end(); ++pFound)
     358             :         {
     359           0 :             bool bEscapeThis = false;
     360           0 :             for(StrVec_t::const_iterator pEscape = vTagsForEscape.begin();
     361           0 :                 pEscape != vTagsForEscape.end(); ++pEscape)
     362             :             {
     363           0 :                 if (pFound->startsWith("<" + *pEscape) ||
     364           0 :                     *pFound == "</" + *pEscape + ">")
     365             :                 {
     366           0 :                     bEscapeThis = true;
     367           0 :                     break;
     368             :                 }
     369             :             }
     370           0 :             if( bEscapeThis || *pFound=="<br/>" ||
     371           0 :                 *pFound =="<help-id-missing/>")
     372             :             {
     373             :                 OString sToReplace = "\\<" +
     374           0 :                     pFound->copy(1,pFound->getLength()-2).
     375           0 :                         replaceAll("\"","\\\"") + "\\>";
     376           0 :                 sResult = sResult.replaceAll(*pFound, sToReplace);
     377             :             }
     378             :         }
     379           0 :         return sResult;
     380             :     }
     381             : 
     382             :     //Escape to get sdf/merge string
     383           0 :     static OString lcl_EscapeSDFText(
     384             :         const OString& rText,const bool bHelpText = false )
     385             :     {
     386           0 :         if ( bHelpText )
     387           0 :             return lcl_EscapeTags(rText.replaceAll("\\","\\\\"));
     388             :         else
     389           0 :             return lcl_EscapeText(rText,"\n\t\r","\\n\\t\\r");
     390             :     }
     391             : }
     392             : 
     393             : //Default constructor
     394           0 : PoEntry::PoEntry()
     395             :     : m_pGenPo( 0 )
     396           0 :     , m_bIsInitialized( false )
     397             : {
     398           0 : }
     399             : 
     400             : //Construct PoEntry from sdfline
     401           0 : PoEntry::PoEntry(const OString& rSDFLine, const TYPE eType)
     402             :     : m_pGenPo( 0 )
     403           0 :     , m_bIsInitialized( false )
     404             : {
     405           0 :     std::vector<OString> vParts;
     406           0 :     lcl_SplitAt(rSDFLine,'\t',vParts);
     407           0 :     if( vParts.size()!=15 ||
     408           0 :         vParts[SOURCEFILE].isEmpty() ||
     409           0 :         vParts[GROUPID].isEmpty() ||
     410           0 :         vParts[RESOURCETYPE].isEmpty() ||
     411           0 :         vParts[eType].isEmpty() ||
     412           0 :         vParts[HELPTEXT].getLength() == 4 )
     413             :     {
     414           0 :         throw INVALIDSDFLINE;
     415             :     }
     416             : 
     417           0 :     m_pGenPo = new GenPoEntry();
     418           0 :     m_pGenPo->setReference(vParts[SOURCEFILE].
     419           0 :         copy(vParts[SOURCEFILE].lastIndexOf("\\")+1));
     420             : 
     421             :     OString sMsgCtxt =
     422           0 :         vParts[GROUPID] + "\n" +
     423           0 :         (vParts[LOCALID].isEmpty() ? OString( "" ) : vParts[LOCALID] + "\n") +
     424           0 :         vParts[RESOURCETYPE];
     425           0 :     switch(eType){
     426             :     case TTEXT:
     427           0 :         sMsgCtxt += ".text"; break;
     428             :     case TQUICKHELPTEXT:
     429           0 :         sMsgCtxt += ".quickhelptext"; break;
     430             :     case TTITLE:
     431           0 :         sMsgCtxt += ".title"; break;
     432             :     /*Default case is unneeded because the type of eType has
     433             :       only three element*/
     434             :     }
     435             :     m_pGenPo->setExtractCom(
     436           0 :         ( !vParts[HELPTEXT].isEmpty() ?  vParts[HELPTEXT] + "\n" : OString( "" )) +
     437             :         lcl_GenKeyId(
     438           0 :             vParts[SOURCEFILE] + sMsgCtxt + vParts[eType] ) );
     439           0 :     m_pGenPo->setMsgCtxt(sMsgCtxt);
     440             :     m_pGenPo->setMsgId(
     441             :         lcl_UnEscapeSDFText(
     442           0 :             vParts[eType],vParts[SOURCEFILE].endsWith(".xhp")));
     443           0 :     m_bIsInitialized = true;
     444           0 : }
     445             : 
     446             : //Destructor
     447           0 : PoEntry::~PoEntry()
     448             : {
     449           0 :     delete m_pGenPo;
     450           0 : }
     451             : 
     452             : //Copy constructor
     453           0 : PoEntry::PoEntry( const PoEntry& rPo )
     454           0 :     : m_pGenPo( rPo.m_pGenPo ? new GenPoEntry( *(rPo.m_pGenPo) ) : 0 )
     455           0 :     , m_bIsInitialized( rPo.m_bIsInitialized )
     456             : {
     457           0 : }
     458             : 
     459             : //Copy operator
     460           0 : PoEntry& PoEntry::operator=(const PoEntry& rPo)
     461             : {
     462           0 :     if( this == &rPo )
     463             :     {
     464           0 :         return *this;
     465             :     }
     466           0 :     if( rPo.m_pGenPo )
     467             :     {
     468           0 :         if( m_pGenPo )
     469             :         {
     470           0 :             *m_pGenPo = *(rPo.m_pGenPo);
     471             :         }
     472             :         else
     473             :         {
     474           0 :             m_pGenPo = new GenPoEntry( *(rPo.m_pGenPo) );
     475             :         }
     476             :     }
     477             :     else
     478             :     {
     479           0 :         delete m_pGenPo;
     480           0 :         m_pGenPo = 0;
     481             :     }
     482           0 :     m_bIsInitialized = rPo.m_bIsInitialized;
     483           0 :     return *this;
     484             : }
     485             : 
     486             : //Get name of file from which entry is extracted
     487           0 : OString PoEntry::getSourceFile() const
     488             : {
     489             :     assert( m_bIsInitialized );
     490           0 :     return m_pGenPo->getReference();
     491             : }
     492             : 
     493             : //Get groupid
     494           0 : OString PoEntry::getGroupId() const
     495             : {
     496             :     assert( m_bIsInitialized );
     497           0 :     return m_pGenPo->getMsgCtxt().getToken(0,'\n');
     498             : }
     499             : 
     500             : //Get localid
     501           0 : OString PoEntry::getLocalId() const
     502             : {
     503             :     assert( m_bIsInitialized );
     504           0 :     const OString sMsgCtxt = m_pGenPo->getMsgCtxt();
     505           0 :     if (sMsgCtxt.indexOf('\n')==sMsgCtxt.lastIndexOf('\n'))
     506           0 :         return OString();
     507             :     else
     508           0 :         return sMsgCtxt.getToken(1,'\n');
     509             : }
     510             : 
     511             : //Get the type of component from which entry is extracted
     512           0 : OString PoEntry::getResourceType() const
     513             : {
     514             :     assert( m_bIsInitialized );
     515           0 :     const OString sMsgCtxt = m_pGenPo->getMsgCtxt();
     516           0 :     if (sMsgCtxt.indexOf('\n')==sMsgCtxt.lastIndexOf('\n'))
     517           0 :         return sMsgCtxt.getToken(1,'\n').getToken(0,'.');
     518             :     else
     519           0 :         return sMsgCtxt.getToken(2,'\n').getToken(0,'.');
     520             : }
     521             : 
     522             : //Get the type of entry
     523           0 : PoEntry::TYPE PoEntry::getType() const
     524             : {
     525             :     assert( m_bIsInitialized );
     526           0 :     const OString sMsgCtxt = m_pGenPo->getMsgCtxt();
     527           0 :     const OString sType = sMsgCtxt.copy( sMsgCtxt.lastIndexOf('.') + 1 );
     528             :     assert(
     529             :         (sType == "text" || sType == "quickhelptext" || sType == "title") );
     530           0 :     if ( sType == "text" )
     531           0 :         return TTEXT;
     532           0 :     else if ( sType == "quickhelptext" )
     533           0 :         return TQUICKHELPTEXT;
     534             :     else
     535           0 :         return TTITLE;
     536             : }
     537             : 
     538             : //Check wheather entry is fuzzy
     539           0 : bool PoEntry::isFuzzy() const
     540             : {
     541             :     assert( m_bIsInitialized );
     542           0 :     return m_pGenPo->isFuzzy();
     543             : }
     544             : 
     545             : //Get keyid
     546           0 : OString PoEntry::getKeyId() const
     547             : {
     548             :     assert( m_bIsInitialized );
     549           0 :     const OString sExtractCom = m_pGenPo->getExtractCom();
     550           0 :     if( sExtractCom.indexOf("\n") == -1 )
     551             :     {
     552           0 :         return sExtractCom;
     553             :     }
     554             :     else
     555             :     {
     556           0 :         return sExtractCom.getToken(1,'\n');
     557           0 :     }
     558             : }
     559             : 
     560             : 
     561             : //Get translation string in sdf/merge format
     562           0 : OString PoEntry::getMsgId() const
     563             : {
     564             :     assert( m_bIsInitialized );
     565             :     return
     566             :         lcl_EscapeSDFText(
     567           0 :             m_pGenPo->getMsgId(), getSourceFile().endsWith(".xhp") );
     568             : }
     569             : 
     570             : //Get translated string in sdf/merge format
     571           0 : OString PoEntry::getMsgStr() const
     572             : {
     573             :     assert( m_bIsInitialized );
     574             :     return
     575             :         lcl_EscapeSDFText(
     576           0 :             m_pGenPo->getMsgStr(), getSourceFile().endsWith(".xhp") );
     577             : 
     578             : }
     579             : 
     580             : //Set translated string when input is in sdf format
     581           0 : void PoEntry::setMsgStr(const OString& rMsgStr)
     582             : {
     583             :     assert( m_bIsInitialized );
     584             :     m_pGenPo->setMsgStr(
     585             :                 lcl_UnEscapeSDFText(
     586           0 :                     rMsgStr,getSourceFile().endsWith(".xhp")));
     587           0 : }
     588             : 
     589             : //Set fuzzy flag
     590           0 : void PoEntry::setFuzzy(const bool bFuzzy)
     591             : {
     592             :     assert( m_bIsInitialized );
     593           0 :     m_pGenPo->setFuzzy(bFuzzy);
     594           0 : }
     595             : 
     596             : //Check whether po-s belong to the same localization component
     597           0 : bool PoEntry::IsInSameComp(const PoEntry& rPo1,const PoEntry& rPo2)
     598             : {
     599             :     assert( rPo1.m_bIsInitialized && rPo2.m_bIsInitialized );
     600           0 :     return ( rPo1.getSourceFile() == rPo2.getSourceFile() &&
     601           0 :              rPo1.getGroupId() == rPo2.getGroupId() &&
     602           0 :              rPo1.getLocalId() == rPo2.getLocalId() &&
     603           0 :              rPo1.getResourceType() == rPo2.getResourceType() );
     604             : }
     605             : 
     606             : //Class PoHeader
     607             : 
     608             : namespace
     609             : {
     610             :     //Get actual time in "YEAR-MO-DA HO:MI+ZONE" form
     611           0 :     static OString lcl_GetTime()
     612             :     {
     613           0 :         time_t aNow = time(NULL);
     614           0 :         struct tm* pNow = localtime(&aNow);
     615             :         char pBuff[50];
     616           0 :         strftime( pBuff, sizeof pBuff, "%Y-%m-%d %H:%M%z", pNow );
     617           0 :         return pBuff;
     618             :     }
     619             : 
     620           0 :     static OString lcl_ReplaceAttribute(
     621             :         const OString& rSource, const OString& rOld, const OString& rNew )
     622             :     {
     623             :         const sal_Int32 nFirstIndex =
     624           0 :             rSource.indexOf( rOld ) + rOld.getLength()+2;
     625             :         const sal_Int32 nCount =
     626           0 :             rSource.indexOf( "\n", nFirstIndex ) - nFirstIndex;
     627           0 :         return rSource.replaceFirst( rSource.copy(nFirstIndex, nCount), rNew );
     628             :     }
     629             : }
     630             : 
     631             : //Default Constructor
     632           0 : PoHeader::PoHeader()
     633             :     : m_pGenPo( 0 )
     634           0 :     , m_bIsInitialized( false )
     635             : {
     636           0 : }
     637             : 
     638             : //Template Constructor
     639           0 : PoHeader::PoHeader( const OString& rExtSrc )
     640             :     : m_pGenPo( new GenPoEntry() )
     641           0 :     , m_bIsInitialized( false )
     642             : {
     643           0 :     m_pGenPo->setExtractCom("extracted from " + rExtSrc);
     644             :     m_pGenPo->setMsgStr(
     645             :         OString("Project-Id-Version: PACKAGE VERSION\n"
     646             :         "Report-Msgid-Bugs-To: https://bugs.freedesktop.org/enter_bug.cgi?"
     647             :         "product=LibreOffice&bug_status=UNCONFIRMED&component=UI\n"
     648           0 :         "POT-Creation-Date: ") + lcl_GetTime() +
     649             :         OString("\nPO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
     650             :         "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
     651             :         "Language-Team: LANGUAGE <LL@li.org>\n"
     652             :         "MIME-Version: 1.0\n"
     653             :         "Content-Type: text/plain; charset=UTF-8\n"
     654             :         "Content-Transfer-Encoding: 8bit\n"
     655             :         "X-Generator: LibreOffice\n"
     656           0 :         "X-Accelerator-Marker: ~\n"));
     657           0 :     m_bIsInitialized = true;
     658           0 : }
     659             : 
     660             : 
     661             : //Constructor for old headers to renew po files
     662           0 : PoHeader::PoHeader(  std::ifstream& rOldPo )
     663             :     : m_pGenPo( new GenPoEntry() )
     664           0 :     , m_bIsInitialized( false )
     665             : {
     666             :     assert( rOldPo.is_open() );
     667           0 :     m_pGenPo->readFromFile( rOldPo );
     668             : 
     669           0 :     const OString sExtractCom = m_pGenPo->getExtractCom();
     670             :     m_pGenPo->setExtractCom(
     671           0 :         sExtractCom.copy( 0, sExtractCom.getLength() - 3 ) );
     672             : 
     673           0 :     OString sMsgStr = m_pGenPo->getMsgStr();
     674             :     sMsgStr =
     675             :         lcl_ReplaceAttribute( sMsgStr, "Report-Msgid-Bugs-To",
     676             :             "https://bugs.freedesktop.org/enter_bug.cgi?product="
     677           0 :             "LibreOffice&bug_status=UNCONFIRMED&component=UI" );
     678             :     sMsgStr =
     679           0 :         lcl_ReplaceAttribute( sMsgStr, "X-Generator", "LibreOffice" );
     680             :     sMsgStr =
     681           0 :         lcl_ReplaceAttribute( sMsgStr, "X-Accelerator-Marker", "~" );
     682           0 :     m_pGenPo->setMsgStr( sMsgStr );
     683           0 :     m_bIsInitialized = true;
     684           0 : }
     685             : 
     686           0 : PoHeader::~PoHeader()
     687             : {
     688           0 :     delete m_pGenPo;
     689           0 : }
     690             : 
     691             : //Class PoOfstream
     692             : 
     693           0 : PoOfstream::PoOfstream()
     694             :     : m_aOutPut()
     695           0 :     , m_bIsAfterHeader( false )
     696             : {
     697           0 : }
     698             : 
     699           0 : PoOfstream::~PoOfstream()
     700             : {
     701           0 :     if( isOpen() )
     702             :     {
     703           0 :        close();
     704             :     }
     705           0 : }
     706             : 
     707           0 : void PoOfstream::open(const OString& rFileName)
     708             : {
     709             :     assert( !isOpen() );
     710             :     m_aOutPut.open( rFileName.getStr(),
     711           0 :         std::ios_base::out | std::ios_base::trunc );
     712           0 :     m_bIsAfterHeader = false;
     713           0 : }
     714             : 
     715           0 : void PoOfstream::close()
     716             : {
     717             :     assert( isOpen() );
     718           0 :     m_aOutPut.close();
     719           0 : }
     720             : 
     721           0 : void PoOfstream::writeHeader(const PoHeader& rPoHeader)
     722             : {
     723             :     assert( isOpen() && !m_bIsAfterHeader && rPoHeader.m_bIsInitialized );
     724           0 :     rPoHeader.m_pGenPo->writeToFile( m_aOutPut );
     725           0 :     m_bIsAfterHeader = true;
     726           0 : }
     727             : 
     728           0 : void PoOfstream::writeEntry( const PoEntry& rPoEntry )
     729             : {
     730             :     assert( isOpen() && m_bIsAfterHeader && rPoEntry.m_bIsInitialized );
     731           0 :     rPoEntry.m_pGenPo->writeToFile( m_aOutPut );
     732           0 : }
     733             : 
     734             : //Class PoIfstream
     735             : 
     736           0 : PoIfstream::PoIfstream()
     737             :     : m_aInPut()
     738           0 :     , m_bEof( false )
     739             : {
     740           0 : }
     741             : 
     742           0 : PoIfstream::~PoIfstream()
     743             : {
     744           0 :     if( isOpen() )
     745             :     {
     746           0 :        close();
     747             :     }
     748           0 : }
     749             : 
     750           0 : void PoIfstream::open( const OString& rFileName )
     751             : {
     752             :     assert( !isOpen() );
     753           0 :     m_aInPut.open( rFileName.getStr(), std::ios_base::in );
     754             : 
     755             :     //Skip header
     756           0 :     std::string sTemp;
     757           0 :     std::getline(m_aInPut,sTemp);
     758           0 :     while( !sTemp.empty() && !m_aInPut.eof() )
     759             :     {
     760           0 :         std::getline(m_aInPut,sTemp);
     761             :     }
     762           0 :     m_bEof = false;
     763           0 : }
     764             : 
     765           0 : void PoIfstream::close()
     766             : {
     767             :     assert( isOpen() );
     768           0 :     m_aInPut.close();
     769           0 : }
     770             : 
     771           0 : void PoIfstream::readEntry( PoEntry& rPoEntry )
     772             : {
     773             :     assert( isOpen() && !eof() );
     774           0 :     GenPoEntry aGenPo;
     775           0 :     aGenPo.readFromFile( m_aInPut );
     776           0 :     if( aGenPo.isNull() )
     777             :     {
     778           0 :         m_bEof = true;
     779           0 :         rPoEntry = PoEntry();
     780             :     }
     781             :     else
     782             :     {
     783           0 :         const OString sMsgCtxt = aGenPo.getMsgCtxt();
     784           0 :         const sal_Int32 nFirstEndLine = sMsgCtxt.indexOf('\n');
     785           0 :         const sal_Int32 nLastEndLine = sMsgCtxt.lastIndexOf('\n');
     786           0 :         const sal_Int32 nLastDot = sMsgCtxt.lastIndexOf('.');
     787           0 :         const OString sType = sMsgCtxt.copy( nLastDot + 1 );
     788           0 :         if( !aGenPo.getReference().isEmpty() &&
     789             :             nFirstEndLine > 0 &&
     790             :             (nLastEndLine == nFirstEndLine ||
     791           0 :                 nLastEndLine == sMsgCtxt.indexOf('\n',nFirstEndLine+1)) &&
     792             :             nLastDot - nLastEndLine > 1 &&
     793           0 :             (sType == "text" || sType == "quickhelptext" || sType == "title")&&
     794           0 :             !aGenPo.getMsgId().isEmpty() )
     795             :         {
     796             :             //Generate keyid if po file not includes it
     797           0 :             const OString sExtractCom = aGenPo.getExtractCom();
     798           0 :             if( sExtractCom.isEmpty() ||
     799           0 :                 ( sExtractCom.getLength() != 4 &&
     800           0 :                     sExtractCom.indexOf("\n") == -1 ) )
     801             :             {
     802             :                 aGenPo.setExtractCom(
     803           0 :                     ( !sExtractCom.isEmpty() ? sExtractCom + "\n" : OString( "" )) +
     804             :                     lcl_GenKeyId(
     805           0 :                         aGenPo.getReference() + sMsgCtxt +
     806           0 :                         aGenPo.getMsgId() ) );
     807             :             }
     808           0 :             if( rPoEntry.m_pGenPo )
     809             :             {
     810           0 :                 *(rPoEntry.m_pGenPo) = aGenPo;
     811             :             }
     812             :             else
     813             :             {
     814           0 :                 rPoEntry.m_pGenPo = new GenPoEntry( aGenPo );
     815             :             }
     816           0 :             rPoEntry.m_bIsInitialized = true;
     817             :         }
     818             :         else
     819             :         {
     820           0 :             throw INVALIDENTRY;
     821           0 :         }
     822           0 :     }
     823           0 : }
     824             : 
     825             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10