LCOV - code coverage report
Current view: top level - xpcom/io - nsLinebreakConverter.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 192 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 16 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsLinebreakConverter.h"
       8             : 
       9             : #include "nsMemory.h"
      10             : #include "nsCRT.h"
      11             : 
      12             : 
      13             : /*----------------------------------------------------------------------------
      14             :   GetLinebreakString
      15             : 
      16             :   Could make this inline
      17             : ----------------------------------------------------------------------------*/
      18             : static const char*
      19           0 : GetLinebreakString(nsLinebreakConverter::ELinebreakType aBreakType)
      20             : {
      21             :   static const char* const sLinebreaks[] = {
      22             :     "",             // any
      23             :     NS_LINEBREAK,   // platform
      24             :     LFSTR,          // content
      25             :     CRLF,           // net
      26             :     CRSTR,          // Mac
      27             :     LFSTR,          // Unix
      28             :     CRLF,           // Windows
      29             :     " ",            // space
      30             :     nullptr
      31             :   };
      32             : 
      33           0 :   return sLinebreaks[aBreakType];
      34             : }
      35             : 
      36             : 
      37             : /*----------------------------------------------------------------------------
      38             :   AppendLinebreak
      39             : 
      40             :   Wee inline method to append a line break. Modifies ioDest.
      41             : ----------------------------------------------------------------------------*/
      42             : template<class T>
      43             : void
      44           0 : AppendLinebreak(T*& aIoDest, const char* aLineBreakStr)
      45             : {
      46           0 :   *aIoDest++ = *aLineBreakStr;
      47             : 
      48           0 :   if (aLineBreakStr[1]) {
      49           0 :     *aIoDest++ = aLineBreakStr[1];
      50             :   }
      51           0 : }
      52             : 
      53             : /*----------------------------------------------------------------------------
      54             :   CountChars
      55             : 
      56             :   Counts occurrences of breakStr in aSrc
      57             : ----------------------------------------------------------------------------*/
      58             : template<class T>
      59             : int32_t
      60           0 : CountLinebreaks(const T* aSrc, int32_t aInLen, const char* aBreakStr)
      61             : {
      62           0 :   const T* src = aSrc;
      63           0 :   const T* srcEnd = aSrc + aInLen;
      64           0 :   int32_t theCount = 0;
      65             : 
      66           0 :   while (src < srcEnd) {
      67           0 :     if (*src == *aBreakStr) {
      68           0 :       src++;
      69             : 
      70           0 :       if (aBreakStr[1]) {
      71           0 :         if (src < srcEnd && *src == aBreakStr[1]) {
      72           0 :           src++;
      73           0 :           theCount++;
      74             :         }
      75             :       } else {
      76           0 :         theCount++;
      77             :       }
      78             :     } else {
      79           0 :       src++;
      80             :     }
      81             :   }
      82             : 
      83           0 :   return theCount;
      84             : }
      85             : 
      86             : 
      87             : /*----------------------------------------------------------------------------
      88             :   ConvertBreaks
      89             : 
      90             :   ioLen *includes* a terminating null, if any
      91             : ----------------------------------------------------------------------------*/
      92             : template<class T>
      93             : static T*
      94           0 : ConvertBreaks(const T* aInSrc, int32_t& aIoLen, const char* aSrcBreak,
      95             :               const char* aDestBreak)
      96             : {
      97           0 :   NS_ASSERTION(aInSrc && aSrcBreak && aDestBreak, "Got a null string");
      98             : 
      99           0 :   T* resultString = nullptr;
     100             : 
     101             :   // handle the no conversion case
     102           0 :   if (nsCRT::strcmp(aSrcBreak, aDestBreak) == 0) {
     103           0 :     resultString = (T*)malloc(sizeof(T) * aIoLen);
     104           0 :     if (!resultString) {
     105           0 :       return nullptr;
     106             :     }
     107           0 :     memcpy(resultString, aInSrc, sizeof(T) * aIoLen); // includes the null, if any
     108           0 :     return resultString;
     109             :   }
     110             : 
     111           0 :   int32_t srcBreakLen = strlen(aSrcBreak);
     112           0 :   int32_t destBreakLen = strlen(aDestBreak);
     113             : 
     114             :   // handle the easy case, where the string length does not change, and the
     115             :   // breaks are only 1 char long, i.e. CR <-> LF
     116           0 :   if (srcBreakLen == destBreakLen && srcBreakLen == 1) {
     117           0 :     resultString = (T*)malloc(sizeof(T) * aIoLen);
     118           0 :     if (!resultString) {
     119           0 :       return nullptr;
     120             :     }
     121             : 
     122           0 :     const T* src = aInSrc;
     123           0 :     const T* srcEnd = aInSrc + aIoLen;  // includes null, if any
     124           0 :     T* dst = resultString;
     125             : 
     126           0 :     char srcBreakChar = *aSrcBreak;  // we know it's one char long already
     127           0 :     char dstBreakChar = *aDestBreak;
     128             : 
     129           0 :     while (src < srcEnd) {
     130           0 :       if (*src == srcBreakChar) {
     131           0 :         *dst++ = dstBreakChar;
     132           0 :         src++;
     133             :       } else {
     134           0 :         *dst++ = *src++;
     135             :       }
     136           0 :     }
     137             : 
     138             :     // aIoLen does not change
     139             :   } else {
     140             :     // src and dest termination is different length. Do it a slower way.
     141             : 
     142             :     // count linebreaks in src. Assumes that chars in 2-char linebreaks are unique.
     143           0 :     int32_t numLinebreaks = CountLinebreaks(aInSrc, aIoLen, aSrcBreak);
     144             : 
     145             :     int32_t newBufLen =
     146           0 :       aIoLen - (numLinebreaks * srcBreakLen) + (numLinebreaks * destBreakLen);
     147           0 :     resultString = (T*)malloc(sizeof(T) * newBufLen);
     148           0 :     if (!resultString) {
     149           0 :       return nullptr;
     150             :     }
     151             : 
     152           0 :     const T* src = aInSrc;
     153           0 :     const T* srcEnd = aInSrc + aIoLen;  // includes null, if any
     154           0 :     T* dst = resultString;
     155             : 
     156           0 :     while (src < srcEnd) {
     157           0 :       if (*src == *aSrcBreak) {
     158           0 :         *dst++ = *aDestBreak;
     159           0 :         if (aDestBreak[1]) {
     160           0 :           *dst++ = aDestBreak[1];
     161             :         }
     162             : 
     163           0 :         src++;
     164           0 :         if (src < srcEnd && aSrcBreak[1] && *src == aSrcBreak[1]) {
     165           0 :           src++;
     166             :         }
     167             :       } else {
     168           0 :         *dst++ = *src++;
     169             :       }
     170             :     }
     171             : 
     172           0 :     aIoLen = newBufLen;
     173             :   }
     174             : 
     175           0 :   return resultString;
     176             : }
     177             : 
     178             : 
     179             : /*----------------------------------------------------------------------------
     180             :   ConvertBreaksInSitu
     181             : 
     182             :   Convert breaks in situ. Can only do this if the linebreak length
     183             :   does not change.
     184             : ----------------------------------------------------------------------------*/
     185             : template<class T>
     186             : static void
     187           0 : ConvertBreaksInSitu(T* aInSrc, int32_t aInLen, char aSrcBreak, char aDestBreak)
     188             : {
     189           0 :   T* src = aInSrc;
     190           0 :   T* srcEnd = aInSrc + aInLen;
     191             : 
     192           0 :   while (src < srcEnd) {
     193           0 :     if (*src == aSrcBreak) {
     194           0 :       *src = aDestBreak;
     195             :     }
     196             : 
     197           0 :     src++;
     198             :   }
     199           0 : }
     200             : 
     201             : 
     202             : /*----------------------------------------------------------------------------
     203             :   ConvertUnknownBreaks
     204             : 
     205             :   Convert unknown line breaks to the specified break.
     206             : 
     207             :   This will convert CRLF pairs to one break, and single CR or LF to a break.
     208             : ----------------------------------------------------------------------------*/
     209             : template<class T>
     210             : static T*
     211           0 : ConvertUnknownBreaks(const T* aInSrc, int32_t& aIoLen, const char* aDestBreak)
     212             : {
     213           0 :   const T* src = aInSrc;
     214           0 :   const T* srcEnd = aInSrc + aIoLen;  // includes null, if any
     215             : 
     216           0 :   int32_t destBreakLen = strlen(aDestBreak);
     217           0 :   int32_t finalLen = 0;
     218             : 
     219           0 :   while (src < srcEnd) {
     220           0 :     if (*src == nsCRT::CR) {
     221           0 :       if (src < srcEnd && src[1] == nsCRT::LF) {
     222             :         // CRLF
     223           0 :         finalLen += destBreakLen;
     224           0 :         src++;
     225             :       } else {
     226             :         // Lone CR
     227           0 :         finalLen += destBreakLen;
     228             :       }
     229           0 :     } else if (*src == nsCRT::LF) {
     230             :       // Lone LF
     231           0 :       finalLen += destBreakLen;
     232             :     } else {
     233           0 :       finalLen++;
     234             :     }
     235           0 :     src++;
     236             :   }
     237             : 
     238           0 :   T* resultString = (T*)malloc(sizeof(T) * finalLen);
     239           0 :   if (!resultString) {
     240           0 :     return nullptr;
     241             :   }
     242             : 
     243           0 :   src = aInSrc;
     244           0 :   srcEnd = aInSrc + aIoLen;  // includes null, if any
     245             : 
     246           0 :   T* dst = resultString;
     247             : 
     248           0 :   while (src < srcEnd) {
     249           0 :     if (*src == nsCRT::CR) {
     250           0 :       if (src < srcEnd && src[1] == nsCRT::LF) {
     251             :         // CRLF
     252           0 :         AppendLinebreak(dst, aDestBreak);
     253           0 :         src++;
     254             :       } else {
     255             :         // Lone CR
     256           0 :         AppendLinebreak(dst, aDestBreak);
     257             :       }
     258           0 :     } else if (*src == nsCRT::LF) {
     259             :       // Lone LF
     260           0 :       AppendLinebreak(dst, aDestBreak);
     261             :     } else {
     262           0 :       *dst++ = *src;
     263             :     }
     264           0 :     src++;
     265             :   }
     266             : 
     267           0 :   aIoLen = finalLen;
     268           0 :   return resultString;
     269             : }
     270             : 
     271             : 
     272             : /*----------------------------------------------------------------------------
     273             :   ConvertLineBreaks
     274             : 
     275             : ----------------------------------------------------------------------------*/
     276             : char*
     277           0 : nsLinebreakConverter::ConvertLineBreaks(const char* aSrc,
     278             :                                         ELinebreakType aSrcBreaks,
     279             :                                         ELinebreakType aDestBreaks,
     280             :                                         int32_t aSrcLen, int32_t* aOutLen)
     281             : {
     282           0 :   NS_ASSERTION(aDestBreaks != eLinebreakAny &&
     283             :                aSrcBreaks != eLinebreakSpace, "Invalid parameter");
     284           0 :   if (!aSrc) {
     285           0 :     return nullptr;
     286             :   }
     287             : 
     288           0 :   int32_t sourceLen = (aSrcLen == kIgnoreLen) ? strlen(aSrc) + 1 : aSrcLen;
     289             : 
     290             :   char* resultString;
     291           0 :   if (aSrcBreaks == eLinebreakAny) {
     292           0 :     resultString = ConvertUnknownBreaks(aSrc, sourceLen,
     293           0 :                                         GetLinebreakString(aDestBreaks));
     294             :   } else
     295           0 :     resultString = ConvertBreaks(aSrc, sourceLen,
     296             :                                  GetLinebreakString(aSrcBreaks),
     297           0 :                                  GetLinebreakString(aDestBreaks));
     298             : 
     299           0 :   if (aOutLen) {
     300           0 :     *aOutLen = sourceLen;
     301             :   }
     302           0 :   return resultString;
     303             : }
     304             : 
     305             : 
     306             : /*----------------------------------------------------------------------------
     307             :   ConvertLineBreaksInSitu
     308             : 
     309             : ----------------------------------------------------------------------------*/
     310             : nsresult
     311           0 : nsLinebreakConverter::ConvertLineBreaksInSitu(char** aIoBuffer,
     312             :                                               ELinebreakType aSrcBreaks,
     313             :                                               ELinebreakType aDestBreaks,
     314             :                                               int32_t aSrcLen, int32_t* aOutLen)
     315             : {
     316           0 :   NS_ASSERTION(aIoBuffer && *aIoBuffer, "Null pointer passed");
     317           0 :   if (!aIoBuffer || !*aIoBuffer) {
     318           0 :     return NS_ERROR_NULL_POINTER;
     319             :   }
     320             : 
     321           0 :   NS_ASSERTION(aDestBreaks != eLinebreakAny &&
     322             :                aSrcBreaks != eLinebreakSpace, "Invalid parameter");
     323             : 
     324           0 :   int32_t sourceLen = (aSrcLen == kIgnoreLen) ? strlen(*aIoBuffer) + 1 : aSrcLen;
     325             : 
     326             :   // can we convert in-place?
     327           0 :   const char* srcBreaks = GetLinebreakString(aSrcBreaks);
     328           0 :   const char* dstBreaks = GetLinebreakString(aDestBreaks);
     329             : 
     330           0 :   if (aSrcBreaks != eLinebreakAny &&
     331           0 :       strlen(srcBreaks) == 1 &&
     332           0 :       strlen(dstBreaks) == 1) {
     333           0 :     ConvertBreaksInSitu(*aIoBuffer, sourceLen, *srcBreaks, *dstBreaks);
     334           0 :     if (aOutLen) {
     335           0 :       *aOutLen = sourceLen;
     336             :     }
     337             :   } else {
     338             :     char* destBuffer;
     339             : 
     340           0 :     if (aSrcBreaks == eLinebreakAny) {
     341           0 :       destBuffer = ConvertUnknownBreaks(*aIoBuffer, sourceLen, dstBreaks);
     342             :     } else {
     343           0 :       destBuffer = ConvertBreaks(*aIoBuffer, sourceLen, srcBreaks, dstBreaks);
     344             :     }
     345             : 
     346           0 :     if (!destBuffer) {
     347           0 :       return NS_ERROR_OUT_OF_MEMORY;
     348             :     }
     349           0 :     *aIoBuffer = destBuffer;
     350           0 :     if (aOutLen) {
     351           0 :       *aOutLen = sourceLen;
     352             :     }
     353             :   }
     354             : 
     355           0 :   return NS_OK;
     356             : }
     357             : 
     358             : 
     359             : /*----------------------------------------------------------------------------
     360             :   ConvertUnicharLineBreaks
     361             : 
     362             : ----------------------------------------------------------------------------*/
     363             : char16_t*
     364           0 : nsLinebreakConverter::ConvertUnicharLineBreaks(const char16_t* aSrc,
     365             :                                                ELinebreakType aSrcBreaks,
     366             :                                                ELinebreakType aDestBreaks,
     367             :                                                int32_t aSrcLen,
     368             :                                                int32_t* aOutLen)
     369             : {
     370           0 :   NS_ASSERTION(aDestBreaks != eLinebreakAny &&
     371             :                aSrcBreaks != eLinebreakSpace, "Invalid parameter");
     372           0 :   if (!aSrc) {
     373           0 :     return nullptr;
     374             :   }
     375             : 
     376           0 :   int32_t bufLen = (aSrcLen == kIgnoreLen) ? NS_strlen(aSrc) + 1 : aSrcLen;
     377             : 
     378             :   char16_t* resultString;
     379           0 :   if (aSrcBreaks == eLinebreakAny) {
     380           0 :     resultString = ConvertUnknownBreaks(aSrc, bufLen,
     381           0 :                                         GetLinebreakString(aDestBreaks));
     382             :   } else
     383           0 :     resultString = ConvertBreaks(aSrc, bufLen, GetLinebreakString(aSrcBreaks),
     384           0 :                                  GetLinebreakString(aDestBreaks));
     385             : 
     386           0 :   if (aOutLen) {
     387           0 :     *aOutLen = bufLen;
     388             :   }
     389           0 :   return resultString;
     390             : }
     391             : 
     392             : 
     393             : /*----------------------------------------------------------------------------
     394             :   ConvertStringLineBreaks
     395             : 
     396             : ----------------------------------------------------------------------------*/
     397             : nsresult
     398           0 : nsLinebreakConverter::ConvertUnicharLineBreaksInSitu(
     399             :     char16_t** aIoBuffer, ELinebreakType aSrcBreaks, ELinebreakType aDestBreaks,
     400             :     int32_t aSrcLen, int32_t* aOutLen)
     401             : {
     402           0 :   NS_ASSERTION(aIoBuffer && *aIoBuffer, "Null pointer passed");
     403           0 :   if (!aIoBuffer || !*aIoBuffer) {
     404           0 :     return NS_ERROR_NULL_POINTER;
     405             :   }
     406           0 :   NS_ASSERTION(aDestBreaks != eLinebreakAny &&
     407             :                aSrcBreaks != eLinebreakSpace, "Invalid parameter");
     408             : 
     409             :   int32_t sourceLen =
     410           0 :     (aSrcLen == kIgnoreLen) ? NS_strlen(*aIoBuffer) + 1 : aSrcLen;
     411             : 
     412             :   // can we convert in-place?
     413           0 :   const char* srcBreaks = GetLinebreakString(aSrcBreaks);
     414           0 :   const char* dstBreaks = GetLinebreakString(aDestBreaks);
     415             : 
     416           0 :   if ((aSrcBreaks != eLinebreakAny) &&
     417           0 :       (strlen(srcBreaks) == 1) &&
     418           0 :       (strlen(dstBreaks) == 1)) {
     419           0 :     ConvertBreaksInSitu(*aIoBuffer, sourceLen, *srcBreaks, *dstBreaks);
     420           0 :     if (aOutLen) {
     421           0 :       *aOutLen = sourceLen;
     422             :     }
     423             :   } else {
     424             :     char16_t* destBuffer;
     425             : 
     426           0 :     if (aSrcBreaks == eLinebreakAny) {
     427           0 :       destBuffer = ConvertUnknownBreaks(*aIoBuffer, sourceLen, dstBreaks);
     428             :     } else {
     429           0 :       destBuffer = ConvertBreaks(*aIoBuffer, sourceLen, srcBreaks, dstBreaks);
     430             :     }
     431             : 
     432           0 :     if (!destBuffer) {
     433           0 :       return NS_ERROR_OUT_OF_MEMORY;
     434             :     }
     435           0 :     *aIoBuffer = destBuffer;
     436           0 :     if (aOutLen) {
     437           0 :       *aOutLen = sourceLen;
     438             :     }
     439             :   }
     440             : 
     441           0 :   return NS_OK;
     442             : }
     443             : 
     444             : /*----------------------------------------------------------------------------
     445             :   ConvertStringLineBreaks
     446             : 
     447             : ----------------------------------------------------------------------------*/
     448             : nsresult
     449           0 : nsLinebreakConverter::ConvertStringLineBreaks(nsString& aIoString,
     450             :                                               ELinebreakType aSrcBreaks,
     451             :                                               ELinebreakType aDestBreaks)
     452             : {
     453             : 
     454           0 :   NS_ASSERTION(aDestBreaks != eLinebreakAny &&
     455             :                aSrcBreaks != eLinebreakSpace, "Invalid parameter");
     456             : 
     457             :   // nothing to do
     458           0 :   if (aIoString.IsEmpty()) {
     459           0 :     return NS_OK;
     460             :   }
     461             : 
     462             :   nsresult rv;
     463             : 
     464             :   // remember the old buffer in case
     465             :   // we blow it away later
     466             :   nsString::char_iterator stringBuf;
     467           0 :   if (!aIoString.BeginWriting(stringBuf, fallible)) {
     468           0 :     return NS_ERROR_OUT_OF_MEMORY;
     469             :   }
     470             : 
     471             :   int32_t    newLen;
     472             : 
     473           0 :   rv = ConvertUnicharLineBreaksInSitu(&stringBuf,
     474             :                                       aSrcBreaks, aDestBreaks,
     475           0 :                                       aIoString.Length() + 1, &newLen);
     476           0 :   if (NS_FAILED(rv)) {
     477           0 :     return rv;
     478             :   }
     479             : 
     480           0 :   if (stringBuf != aIoString.get()) {
     481           0 :     aIoString.Adopt(stringBuf, newLen - 1);
     482             :   }
     483             : 
     484           0 :   return NS_OK;
     485             : }
     486             : 
     487             : 
     488             : 

Generated by: LCOV version 1.13