VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/io/nsLinebreakConverter.cpp@ 6542

Last change on this file since 6542 was 1, checked in by vboxsync, 55 years ago

import

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette