Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/xpcom/io/nsLinebreakConverter.cpp
Line
Count
Source (jump to first uncovered line)
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
GetLinebreakString(nsLinebreakConverter::ELinebreakType aBreakType)
20
0
{
21
0
  static const char* const sLinebreaks[] = {
22
0
    "",             // any
23
0
    NS_LINEBREAK,   // platform
24
0
    LFSTR,          // content
25
0
    CRLF,           // net
26
0
    CRSTR,          // Mac
27
0
    LFSTR,          // Unix
28
0
    CRLF,           // Windows
29
0
    " ",            // space
30
0
    nullptr
31
0
  };
32
0
33
0
  return sLinebreaks[aBreakType];
34
0
}
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
AppendLinebreak(T*& aIoDest, const char* aLineBreakStr)
45
0
{
46
0
  *aIoDest++ = *aLineBreakStr;
47
0
48
0
  if (aLineBreakStr[1]) {
49
0
    *aIoDest++ = aLineBreakStr[1];
50
0
  }
51
0
}
Unexecuted instantiation: void AppendLinebreak<char>(char*&, char const*)
Unexecuted instantiation: void AppendLinebreak<char16_t>(char16_t*&, char const*)
52
53
/*----------------------------------------------------------------------------
54
  CountChars
55
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)
61
0
{
62
0
  const T* src = aSrc;
63
0
  const T* srcEnd = aSrc + aInLen;
64
0
  int32_t theCount = 0;
65
0
66
0
  while (src < srcEnd) {
67
0
    if (*src == *aBreakStr) {
68
0
      src++;
69
0
70
0
      if (aBreakStr[1]) {
71
0
        if (src < srcEnd && *src == aBreakStr[1]) {
72
0
          src++;
73
0
          theCount++;
74
0
        }
75
0
      } else {
76
0
        theCount++;
77
0
      }
78
0
    } else {
79
0
      src++;
80
0
    }
81
0
  }
82
0
83
0
  return theCount;
84
0
}
Unexecuted instantiation: int CountLinebreaks<char>(char const*, int, char const*)
Unexecuted instantiation: int CountLinebreaks<char16_t>(char16_t const*, int, char const*)
85
86
87
/*----------------------------------------------------------------------------
88
  ConvertBreaks
89
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)
96
0
{
97
0
  NS_ASSERTION(aInSrc && aSrcBreak && aDestBreak, "Got a null string");
98
0
99
0
  T* resultString = nullptr;
100
0
101
0
  // 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
0
    }
107
0
    memcpy(resultString, aInSrc, sizeof(T) * aIoLen); // includes the null, if any
108
0
    return resultString;
109
0
  }
110
0
111
0
  int32_t srcBreakLen = strlen(aSrcBreak);
112
0
  int32_t destBreakLen = strlen(aDestBreak);
113
0
114
0
  // handle the easy case, where the string length does not change, and the
115
0
  // 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
0
    }
121
0
122
0
    const T* src = aInSrc;
123
0
    const T* srcEnd = aInSrc + aIoLen;  // includes null, if any
124
0
    T* dst = resultString;
125
0
126
0
    char srcBreakChar = *aSrcBreak;  // we know it's one char long already
127
0
    char dstBreakChar = *aDestBreak;
128
0
129
0
    while (src < srcEnd) {
130
0
      if (*src == srcBreakChar) {
131
0
        *dst++ = dstBreakChar;
132
0
        src++;
133
0
      } else {
134
0
        *dst++ = *src++;
135
0
      }
136
0
    }
137
0
138
0
    // aIoLen does not change
139
0
  } else {
140
0
    // src and dest termination is different length. Do it a slower way.
141
0
142
0
    // count linebreaks in src. Assumes that chars in 2-char linebreaks are unique.
143
0
    int32_t numLinebreaks = CountLinebreaks(aInSrc, aIoLen, aSrcBreak);
144
0
145
0
    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
0
    }
151
0
152
0
    const T* src = aInSrc;
153
0
    const T* srcEnd = aInSrc + aIoLen;  // includes null, if any
154
0
    T* dst = resultString;
155
0
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
0
        }
162
0
163
0
        src++;
164
0
        if (src < srcEnd && aSrcBreak[1] && *src == aSrcBreak[1]) {
165
0
          src++;
166
0
        }
167
0
      } else {
168
0
        *dst++ = *src++;
169
0
      }
170
0
    }
171
0
172
0
    aIoLen = newBufLen;
173
0
  }
174
0
175
0
  return resultString;
176
0
}
Unexecuted instantiation: Unified_cpp_xpcom_io1.cpp:char* ConvertBreaks<char>(char const*, int&, char const*, char const*)
Unexecuted instantiation: Unified_cpp_xpcom_io1.cpp:char16_t* ConvertBreaks<char16_t>(char16_t const*, int&, char const*, char const*)
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
ConvertBreaksInSitu(T* aInSrc, int32_t aInLen, char aSrcBreak, char aDestBreak)
188
0
{
189
0
  T* src = aInSrc;
190
0
  T* srcEnd = aInSrc + aInLen;
191
0
192
0
  while (src < srcEnd) {
193
0
    if (*src == aSrcBreak) {
194
0
      *src = aDestBreak;
195
0
    }
196
0
197
0
    src++;
198
0
  }
199
0
}
Unexecuted instantiation: Unified_cpp_xpcom_io1.cpp:void ConvertBreaksInSitu<char>(char*, int, char, char)
Unexecuted instantiation: Unified_cpp_xpcom_io1.cpp:void ConvertBreaksInSitu<char16_t>(char16_t*, int, char, char)
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
ConvertUnknownBreaks(const T* aInSrc, int32_t& aIoLen, const char* aDestBreak)
212
0
{
213
0
  const T* src = aInSrc;
214
0
  const T* srcEnd = aInSrc + aIoLen;  // includes null, if any
215
0
216
0
  int32_t destBreakLen = strlen(aDestBreak);
217
0
  int32_t finalLen = 0;
218
0
219
0
  while (src < srcEnd) {
220
0
    if (*src == nsCRT::CR) {
221
0
      if (src < srcEnd && src[1] == nsCRT::LF) {
222
0
        // CRLF
223
0
        finalLen += destBreakLen;
224
0
        src++;
225
0
      } else {
226
0
        // Lone CR
227
0
        finalLen += destBreakLen;
228
0
      }
229
0
    } else if (*src == nsCRT::LF) {
230
0
      // Lone LF
231
0
      finalLen += destBreakLen;
232
0
    } else {
233
0
      finalLen++;
234
0
    }
235
0
    src++;
236
0
  }
237
0
238
0
  T* resultString = (T*)malloc(sizeof(T) * finalLen);
239
0
  if (!resultString) {
240
0
    return nullptr;
241
0
  }
242
0
243
0
  src = aInSrc;
244
0
  srcEnd = aInSrc + aIoLen;  // includes null, if any
245
0
246
0
  T* dst = resultString;
247
0
248
0
  while (src < srcEnd) {
249
0
    if (*src == nsCRT::CR) {
250
0
      if (src < srcEnd && src[1] == nsCRT::LF) {
251
0
        // CRLF
252
0
        AppendLinebreak(dst, aDestBreak);
253
0
        src++;
254
0
      } else {
255
0
        // Lone CR
256
0
        AppendLinebreak(dst, aDestBreak);
257
0
      }
258
0
    } else if (*src == nsCRT::LF) {
259
0
      // Lone LF
260
0
      AppendLinebreak(dst, aDestBreak);
261
0
    } else {
262
0
      *dst++ = *src;
263
0
    }
264
0
    src++;
265
0
  }
266
0
267
0
  aIoLen = finalLen;
268
0
  return resultString;
269
0
}
Unexecuted instantiation: Unified_cpp_xpcom_io1.cpp:char* ConvertUnknownBreaks<char>(char const*, int&, char const*)
Unexecuted instantiation: Unified_cpp_xpcom_io1.cpp:char16_t* ConvertUnknownBreaks<char16_t>(char16_t const*, int&, char const*)
270
271
272
/*----------------------------------------------------------------------------
273
  ConvertLineBreaks
274
275
----------------------------------------------------------------------------*/
276
char*
277
nsLinebreakConverter::ConvertLineBreaks(const char* aSrc,
278
                                        ELinebreakType aSrcBreaks,
279
                                        ELinebreakType aDestBreaks,
280
                                        int32_t aSrcLen, int32_t* aOutLen)
