Coverage Report

Created: 2026-10-28 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libcdr/src/lib/libcdr_utils.cpp
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/*
3
 * This file is part of the libcdr project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 */
9
10
#include "libcdr_utils.h"
11
12
#include <cassert>
13
#include <cstdarg>
14
#include <cstdio>
15
#include <string.h>
16
17
#include <unicode/ucsdet.h>
18
#include <unicode/ucnv.h>
19
#include <unicode/utypes.h>
20
#include <unicode/utf8.h>
21
22
#define CDR_NUM_ELEMENTS(array) sizeof(array)/sizeof(array[0])
23
24
#define SURROGATE_VALUE(h,l) (((h) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000)
25
26
namespace
27
{
28
29
static unsigned short getEncodingFromICUName(const char *name)
30
479k
{
31
  // ANSI
32
479k
  if (strcmp(name, "ISO-8859-1") == 0)
33
21.0k
    return 0;
34
458k
  if (strcmp(name, "windows-1252") == 0)
35
2.15k
    return 0;
36
  // CENTRAL EUROPE
37
455k
  if (strcmp(name, "ISO-8859-2") == 0)
38
8.14k
    return 0xee;
39
447k
  if (strcmp(name, "windows-1250") == 0)
40
1.09k
    return 0xee;
41
  // RUSSIAN
42
446k
  if (strcmp(name, "ISO-8859-5") == 0)
43
1.33k
    return 0xcc;
44
445k
  if (strcmp(name, "windows-1251") == 0)
45
814
    return 0xcc;
46
444k
  if (strcmp(name, "KOI8-R") == 0)
47
800
    return 0xcc;
48
  // ARABIC
49
443k
  if (strcmp(name, "ISO-8859-6") == 0)
50
110
    return 0xb2;
51
443k
  if (strcmp(name, "windows-1256") == 0)
52
123
    return 0xb2;
53
  // TURKISH
54
443k
  if (strcmp(name, "ISO-8859-9") == 0)
55
361
    return 0xa2;
56
443k
  if (strcmp(name, "windows-1254") == 0)
57
115
    return 0xa2;
58
  // GREEK
59
442k
  if (strcmp(name, "ISO-8859-7") == 0)
60
950
    return 0xa1;
61
442k
  if (strcmp(name, "windows-1253") == 0)
62
498
    return 0xa1;
63
  // HEBREW
64
441k
  if (strcmp(name, "ISO-8859-8") == 0)
65
732
    return 0xb1;
66
440k
  if (strcmp(name, "windows-1255") == 0)
67
531
    return 0xb1;
68
  // JAPANESE
69
440k
  if (strcmp(name, "Shift_JIS") == 0)
70
8.69k
    return 0x80;
71
431k
  if (strcmp(name, "ISO-2022-JP") == 0)
72
5
    return 0x80;
73
431k
  if (strcmp(name, "EUC-JP") == 0)
74
4.25k
    return 0x80;
75
427k
  if (strcmp(name, "windows-932") == 0)
76
0
    return 0x80;
77
  // KOREAN
78
427k
  if (strcmp(name, "ISO-2022-KR") == 0)
79
0
    return 0x81;
80
427k
  if (strcmp(name, "EUC-KR") == 0)
81
310
    return 0x81;
82
426k
  if (strcmp(name, "windows-949") == 0)
83
0
    return 0x81;
84
  // CHINESE SIMPLIFIED
85
426k
  if (strcmp(name, "ISO-2022-CN") == 0)
86
625
    return 0x86;
87
426k
  if (strcmp(name, "GB18030") == 0)
88
9.64k
    return 0x86;
89
416k
  if (strcmp(name, "windows-936") == 0)
90
0
    return 0x86;
91
  // CHINESE TRADITIONAL
92
416k
  if (strcmp(name, "Big5") == 0)
93
91
    return 0x88;
94
416k
  if (strcmp(name, "windows-950") == 0)
95
0
    return 0x88;
96
97
416k
  return 0;
98
416k
}
99
100
static unsigned short getEncoding(const unsigned char *buffer, unsigned long bufferLength)
101
510k
{
102
510k
  if (!buffer)
103
0
    return 0;
104
510k
  UErrorCode status = U_ZERO_ERROR;
105
510k
  UCharsetDetector *csd = nullptr;
106
510k
  try
107
510k
  {
108
510k
    csd = ucsdet_open(&status);
109
510k
    if (U_FAILURE(status) || !csd)
110
0
      return 0;
111
510k
    ucsdet_enableInputFilter(csd, true);
112
510k
    ucsdet_setText(csd, (const char *)buffer, (unsigned)bufferLength, &status);
113
510k
    if (U_FAILURE(status))
114
0
      throw libcdr::EncodingException();
115
510k
    const UCharsetMatch *csm = ucsdet_detect(csd, &status);
116
510k
    if (U_FAILURE(status) || !csm)
117
31.6k
      throw libcdr::EncodingException();
118
479k
    const char *name = ucsdet_getName(csm, &status);
119
479k
    if (U_FAILURE(status) || !name)
120
0
      throw libcdr::EncodingException();
121
479k
    int32_t confidence = ucsdet_getConfidence(csm, &status);
122
479k
    if (U_FAILURE(status))
123
0
      throw libcdr::EncodingException();
124
479k
    CDR_DEBUG_MSG(("UCSDET: getEncoding name %s, confidence %i\n", name, confidence));
125
479k
    unsigned short encoding = getEncodingFromICUName(name);
126
479k
    ucsdet_close(csd);
127
    /* From ICU documentation
128
     * A confidence value of ten does have a general meaning - it is used
129
     * for charsets that can represent the input data, but for which there
130
     * is no other indication that suggests that the charset is the correct
131
     * one. Pure 7 bit ASCII data, for example, is compatible with a great
132
     * many charsets, most of which will appear as possible matches with
133
     * a confidence of 10.
134
     */
135
479k
    if (confidence == 10)
136
35.6k
      return 0;
137
443k
    return encoding;
138
479k
  }
139
510k
  catch (const libcdr::EncodingException &)
140
510k
  {
141
31.6k
    ucsdet_close(csd);
142
31.6k
    return 0;
143
31.6k
  }
144
510k
}
145
146
static void _appendUCS4(librevenge::RVNGString &text, UChar32 ucs4Character)
147
15.8M
{
148
  // Convert carriage returns to new line characters
149
  // Writerperfect/LibreOffice will replace them by <text:line-break>
150
15.8M
  if (ucs4Character == (UChar32) 0x0d)
151
4.35k
    ucs4Character = (UChar32) '\n';
152
153
15.8M
  unsigned char outbuf[U8_MAX_LENGTH+1];
154
15.8M
  int i = 0;
155
15.8M
  U8_APPEND_UNSAFE(&outbuf[0], i, ucs4Character);
156
15.8M
  outbuf[i] = 0;
157
158
15.8M
  text.append((char *)outbuf);
159
15.8M
}
160
161
} // anonymous namespace
162
163
uint8_t libcdr::readU8(librevenge::RVNGInputStream *input, bool /* bigEndian */)
164
114M
{
165
114M
  if (!input || input->isEnd())
166
19.6k
  {
167
19.6k
    CDR_DEBUG_MSG(("Throwing EndOfStreamException\n"));
168
19.6k
    throw EndOfStreamException();
169
19.6k
  }
170
114M
  unsigned long numBytesRead;
171
114M
  uint8_t const *p = input->read(sizeof(uint8_t), numBytesRead);
172
173
114M
  if (p && numBytesRead == sizeof(uint8_t))
174
114M
    return *(uint8_t const *)(p);
175
0
  CDR_DEBUG_MSG(("Throwing EndOfStreamException\n"));
176
0
  throw EndOfStreamException();
177
114M
}
178
179
uint16_t libcdr::readU16(librevenge::RVNGInputStream *input, bool bigEndian)
180
340M
{
181
340M
  if (!input || input->isEnd())
182
16.4k
  {
183
16.4k
    CDR_DEBUG_MSG(("Throwing EndOfStreamException\n"));
184
16.4k
    throw EndOfStreamException();
185
16.4k
  }
186
340M
  unsigned long numBytesRead;
187
340M
  uint8_t const *p = input->read(sizeof(uint16_t), numBytesRead);
188
189
340M
  if (p && numBytesRead == sizeof(uint16_t))
190
340M
  {
191
340M
    if (bigEndian)
192
538
      return (uint16_t)(p[1]|((uint16_t)p[0]<<8));
193
340M
    return (uint16_t)(p[0]|((uint16_t)p[1]<<8));
194
340M
  }
195
13.1k
  CDR_DEBUG_MSG(("Throwing EndOfStreamException\n"));
196
13.1k
  throw EndOfStreamException();
197
340M
}
198
199
int16_t libcdr::readS16(librevenge::RVNGInputStream *input, bool bigEndian)
200
16.4M
{
201
16.4M
  return (int16_t)readU16(input, bigEndian);
202
16.4M
}
203
204
uint32_t libcdr::readU32(librevenge::RVNGInputStream *input, bool bigEndian)
205
70.0M
{
206
70.0M
  if (!input || input->isEnd())
207
62.4k
  {
208
62.4k
    CDR_DEBUG_MSG(("Throwing EndOfStreamException\n"));
209
62.4k
    throw EndOfStreamException();
210
62.4k
  }
211
70.0M
  unsigned long numBytesRead;
212
70.0M
  uint8_t const *p = input->read(sizeof(uint32_t), numBytesRead);
213
214
70.0M
  if (p && numBytesRead == sizeof(uint32_t))
215
69.9M
  {
216
69.9M
    if (bigEndian)
217
1.06k
      return (uint32_t)p[3]|((uint32_t)p[2]<<8)|((uint32_t)p[1]<<16)|((uint32_t)p[0]<<24);
218
69.9M
    return (uint32_t)p[0]|((uint32_t)p[1]<<8)|((uint32_t)p[2]<<16)|((uint32_t)p[3]<<24);
219
69.9M
  }
220
24.8k
  CDR_DEBUG_MSG(("Throwing EndOfStreamException\n"));
221
24.8k
  throw EndOfStreamException();
222
70.0M
}
223
224
int32_t libcdr::readS32(librevenge::RVNGInputStream *input, bool bigEndian)
225
16.8M
{
226
16.8M
  return (int32_t)readU32(input, bigEndian);
227
16.8M
}
228
229
uint64_t libcdr::readU64(librevenge::RVNGInputStream *input, bool bigEndian)
230
4.58M
{
231
4.58M
  if (!input || input->isEnd())
232
33
  {
233
33
    CDR_DEBUG_MSG(("Throwing EndOfStreamException\n"));
234
33
    throw EndOfStreamException();
235
33
  }
236
4.58M
  unsigned long numBytesRead;
237
4.58M
  uint8_t const *p = input->read(sizeof(uint64_t), numBytesRead);
238
239
4.58M
  if (p && numBytesRead == sizeof(uint64_t))
240
4.58M
  {
241
4.58M
    if (bigEndian)
242
130
      return (uint64_t)p[7]|((uint64_t)p[6]<<8)|((uint64_t)p[5]<<16)|((uint64_t)p[4]<<24)|((uint64_t)p[3]<<32)|((uint64_t)p[2]<<40)|((uint64_t)p[1]<<48)|((uint64_t)p[0]<<56);
243
4.58M
    return (uint64_t)p[0]|((uint64_t)p[1]<<8)|((uint64_t)p[2]<<16)|((uint64_t)p[3]<<24)|((uint64_t)p[4]<<32)|((uint64_t)p[5]<<40)|((uint64_t)p[6]<<48)|((uint64_t)p[7]<<56);
244
4.58M
  }
245
62
  CDR_DEBUG_MSG(("Throwing EndOfStreamException\n"));
246
62
  throw EndOfStreamException();
247
4.58M
}
248
249
double libcdr::readDouble(librevenge::RVNGInputStream *input, bool bigEndian)
250
1.69M
{
251
1.69M
  union
252
1.69M
  {
253
1.69M
    uint64_t u;
254
1.69M
    double d;
255
1.69M
  } tmpUnion;
256
257
1.69M
  tmpUnion.u = readU64(input, bigEndian);
258
259
1.69M
  return tmpUnion.d;
260
1.69M
}
261
262
double libcdr::readFixedPoint(librevenge::RVNGInputStream *input, bool bigEndian)
263
83.7k
{
264
83.7k
  unsigned fixedPointNumber = readU32(input, bigEndian);
265
83.7k
  auto fixedPointNumberIntegerPart = (short)((fixedPointNumber & 0xFFFF0000) >> 16);
266
83.7k
  auto fixedPointNumberFractionalPart = (double)((double)(fixedPointNumber & 0x0000FFFF)/(double)0xFFFF);
267
83.7k
  return ((double)fixedPointNumberIntegerPart + fixedPointNumberFractionalPart);
268
83.7k
}
269
270
unsigned long libcdr::getLength(librevenge::RVNGInputStream *const input)
271
3.95M
{
272
3.95M
  if (!input)
273
0
    throw EndOfStreamException();
274
275
3.95M
  const long orig = input->tell();
276
3.95M
  long end = 0;
277
278
3.95M
  if (input->seek(0, librevenge::RVNG_SEEK_END) == 0)
279
3.95M
  {
280
3.95M
    end = input->tell();
281
3.95M
  }
282
0
  else
283
0
  {
284
    // RVNG_SEEK_END does not work. Use the harder way.
285
0
    if (input->seek(0, librevenge::RVNG_SEEK_SET) != 0)
286
0
      throw EndOfStreamException();
287
0
    while (!input->isEnd())
288
0
    {
289
0
      readU8(input);
290
0
      ++end;
291
0
    }
292
0
  }
293
3.95M
  assert(end >= 0);
294
295
3.95M
  if (input->seek(orig, librevenge::RVNG_SEEK_SET) != 0)
296
0
    throw EndOfStreamException();
297
298
3.95M
  return static_cast<unsigned long>(end);
299
3.95M
}
300
301
unsigned long libcdr::getRemainingLength(librevenge::RVNGInputStream *const input)
302
3.86M
{
303
3.86M
  return getLength(input) - static_cast<unsigned long>(input->tell());
304
3.86M
}
305
306
int libcdr::cdr_round(double d)
307
5.16M
{
308
5.16M
  return (d>0) ? int(d+0.5) : int(d-0.5);
309
5.16M
}
310
311
void libcdr::writeU16(librevenge::RVNGBinaryData &buffer, const int value)
312
48.4k
{
313
48.4k
  buffer.append((unsigned char)(value & 0xFF));
314
48.4k
  buffer.append((unsigned char)((value >> 8) & 0xFF));
315
48.4k
}
316
317
void libcdr::writeU32(librevenge::RVNGBinaryData &buffer, const int value)
318
29.4M
{
319
29.4M
  buffer.append((unsigned char)(value & 0xFF));
320
29.4M
  buffer.append((unsigned char)((value >> 8) & 0xFF));
321
29.4M
  buffer.append((unsigned char)((value >> 16) & 0xFF));
322
29.4M
  buffer.append((unsigned char)((value >> 24) & 0xFF));
323
29.4M
}
324
325
void libcdr::appendCharacters(librevenge::RVNGString &text, std::vector<unsigned char> characters, unsigned short charset)
326
3.44M
{
327
3.44M
  if (characters.empty())
328
5.52k
    return;
329
3.43M
  static const UChar32 symbolmap [] =
330
3.43M
  {
331
3.43M
    0x0020, 0x0021, 0x2200, 0x0023, 0x2203, 0x0025, 0x0026, 0x220D, // 0x20 ..
332
3.43M
    0x0028, 0x0029, 0x2217, 0x002B, 0x002C, 0x2212, 0x002E, 0x002F,
333
3.43M
    0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
334
3.43M
    0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
335
3.43M
    0x2245, 0x0391, 0x0392, 0x03A7, 0x0394, 0x0395, 0x03A6, 0x0393,
336
3.43M
    0x0397, 0x0399, 0x03D1, 0x039A, 0x039B, 0x039C, 0x039D, 0x039F,
337
3.43M
    0x03A0, 0x0398, 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03C2, 0x03A9,
338
3.43M
    0x039E, 0x03A8, 0x0396, 0x005B, 0x2234, 0x005D, 0x22A5, 0x005F,
339
3.43M
    0xF8E5, 0x03B1, 0x03B2, 0x03C7, 0x03B4, 0x03B5, 0x03C6, 0x03B3,
340
3.43M
    0x03B7, 0x03B9, 0x03D5, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BF,
341
3.43M
    0x03C0, 0x03B8, 0x03C1, 0x03C3, 0x03C4, 0x03C5, 0x03D6, 0x03C9,
342
3.43M
    0x03BE, 0x03C8, 0x03B6, 0x007B, 0x007C, 0x007D, 0x223C, 0x0020, // .. 0x7F
343
3.43M
    0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
344
3.43M
    0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
345
3.43M
    0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
346
3.43M
    0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009E, 0x009f,
347
3.43M
    0x20AC, 0x03D2, 0x2032, 0x2264, 0x2044, 0x221E, 0x0192, 0x2663, // 0xA0 ..
348
3.43M
    0x2666, 0x2665, 0x2660, 0x2194, 0x2190, 0x2191, 0x2192, 0x2193,
349
3.43M
    0x00B0, 0x00B1, 0x2033, 0x2265, 0x00D7, 0x221D, 0x2202, 0x2022,
350
3.43M
    0x00F7, 0x2260, 0x2261, 0x2248, 0x2026, 0x23D0, 0x23AF, 0x21B5,
351
3.43M
    0x2135, 0x2111, 0x211C, 0x2118, 0x2297, 0x2295, 0x2205, 0x2229,
352
3.43M
    0x222A, 0x2283, 0x2287, 0x2284, 0x2282, 0x2286, 0x2208, 0x2209,
353
3.43M
    0x2220, 0x2207, 0x00AE, 0x00A9, 0x2122, 0x220F, 0x221A, 0x22C5,
354
3.43M
    0x00AC, 0x2227, 0x2228, 0x21D4, 0x21D0, 0x21D1, 0x21D2, 0x21D3,
355
3.43M
    0x25CA, 0x3008, 0x00AE, 0x00A9, 0x2122, 0x2211, 0x239B, 0x239C,
356
3.43M
    0x239D, 0x23A1, 0x23A2, 0x23A3, 0x23A7, 0x23A8, 0x23A9, 0x23AA,
357
3.43M
    0xF8FF, 0x3009, 0x222B, 0x2320, 0x23AE, 0x2321, 0x239E, 0x239F,
358
3.43M
    0x23A0, 0x23A4, 0x23A5, 0x23A6, 0x23AB, 0x23AC, 0x23AD, 0x0020  // .. 0xFE
359
3.43M
  };
360
361
3.43M
  if (!charset && !characters.empty())
362
510k
    charset = getEncoding(&characters[0], characters.size());
363
364
3.43M
  if (charset == 0x02) // SYMBOL
365
792
  {
366
792
    uint32_t ucs4Character = 0;
367
792
    for (std::vector<unsigned char>::const_iterator iter = characters.begin();
368
3.50k
         iter != characters.end(); ++iter)
369
2.71k
    {
370
2.71k
      if (*iter < 0x20)
371
842
        ucs4Character = 0x20;
372
1.86k
      else
373
1.86k
        ucs4Character = symbolmap[*iter - 0x20];
374
2.71k
      _appendUCS4(text, ucs4Character);
375
2.71k
    }
376
792
  }
377
3.43M
  else
378
3.43M
  {
379
3.43M
    UErrorCode status = U_ZERO_ERROR;
380
3.43M
    UConverter *conv = nullptr;
381
3.43M
    switch (charset)
382
3.43M
    {
383
1.97k
    case 0x80: // SHIFTJIS
384
1.97k
      conv = ucnv_open("windows-932", &status);
385
1.97k
      break;
386
841
    case 0x81: // HANGUL
387
841
      conv = ucnv_open("windows-949", &status);
388
841
      break;
389
880
    case 0x86: // GB2312
390
880
      conv = ucnv_open("windows-936", &status);
391
880
      break;
392
1.95k
    case 0x88: // CHINESEBIG5
393
1.95k
      conv = ucnv_open("windows-950", &status);
394
1.95k
      break;
395
1.75k
    case 0xa1: // GREEEK
396
1.75k
      conv = ucnv_open("windows-1253", &status);
397
1.75k
      break;
398
668
    case 0xa2: // TURKISH
399
668
      conv = ucnv_open("windows-1254", &status);
400
668
      break;
401
2.77k
    case 0xa3: // VIETNAMESE
402
2.77k
      conv = ucnv_open("windows-1258", &status);
403
2.77k
      break;
404
1.27k
    case 0xb1: // HEBREW
405
1.27k
      conv = ucnv_open("windows-1255", &status);
406
1.27k
      break;
407
630
    case 0xb2: // ARABIC
408
630
      conv = ucnv_open("windows-1256", &status);
409
630
      break;
410
201
    case 0xba: // BALTIC
411
201
      conv = ucnv_open("windows-1257", &status);
412
201
      break;
413
3.84k
    case 0xcc: // RUSSIAN
414
3.84k
      conv = ucnv_open("windows-1251", &status);
415
3.84k
      break;
416
239
    case 0xde: // THAI
417
239
      conv = ucnv_open("windows-874", &status);
418
239
      break;
419
9.23k
    case 0xee: // CENTRAL EUROPE
420
9.23k
      conv = ucnv_open("windows-1250", &status);
421
9.23k
      break;
422
3.40M
    default:
423
3.40M
      conv = ucnv_open("windows-1252", &status);
424
3.40M
      break;
425
3.43M
    }
426
3.43M
    if (U_SUCCESS(status) && conv)
427
3.43M
    {
428
3.43M
      const auto *src = (const char *)&characters[0];
429
3.43M
      const char *srcLimit = (const char *)src + characters.size();
430
13.2M
      while (src < srcLimit)
431
9.86M
      {
432
9.86M
        UChar32 ucs4Character = ucnv_getNextUChar(conv, &src, srcLimit, &status);
433
9.86M
        if (U_SUCCESS(status) && U_IS_UNICODE_CHAR(ucs4Character))
434
9.86M
          _appendUCS4(text, ucs4Character);
435
9.86M
      }
436
3.43M
    }
437
3.43M
    if (conv)
438
3.43M
      ucnv_close(conv);
439
3.43M
  }
440
3.43M
}
441
442
void libcdr::appendCharacters(librevenge::RVNGString &text, std::vector<unsigned char> characters)
443
1.09M
{
444
1.09M
  if (characters.empty())
445
8.16k
    return;
446
447
1.08M
  UErrorCode status = U_ZERO_ERROR;
448
1.08M
  UConverter *conv = ucnv_open("UTF-16LE", &status);
449
450
1.08M
  if (U_SUCCESS(status) && conv)
451
1.08M
  {
452
1.08M
    const auto *src = (const char *)&characters[0];
453
1.08M
    const char *srcLimit = (const char *)src + characters.size();
454
7.31M
    while (src < srcLimit)
455
6.22M
    {
456
6.22M
      UChar32 ucs4Character = ucnv_getNextUChar(conv, &src, srcLimit, &status);
457
6.22M
      if (U_SUCCESS(status) && U_IS_UNICODE_CHAR(ucs4Character))
458
6.00M
        _appendUCS4(text, ucs4Character);
459
6.22M
    }
460
1.08M
  }
461
1.08M
  if (conv)
462
1.08M
    ucnv_close(conv);
463
1.08M
}
464
465
void libcdr::appendUTF8Characters(librevenge::RVNGString &text, std::vector<unsigned char> characters)
466
35.8k
{
467
35.8k
  if (characters.empty())
468
25.6k
    return;
469
470
45.7M
  for (std::vector<unsigned char>::const_iterator iter = characters.begin(); iter != characters.end(); ++iter)
471
45.7M
    text.append((char)*iter);
472
10.2k
}
473
474
#ifdef DEBUG
475
476
void libcdr::debugPrint(const char *const format, ...)
477
{
478
  va_list args;
479
  va_start(args, format);
480
  std::vfprintf(stderr, format, args);
481
  va_end(args);
482
}
483
484
const char *libcdr::toFourCC(unsigned value, bool bigEndian)
485
{
486
  static char sValue[5] = { 0, 0, 0, 0, 0 };
487
  if (bigEndian)
488
  {
489
    sValue[3] = (char)(value & 0xff);
490
    sValue[2] = (char)((value & 0xff00) >> 8);
491
    sValue[1] = (char)((value & 0xff0000) >> 16);
492
    sValue[0] = (char)((value & 0xff000000) >> 24);
493
  }
494
  else
495
  {
496
    sValue[0] = (char)(value & 0xff);
497
    sValue[1] = (char)((value & 0xff00) >> 8);
498
    sValue[2] = (char)((value & 0xff0000) >> 16);
499
    sValue[3] = (char)((value & 0xff000000) >> 24);
500
  }
501
  return sValue;
502
}
503
#endif
504
505
/* vim:set shiftwidth=2 softtabstop=2 expandtab: */