Bumping manifests a=b2g-bump
[gecko.git] / xpcom / io / nsLinebreakConverter.cpp
blobdc86c0a8397822b463012e563b019ccd0b67263b
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/. */
7 #include "nsLinebreakConverter.h"
9 #include "nsMemory.h"
10 #include "nsCRT.h"
13 /*----------------------------------------------------------------------------
14 GetLinebreakString
16 Could make this inline
17 ----------------------------------------------------------------------------*/
18 static const char*
19 GetLinebreakString(nsLinebreakConverter::ELinebreakType aBreakType)
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
33 return sLinebreaks[aBreakType];
37 /*----------------------------------------------------------------------------
38 AppendLinebreak
40 Wee inline method to append a line break. Modifies ioDest.
41 ----------------------------------------------------------------------------*/
42 template<class T>
43 void
44 AppendLinebreak(T*& aIoDest, const char* aLineBreakStr)
46 *aIoDest++ = *aLineBreakStr;
48 if (aLineBreakStr[1]) {
49 *aIoDest++ = aLineBreakStr[1];
53 /*----------------------------------------------------------------------------
54 CountChars
56 Counts occurrences of breakStr in aSrc
57 ----------------------------------------------------------------------------*/
58 template<class T>
59 int32_t
60 CountLinebreaks(const T* aSrc, int32_t aInLen, const char* aBreakStr)
62 const T* src = aSrc;
63 const T* srcEnd = aSrc + aInLen;
64 int32_t theCount = 0;
66 while (src < srcEnd) {
67 if (*src == *aBreakStr) {
68 src++;
70 if (aBreakStr[1]) {
71 if (src < srcEnd && *src == aBreakStr[1]) {
72 src++;
73 theCount++;
75 } else {
76 theCount++;
78 } else {
79 src++;
83 return theCount;
87 /*----------------------------------------------------------------------------
88 ConvertBreaks
90 ioLen *includes* a terminating null, if any
91 ----------------------------------------------------------------------------*/
92 template<class T>
93 static T*
94 ConvertBreaks(const T* aInSrc, int32_t& aIoLen, const char* aSrcBreak,
95 const char* aDestBreak)
97 NS_ASSERTION(aInSrc && aSrcBreak && aDestBreak, "Got a null string");
99 T* resultString = nullptr;
101 // handle the no conversion case
102 if (nsCRT::strcmp(aSrcBreak, aDestBreak) == 0) {
103 resultString = (T*)nsMemory::Alloc(sizeof(T) * aIoLen);
104 if (!resultString) {
105 return nullptr;
107 memcpy(resultString, aInSrc, sizeof(T) * aIoLen); // includes the null, if any
108 return resultString;
111 int32_t srcBreakLen = strlen(aSrcBreak);
112 int32_t destBreakLen = strlen(aDestBreak);
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 if (srcBreakLen == destBreakLen && srcBreakLen == 1) {
117 resultString = (T*)nsMemory::Alloc(sizeof(T) * aIoLen);
118 if (!resultString) {
119 return nullptr;
122 const T* src = aInSrc;
123 const T* srcEnd = aInSrc + aIoLen; // includes null, if any
124 T* dst = resultString;
126 char srcBreakChar = *aSrcBreak; // we know it's one char long already
127 char dstBreakChar = *aDestBreak;
129 while (src < srcEnd) {
130 if (*src == srcBreakChar) {
131 *dst++ = dstBreakChar;
132 src++;
133 } else {
134 *dst++ = *src++;
138 // aIoLen does not change
139 } else {
140 // src and dest termination is different length. Do it a slower way.
142 // count linebreaks in src. Assumes that chars in 2-char linebreaks are unique.
143 int32_t numLinebreaks = CountLinebreaks(aInSrc, aIoLen, aSrcBreak);
145 int32_t newBufLen =
146 aIoLen - (numLinebreaks * srcBreakLen) + (numLinebreaks * destBreakLen);
147 resultString = (T*)nsMemory::Alloc(sizeof(T) * newBufLen);
148 if (!resultString) {
149 return nullptr;
152 const T* src = aInSrc;
153 const T* srcEnd = aInSrc + aIoLen; // includes null, if any
154 T* dst = resultString;
156 while (src < srcEnd) {
157 if (*src == *aSrcBreak) {
158 *dst++ = *aDestBreak;
159 if (aDestBreak[1]) {
160 *dst++ = aDestBreak[1];
163 src++;
164 if (src < srcEnd && aSrcBreak[1] && *src == aSrcBreak[1]) {
165 src++;
167 } else {
168 *dst++ = *src++;
172 aIoLen = newBufLen;
175 return resultString;
179 /*----------------------------------------------------------------------------
180 ConvertBreaksInSitu
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 ConvertBreaksInSitu(T* aInSrc, int32_t aInLen, char aSrcBreak, char aDestBreak)
189 T* src = aInSrc;
190 T* srcEnd = aInSrc + aInLen;
192 while (src < srcEnd) {
193 if (*src == aSrcBreak) {
194 *src = aDestBreak;
197 src++;
202 /*----------------------------------------------------------------------------
203 ConvertUnknownBreaks
205 Convert unknown line breaks to the specified break.
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 ConvertUnknownBreaks(const T* aInSrc, int32_t& aIoLen, const char* aDestBreak)
213 const T* src = aInSrc;
214 const T* srcEnd = aInSrc + aIoLen; // includes null, if any
216 int32_t destBreakLen = strlen(aDestBreak);
217 int32_t finalLen = 0;
219 while (src < srcEnd) {
220 if (*src == nsCRT::CR) {
221 if (src < srcEnd && src[1] == nsCRT::LF) {
222 // CRLF
223 finalLen += destBreakLen;
224 src++;
225 } else {
226 // Lone CR
227 finalLen += destBreakLen;
229 } else if (*src == nsCRT::LF) {
230 // Lone LF
231 finalLen += destBreakLen;
232 } else {
233 finalLen++;
235 src++;
238 T* resultString = (T*)nsMemory::Alloc(sizeof(T) * finalLen);
239 if (!resultString) {
240 return nullptr;
243 src = aInSrc;
244 srcEnd = aInSrc + aIoLen; // includes null, if any
246 T* dst = resultString;
248 while (src < srcEnd) {
249 if (*src == nsCRT::CR) {
250 if (src < srcEnd && src[1] == nsCRT::LF) {
251 // CRLF
252 AppendLinebreak(dst, aDestBreak);
253 src++;
254 } else {
255 // Lone CR
256 AppendLinebreak(dst, aDestBreak);
258 } else if (*src == nsCRT::LF) {
259 // Lone LF
260 AppendLinebreak(dst, aDestBreak);
261 } else {
262 *dst++ = *src;
264 src++;
267 aIoLen = finalLen;
268 return resultString;
272 /*----------------------------------------------------------------------------
273 ConvertLineBreaks
275 ----------------------------------------------------------------------------*/
276 char*
277 nsLinebreakConverter::ConvertLineBreaks(const char* aSrc,
278 ELinebreakType aSrcBreaks,
279 ELinebreakType aDestBreaks,
280 int32_t aSrcLen, int32_t* aOutLen)
282 NS_ASSERTION(aDestBreaks != eLinebreakAny &&
283 aSrcBreaks != eLinebreakSpace, "Invalid parameter");
284 if (!aSrc) {
285 return nullptr;
288 int32_t sourceLen = (aSrcLen == kIgnoreLen) ? strlen(aSrc) + 1 : aSrcLen;
290 char* resultString;
291 if (aSrcBreaks == eLinebreakAny) {
292 resultString = ConvertUnknownBreaks(aSrc, sourceLen,
293 GetLinebreakString(aDestBreaks));
294 } else
295 resultString = ConvertBreaks(aSrc, sourceLen,
296 GetLinebreakString(aSrcBreaks),
297 GetLinebreakString(aDestBreaks));
299 if (aOutLen) {
300 *aOutLen = sourceLen;
302 return resultString;
306 /*----------------------------------------------------------------------------
307 ConvertLineBreaksInSitu
309 ----------------------------------------------------------------------------*/
310 nsresult
311 nsLinebreakConverter::ConvertLineBreaksInSitu(char** aIoBuffer,
312 ELinebreakType aSrcBreaks,
313 ELinebreakType aDestBreaks,
314 int32_t aSrcLen, int32_t* aOutLen)
316 NS_ASSERTION(aIoBuffer && *aIoBuffer, "Null pointer passed");
317 if (!aIoBuffer || !*aIoBuffer) {
318 return NS_ERROR_NULL_POINTER;
321 NS_ASSERTION(aDestBreaks != eLinebreakAny &&
322 aSrcBreaks != eLinebreakSpace, "Invalid parameter");
324 int32_t sourceLen = (aSrcLen == kIgnoreLen) ? strlen(*aIoBuffer) + 1 : aSrcLen;
326 // can we convert in-place?
327 const char* srcBreaks = GetLinebreakString(aSrcBreaks);
328 const char* dstBreaks = GetLinebreakString(aDestBreaks);
330 if (aSrcBreaks != eLinebreakAny &&
331 strlen(srcBreaks) == 1 &&
332 strlen(dstBreaks) == 1) {
333 ConvertBreaksInSitu(*aIoBuffer, sourceLen, *srcBreaks, *dstBreaks);
334 if (aOutLen) {
335 *aOutLen = sourceLen;
337 } else {
338 char* destBuffer;
340 if (aSrcBreaks == eLinebreakAny) {
341 destBuffer = ConvertUnknownBreaks(*aIoBuffer, sourceLen, dstBreaks);
342 } else {
343 destBuffer = ConvertBreaks(*aIoBuffer, sourceLen, srcBreaks, dstBreaks);
346 if (!destBuffer) {
347 return NS_ERROR_OUT_OF_MEMORY;
349 *aIoBuffer = destBuffer;
350 if (aOutLen) {
351 *aOutLen = sourceLen;
355 return NS_OK;
359 /*----------------------------------------------------------------------------
360 ConvertUnicharLineBreaks
362 ----------------------------------------------------------------------------*/
363 char16_t*
364 nsLinebreakConverter::ConvertUnicharLineBreaks(const char16_t* aSrc,
365 ELinebreakType aSrcBreaks,
366 ELinebreakType aDestBreaks,
367 int32_t aSrcLen,
368 int32_t* aOutLen)
370 NS_ASSERTION(aDestBreaks != eLinebreakAny &&
371 aSrcBreaks != eLinebreakSpace, "Invalid parameter");
372 if (!aSrc) {
373 return nullptr;
376 int32_t bufLen = (aSrcLen == kIgnoreLen) ? NS_strlen(aSrc) + 1 : aSrcLen;
378 char16_t* resultString;
379 if (aSrcBreaks == eLinebreakAny) {
380 resultString = ConvertUnknownBreaks(aSrc, bufLen,
381 GetLinebreakString(aDestBreaks));
382 } else
383 resultString = ConvertBreaks(aSrc, bufLen, GetLinebreakString(aSrcBreaks),
384 GetLinebreakString(aDestBreaks));
386 if (aOutLen) {
387 *aOutLen = bufLen;
389 return resultString;
393 /*----------------------------------------------------------------------------
394 ConvertStringLineBreaks
396 ----------------------------------------------------------------------------*/
397 nsresult
398 nsLinebreakConverter::ConvertUnicharLineBreaksInSitu(
399 char16_t** aIoBuffer, ELinebreakType aSrcBreaks, ELinebreakType aDestBreaks,
400 int32_t aSrcLen, int32_t* aOutLen)
402 NS_ASSERTION(aIoBuffer && *aIoBuffer, "Null pointer passed");
403 if (!aIoBuffer || !*aIoBuffer) {
404 return NS_ERROR_NULL_POINTER;
406 NS_ASSERTION(aDestBreaks != eLinebreakAny &&
407 aSrcBreaks != eLinebreakSpace, "Invalid parameter");
409 int32_t sourceLen =
410 (aSrcLen == kIgnoreLen) ? NS_strlen(*aIoBuffer) + 1 : aSrcLen;
412 // can we convert in-place?
413 const char* srcBreaks = GetLinebreakString(aSrcBreaks);
414 const char* dstBreaks = GetLinebreakString(aDestBreaks);
416 if ((aSrcBreaks != eLinebreakAny) &&
417 (strlen(srcBreaks) == 1) &&
418 (strlen(dstBreaks) == 1)) {
419 ConvertBreaksInSitu(*aIoBuffer, sourceLen, *srcBreaks, *dstBreaks);
420 if (aOutLen) {
421 *aOutLen = sourceLen;
423 } else {
424 char16_t* destBuffer;
426 if (aSrcBreaks == eLinebreakAny) {
427 destBuffer = ConvertUnknownBreaks(*aIoBuffer, sourceLen, dstBreaks);
428 } else {
429 destBuffer = ConvertBreaks(*aIoBuffer, sourceLen, srcBreaks, dstBreaks);
432 if (!destBuffer) {
433 return NS_ERROR_OUT_OF_MEMORY;
435 *aIoBuffer = destBuffer;
436 if (aOutLen) {
437 *aOutLen = sourceLen;
441 return NS_OK;
444 /*----------------------------------------------------------------------------
445 ConvertStringLineBreaks
447 ----------------------------------------------------------------------------*/
448 nsresult
449 nsLinebreakConverter::ConvertStringLineBreaks(nsString& aIoString,
450 ELinebreakType aSrcBreaks,
451 ELinebreakType aDestBreaks)
454 NS_ASSERTION(aDestBreaks != eLinebreakAny &&
455 aSrcBreaks != eLinebreakSpace, "Invalid parameter");
457 // nothing to do
458 if (aIoString.IsEmpty()) {
459 return NS_OK;
462 nsresult rv;
464 // remember the old buffer in case
465 // we blow it away later
466 nsString::char_iterator stringBuf;
467 aIoString.BeginWriting(stringBuf);
469 int32_t newLen;
471 rv = ConvertUnicharLineBreaksInSitu(&stringBuf,
472 aSrcBreaks, aDestBreaks,
473 aIoString.Length() + 1, &newLen);
474 if (NS_FAILED(rv)) {
475 return rv;
478 if (stringBuf != aIoString.get()) {
479 aIoString.Adopt(stringBuf);
482 return NS_OK;