281
0
{
282
0
  NS_ASSERTION(aDestBreaks != eLinebreakAny &&
283
0
               aSrcBreaks != eLinebreakSpace, "Invalid parameter");
284
0
  if (!aSrc) {
285
0
    return nullptr;
286
0
  }
287
0
288
0
  int32_t sourceLen = (aSrcLen == kIgnoreLen) ? strlen(aSrc) + 1 : aSrcLen;
289
0
290
0
  char* resultString;
291
0
  if (aSrcBreaks == eLinebreakAny) {
292
0
    resultString = ConvertUnknownBreaks(aSrc, sourceLen,
293
0
                                        GetLinebreakString(aDestBreaks));
294
0
  } else
295
0
    resultString = ConvertBreaks(aSrc, sourceLen,
296
0
                                 GetLinebreakString(aSrcBreaks),
297
0
                                 GetLinebreakString(aDestBreaks));
298
0
299
0
  if (aOutLen) {
300
0
    *aOutLen = sourceLen;
301
0
  }
302
0
  return resultString;
303
0
}
304
305
306
/*----------------------------------------------------------------------------
307
  ConvertLineBreaksInSitu
308
309
----------------------------------------------------------------------------*/
310
nsresult
311
nsLinebreakConverter::ConvertLineBreaksInSitu(char** aIoBuffer,
312
                                              ELinebreakType aSrcBreaks,
313
                                              ELinebreakType aDestBreaks,
314
                                              int32_t aSrcLen, int32_t* aOutLen)
315
0
{
316
0
  NS_ASSERTION(aIoBuffer && *aIoBuffer, "Null pointer passed");
317
0
  if (!aIoBuffer || !*aIoBuffer) {
318
0
    return NS_ERROR_NULL_POINTER;
319
0
  }
320
0
321
0
  NS_ASSERTION(aDestBreaks != eLinebreakAny &&
322
0
               aSrcBreaks != eLinebreakSpace, "Invalid parameter");
323
0
324
0
  int32_t sourceLen = (aSrcLen == kIgnoreLen) ? strlen(*aIoBuffer) + 1 : aSrcLen;
325
0
326
0
  // can we convert in-place?
327
0
  const char* srcBreaks = GetLinebreakString(aSrcBreaks);
328
0
  const char* dstBreaks = GetLinebreakString(aDestBreaks);
329
0
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
0
    }
337
0
  } else {
338
0
    char* destBuffer;
339
0
340
0
    if (aSrcBreaks == eLinebreakAny) {
341
0
      destBuffer = ConvertUnknownBreaks(*aIoBuffer, sourceLen, dstBreaks);
342
0
    } else {
343
0
      destBuffer = ConvertBreaks(*aIoBuffer, sourceLen, srcBreaks, dstBreaks);
344
0
    }
345
0
346
0
    if (!destBuffer) {
347
0
      return NS_ERROR_OUT_OF_MEMORY;
348
0
    }
349
0
    *aIoBuffer = destBuffer;
350
0
    if (aOutLen) {
351
0
      *aOutLen = sourceLen;
352
0
    }
353
0
  }
354
0
355
0
  return NS_OK;
