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"
13 /*----------------------------------------------------------------------------
16 Could make this inline
17 ----------------------------------------------------------------------------*/
19 GetLinebreakString(nsLinebreakConverter::ELinebreakType aBreakType
)
21 static const char* const sLinebreaks
[] = {
23 NS_LINEBREAK
, // platform
33 return sLinebreaks
[aBreakType
];
37 /*----------------------------------------------------------------------------
40 Wee inline method to append a line break. Modifies ioDest.
41 ----------------------------------------------------------------------------*/
44 AppendLinebreak(T
*& aIoDest
, const char* aLineBreakStr
)
46 *aIoDest
++ = *aLineBreakStr
;
48 if (aLineBreakStr
[1]) {
49 *aIoDest
++ = aLineBreakStr
[1];
53 /*----------------------------------------------------------------------------
56 Counts occurrences of breakStr in aSrc
57 ----------------------------------------------------------------------------*/
60 CountLinebreaks(const T
* aSrc
, int32_t aInLen
, const char* aBreakStr
)
63 const T
* srcEnd
= aSrc
+ aInLen
;
66 while (src
< srcEnd
) {
67 if (*src
== *aBreakStr
) {
71 if (src
< srcEnd
&& *src
== aBreakStr
[1]) {
87 /*----------------------------------------------------------------------------
90 ioLen *includes* a terminating null, if any
91 ----------------------------------------------------------------------------*/
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
);
107 memcpy(resultString
, aInSrc
, sizeof(T
) * aIoLen
); // includes the null, if any
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
);
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
;
138 // aIoLen does not change
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
);
146 aIoLen
- (numLinebreaks
* srcBreakLen
) + (numLinebreaks
* destBreakLen
);
147 resultString
= (T
*)nsMemory::Alloc(sizeof(T
) * newBufLen
);
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
;
160 *dst
++ = aDestBreak
[1];
164 if (src
< srcEnd
&& aSrcBreak
[1] && *src
== aSrcBreak
[1]) {
179 /*----------------------------------------------------------------------------
182 Convert breaks in situ. Can only do this if the linebreak length
184 ----------------------------------------------------------------------------*/
187 ConvertBreaksInSitu(T
* aInSrc
, int32_t aInLen
, char aSrcBreak
, char aDestBreak
)
190 T
* srcEnd
= aInSrc
+ aInLen
;
192 while (src
< srcEnd
) {
193 if (*src
== aSrcBreak
) {
202 /*----------------------------------------------------------------------------
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 ----------------------------------------------------------------------------*/
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
) {
223 finalLen
+= destBreakLen
;
227 finalLen
+= destBreakLen
;
229 } else if (*src
== nsCRT::LF
) {
231 finalLen
+= destBreakLen
;
238 T
* resultString
= (T
*)nsMemory::Alloc(sizeof(T
) * finalLen
);
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
) {
252 AppendLinebreak(dst
, aDestBreak
);
256 AppendLinebreak(dst
, aDestBreak
);
258 } else if (*src
== nsCRT::LF
) {
260 AppendLinebreak(dst
, aDestBreak
);
272 /*----------------------------------------------------------------------------
275 ----------------------------------------------------------------------------*/
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");
288 int32_t sourceLen
= (aSrcLen
== kIgnoreLen
) ? strlen(aSrc
) + 1 : aSrcLen
;
291 if (aSrcBreaks
== eLinebreakAny
) {
292 resultString
= ConvertUnknownBreaks(aSrc
, sourceLen
,
293 GetLinebreakString(aDestBreaks
));
295 resultString
= ConvertBreaks(aSrc
, sourceLen
,
296 GetLinebreakString(aSrcBreaks
),
297 GetLinebreakString(aDestBreaks
));
300 *aOutLen
= sourceLen
;
306 /*----------------------------------------------------------------------------
307 ConvertLineBreaksInSitu
309 ----------------------------------------------------------------------------*/
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
);
335 *aOutLen
= sourceLen
;
340 if (aSrcBreaks
== eLinebreakAny
) {
341 destBuffer
= ConvertUnknownBreaks(*aIoBuffer
, sourceLen
, dstBreaks
);
343 destBuffer
= ConvertBreaks(*aIoBuffer
, sourceLen
, srcBreaks
, dstBreaks
);
347 return NS_ERROR_OUT_OF_MEMORY
;
349 *aIoBuffer
= destBuffer
;
351 *aOutLen
= sourceLen
;
359 /*----------------------------------------------------------------------------
360 ConvertUnicharLineBreaks
362 ----------------------------------------------------------------------------*/
364 nsLinebreakConverter::ConvertUnicharLineBreaks(const char16_t
* aSrc
,
365 ELinebreakType aSrcBreaks
,
366 ELinebreakType aDestBreaks
,
370 NS_ASSERTION(aDestBreaks
!= eLinebreakAny
&&
371 aSrcBreaks
!= eLinebreakSpace
, "Invalid parameter");
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
));
383 resultString
= ConvertBreaks(aSrc
, bufLen
, GetLinebreakString(aSrcBreaks
),
384 GetLinebreakString(aDestBreaks
));
393 /*----------------------------------------------------------------------------
394 ConvertStringLineBreaks
396 ----------------------------------------------------------------------------*/
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");
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
);
421 *aOutLen
= sourceLen
;
424 char16_t
* destBuffer
;
426 if (aSrcBreaks
== eLinebreakAny
) {
427 destBuffer
= ConvertUnknownBreaks(*aIoBuffer
, sourceLen
, dstBreaks
);
429 destBuffer
= ConvertBreaks(*aIoBuffer
, sourceLen
, srcBreaks
, dstBreaks
);
433 return NS_ERROR_OUT_OF_MEMORY
;
435 *aIoBuffer
= destBuffer
;
437 *aOutLen
= sourceLen
;
444 /*----------------------------------------------------------------------------
445 ConvertStringLineBreaks
447 ----------------------------------------------------------------------------*/
449 nsLinebreakConverter::ConvertStringLineBreaks(nsString
& aIoString
,
450 ELinebreakType aSrcBreaks
,
451 ELinebreakType aDestBreaks
)
454 NS_ASSERTION(aDestBreaks
!= eLinebreakAny
&&
455 aSrcBreaks
!= eLinebreakSpace
, "Invalid parameter");
458 if (aIoString
.IsEmpty()) {
464 // remember the old buffer in case
465 // we blow it away later
466 nsString::char_iterator stringBuf
;
467 aIoString
.BeginWriting(stringBuf
);
471 rv
= ConvertUnicharLineBreaksInSitu(&stringBuf
,
472 aSrcBreaks
, aDestBreaks
,
473 aIoString
.Length() + 1, &newLen
);
478 if (stringBuf
!= aIoString
.get()) {
479 aIoString
.Adopt(stringBuf
);