356
0
}
357
358
359
/*----------------------------------------------------------------------------
360
  ConvertUnicharLineBreaks
361
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)
369
0
{
370
0
  NS_ASSERTION(aDestBreaks != eLinebreakAny &&
371
0
               aSrcBreaks != eLinebreakSpace, "Invalid parameter");
372
0
  if (!aSrc) {
373
0
    return nullptr;
374
0
  }
375
0
376
0
  int32_t bufLen = (aSrcLen == kIgnoreLen) ? NS_strlen(aSrc) + 1 : aSrcLen;
377
0
378
0
  char16_t* resultString;
379
0
  if (aSrcBreaks == eLinebreakAny) {
380
0
    resultString = ConvertUnknownBreaks(aSrc, bufLen,
381
0
                                        GetLinebreakString(aDestBreaks));
382
0
  } else
383
0
    resultString = ConvertBreaks(aSrc, bufLen, GetLinebreakString(aSrcBreaks),
384
0
                                 GetLinebreakString(aDestBreaks));
385
0
386
0
  if (aOutLen) {
387
0
    *aOutLen = bufLen;
388
0
  }
389
0
  return resultString;
390
0
}
391
392
393
/*----------------------------------------------------------------------------
394
  ConvertStringLineBreaks
395
396
----------------------------------------------------------------------------*/
397
nsresult
398
nsLinebreakConverter::ConvertUnicharLineBreaksInSitu(
399
    char16_t** aIoBuffer, ELinebreakType aSrcBreaks, ELinebreakType aDestBreaks,
400
    int32_t aSrcLen, int32_t* aOutLen)
401
0
{
402
0
  NS_ASSERTION(aIoBuffer && *aIoBuffer, "Null pointer passed");
403
0
  if (!aIoBuffer || !*aIoBuffer) {
404
0
    return NS_ERROR_NULL_POINTER;
405
0
  }
406
0
  NS_ASSERTION(aDestBreaks != eLinebreakAny &&
407
0
               aSrcBreaks != eLinebreakSpace, "Invalid parameter");
408
0
409
0
  int32_t sourceLen =
410
0
    (aSrcLen == kIgnoreLen) ? NS_strlen(*aIoBuffer) + 1 : aSrcLen;
411
0
412
0
  // can we convert in-place?
413
0
  const char* srcBreaks = GetLinebreakString(aSrcBreaks);
414
0
  const char* dstBreaks = GetLinebreakString(aDestBreaks);
415
0
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
0
    }
423
0
  } else {
424
0
    char16_t* destBuffer;
425
0
426
0
    if (aSrcBreaks == eLinebreakAny) {
427
0
      destBuffer = ConvertUnknownBreaks(*aIoBuffer, sourceLen, dstBreaks);
428
0
    } else {
429
0
      destBuffer = ConvertBreaks(*aIoBuffer, sourceLen, srcBreaks, dstBreaks);
430
0
    }
431
0
432
0
    if (!destBuffer) {
433
0
      return NS_ERROR_OUT_OF_MEMORY;
434
0
    }
435
0
    *aIoBuffer = destBuffer;
436
0
    if (aOutLen) {
437
0
      *aOutLen = sourceLen;
438
0
    }
439
0
  }
440
0
441
0
  return NS_OK;
442
0
}
443
444
/*----------------------------------------------------------------------------
445
  ConvertStringLineBreaks
446
447
----------------------------------------------------------------------------*/
448
nsresult
449
nsLinebreakConverter::ConvertStringLineBreaks(nsString& aIoString,
450
                                              ELinebreakType aSrcBreaks,
451
                                              ELinebreakType aDestBreaks)
452
0
{
453
0
454
0
  NS_ASSERTION(aDestBreaks != eLinebreakAny &&
455
0
               aSrcBreaks != eLinebreakSpace, "Invalid parameter");
456
0
457
0
  // nothing to do
458
0
  if (aIoString.IsEmpty()) {
459
0
    return NS_OK;
460
0
  }
461
0
462
0
  nsresult rv;
463
0
464
0
  // remember the old buffer in case
465
0
  // we blow it away later
466
0
  auto stringBuf = aIoString.BeginWriting(mozilla::fallible);
467
0
  if (!stringBuf) {
468
0
    return NS_ERROR_OUT_OF_MEMORY;
469
0
  }
470
0
471
0
  int32_t    newLen;
472
0
473
0
  rv = ConvertUnicharLineBreaksInSitu(&stringBuf,
474
0
                                      aSrcBreaks, aDestBreaks,
475
0
                                      aIoString.Length() + 1, &newLen);
476
0
  if (NS_FAILED(rv)) {
477
0
    return rv;
478
0
  }
479
0
480
0
  if (stringBuf != aIoString.get()) {
481
0
    aIoString.Adopt(stringBuf, newLen - 1);
482
0
  }
483
0
484
0
  return NS_OK;
485
0
}
486
487
488