Coverage Report

Created: 2026-10-28 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/port/cpl_recode_stub.cpp
Line
Count
Source
1
/**********************************************************************
2
 *
3
 * Name:     cpl_recode_stub.cpp
4
 * Project:  CPL - Common Portability Library
5
 * Purpose:  Character set recoding and char/wchar_t conversions, stub
6
 *           implementation to be used if iconv() functionality is not
7
 *           available.
8
 * Author:   Frank Warmerdam, warmerdam@pobox.com
9
 *
10
 * The bulk of this code is derived from the utf.c module from FLTK. It
11
 * was originally downloaded from:
12
 *    http://svn.easysw.com/public/fltk/fltk/trunk/src/utf.c
13
 *
14
 **********************************************************************
15
 * Copyright (c) 2008, Frank Warmerdam
16
 * Copyright 2006 by Bill Spitzak and others.
17
 * Copyright (c) 2009-2014, Even Rouault <even dot rouault at spatialys.com>
18
 *
19
 * Permission to use, copy, modify, and distribute this software for any
20
 * purpose with or without fee is hereby granted, provided that the above
21
 * copyright notice and this permission notice appear in all copies.
22
 *
23
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
24
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
25
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
26
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
27
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
28
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
29
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30
 **********************************************************************/
31
32
#include "cpl_port.h"
33
#include "cpl_string.h"
34
35
#include <cstring>
36
37
#include "cpl_conv.h"
38
#include "cpl_error.h"
39
#include "cpl_character_sets.c"
40
41
static unsigned utf8decode(const char *p, const char *end, int *len);
42
static unsigned utf8towc(const char *src, unsigned srclen, wchar_t *dst,
43
                         unsigned dstlen);
44
static unsigned utf8toa(const char *src, unsigned srclen, char *dst,
45
                        unsigned dstlen);
46
static unsigned utf8fromwc(char *dst, unsigned dstlen, const wchar_t *src,
47
                           unsigned srclen);
48
static unsigned utf8froma(char *dst, unsigned dstlen, const char *src,
49
                          unsigned srclen);
50
static int utf8test(const char *src, unsigned srclen);
51
52
#ifdef _WIN32
53
54
#include <windows.h>
55
#include <winnls.h>
56
57
static char *CPLWin32Recode(const char *src, unsigned src_code_page,
58
                            unsigned dst_code_page) CPL_RETURNS_NONNULL;
59
#endif
60
61
/* used by cpl_recode.cpp */
62
extern void CPLClearRecodeStubWarningFlags();
63
extern char *CPLRecodeStub(const char *, const char *,
64
                           const char *) CPL_RETURNS_NONNULL;
65
extern char *CPLRecodeFromWCharStub(const wchar_t *, const char *,
66
                                    const char *);
67
extern wchar_t *CPLRecodeToWCharStub(const char *, const char *, const char *);
68
69
/************************************************************************/
70
/* ==================================================================== */
71
/*      Stub Implementation not depending on iconv() or WIN32 API.      */
72
/* ==================================================================== */
73
/************************************************************************/
74
75
static bool bHaveWarned1 = false;
76
static bool bHaveWarned2 = false;
77
static bool bHaveWarned3 = false;
78
static bool bHaveWarned4 = false;
79
#ifdef _WIN32
80
static bool bHaveWarned5 = false;
81
static bool bHaveWarned6 = false;
82
#endif
83
84
/************************************************************************/
85
/*                   CPLClearRecodeStubWarningFlags()                   */
86
/************************************************************************/
87
88
void CPLClearRecodeStubWarningFlags()
89
0
{
90
0
    bHaveWarned1 = false;
91
0
    bHaveWarned2 = false;
92
0
    bHaveWarned3 = false;
93
0
    bHaveWarned4 = false;
94
#ifdef _WIN32
95
    bHaveWarned5 = false;
96
    bHaveWarned6 = false;
97
#endif
98
0
}
99
100
/************************************************************************/
101
/*                           CPLRecodeStub()                            */
102
/************************************************************************/
103
104
/**
105
 * Convert a string from a source encoding to a destination encoding.
106
 *
107
 * The only guaranteed supported encodings are CPL_ENC_UTF8, CPL_ENC_ASCII
108
 * and CPL_ENC_ISO8859_1. Currently, the following conversions are supported :
109
 * <ul>
110
 *  <li>CPL_ENC_ASCII -> CPL_ENC_UTF8 or CPL_ENC_ISO8859_1 (no conversion in
111
 *  fact)</li>
112
 *  <li>CPL_ENC_ISO8859_1 -> CPL_ENC_UTF8</li>
113
 *  <li>CPL_ENC_UTF8 -> CPL_ENC_ISO8859_1</li>
114
 * </ul>
115
 *
116
 * If an error occurs an error may, or may not be posted with CPLError().
117
 *
118
 * @param pszSource a NULL terminated string.
119
 * @param pszSrcEncoding the source encoding.
120
 * @param pszDstEncoding the destination encoding.
121
 *
122
 * @return a NULL terminated string which should be freed with CPLFree().
123
 */
124
125
char *CPLRecodeStub(const char *pszSource, const char *pszSrcEncoding,
126
                    const char *pszDstEncoding)
127
128
0
{
129
    /* -------------------------------------------------------------------- */
130
    /*      If the source or destination is current locale(), we change     */
131
    /*      it to ISO8859-1 since our stub implementation does not          */
132
    /*      attempt to address locales properly.                            */
133
    /* -------------------------------------------------------------------- */
134
135
0
    if (pszSrcEncoding[0] == '\0')
136
0
        pszSrcEncoding = CPL_ENC_ISO8859_1;
137
138
0
    if (pszDstEncoding[0] == '\0')
139
0
        pszDstEncoding = CPL_ENC_ISO8859_1;
140
141
    /* -------------------------------------------------------------------- */
142
    /*      ISO8859 to UTF8                                                 */
143
    /* -------------------------------------------------------------------- */
144
0
    if (strcmp(pszSrcEncoding, CPL_ENC_ISO8859_1) == 0 &&
145
0
        strcmp(pszDstEncoding, CPL_ENC_UTF8) == 0)
146
0
    {
147
0
        const int nCharCount = static_cast<int>(strlen(pszSource));
148
0
        char *pszResult = static_cast<char *>(CPLCalloc(1, nCharCount * 2 + 1));
149
150
0
        utf8froma(pszResult, nCharCount * 2 + 1, pszSource, nCharCount);
151
152
0
        return pszResult;
153
0
    }
154
155
    /* -------------------------------------------------------------------- */
156
    /*      UTF8 to ISO8859                                                 */
157
    /* -------------------------------------------------------------------- */
158
0
    if (strcmp(pszSrcEncoding, CPL_ENC_UTF8) == 0 &&
159
0
        strcmp(pszDstEncoding, CPL_ENC_ISO8859_1) == 0)
160
0
    {
161
0
        int nCharCount = static_cast<int>(strlen(pszSource));
162
0
        char *pszResult = static_cast<char *>(CPLCalloc(1, nCharCount + 1));
163
164
0
        utf8toa(pszSource, nCharCount, pszResult, nCharCount + 1);
165
166
0
        return pszResult;
167
0
    }
168
169
    // A few hard coded CPxxx/ISO-8859-x to UTF-8 tables
170
0
    if (EQUAL(pszDstEncoding, CPL_ENC_UTF8))
171
0
    {
172
0
        const auto pConvTable = CPLGetConversionTableToUTF8(pszSrcEncoding);
173
0
        if (pConvTable)
174
0
        {
175
0
            const auto convTable = *pConvTable;
176
0
            const size_t nCharCount = strlen(pszSource);
177
0
            char *pszResult =
178
0
                static_cast<char *>(CPLCalloc(1, nCharCount * 3 + 1));
179
0
            size_t iDst = 0;
180
0
            unsigned char *pabyResult =
181
0
                reinterpret_cast<unsigned char *>(pszResult);
182
0
            for (size_t i = 0; i < nCharCount; ++i)
183
0
            {
184
0
                const unsigned char nChar =
185
0
                    static_cast<unsigned char>(pszSource[i]);
186
0
                if (nChar <= 127)
187
0
                {
188
0
                    pszResult[iDst] = pszSource[i];
189
0
                    ++iDst;
190
0
                }
191
0
                else
192
0
                {
193
0
                    const unsigned char nShiftedChar = nChar - 128;
194
0
                    if (convTable[nShiftedChar][0])
195
0
                    {
196
0
                        pabyResult[iDst] = convTable[nShiftedChar][0];
197
0
                        ++iDst;
198
0
                        CPLAssert(convTable[nShiftedChar][1]);
199
0
                        pabyResult[iDst] = convTable[nShiftedChar][1];
200
0
                        ++iDst;
201
0
                        if (convTable[nShiftedChar][2])
202
0
                        {
203
0
                            pabyResult[iDst] = convTable[nShiftedChar][2];
204
0
                            ++iDst;
205
0
                        }
206
0
                    }
207
0
                    else
208
0
                    {
209
                        // Skip the invalid sequence in the input string.
210
0
                        if (!bHaveWarned2)
211
0
                        {
212
0
                            bHaveWarned2 = true;
213
0
                            CPLError(CE_Warning, CPLE_AppDefined,
214
0
                                     "One or several characters couldn't be "
215
0
                                     "converted correctly from %s to %s. "
216
0
                                     "This warning will not be emitted anymore",
217
0
                                     pszSrcEncoding, pszDstEncoding);
218
0
                        }
219
0
                    }
220
0
                }
221
0
            }
222
223
0
            pszResult[iDst] = 0;
224
0
            return pszResult;
225
0
        }
226
0
    }
227
228
#ifdef _WIN32
229
    const auto MapEncodingToWindowsCodePage = [](const char *pszEncoding)
230
    {
231
        // Cf https://learn.microsoft.com/fr-fr/windows/win32/intl/code-page-identifiers
232
        if (STARTS_WITH(pszEncoding, "CP"))
233
        {
234
            const int nCode = atoi(pszEncoding + strlen("CP"));
235
            if (nCode > 0)
236
                return nCode;
237
            else if (EQUAL(pszEncoding, "CP_OEMCP"))
238
                return CP_OEMCP;
239
            else if (EQUAL(pszEncoding, "CP_ACP"))
240
                return CP_ACP;
241
        }
242
        else if (STARTS_WITH(pszEncoding, "WINDOWS-"))
243
        {
244
            const int nCode = atoi(pszEncoding + strlen("WINDOWS-"));
245
            if (nCode > 0)
246
                return nCode;
247
        }
248
        else if (STARTS_WITH(pszEncoding, "ISO-8859-"))
249
        {
250
            const int nCode = atoi(pszEncoding + strlen("ISO-8859-"));
251
            if ((nCode >= 1 && nCode <= 9) || nCode == 13 || nCode == 15)
252
                return 28590 + nCode;
253
        }
254
255
        // Return a negative value, since CP_ACP = 0
256
        return -1;
257
    };
258
259
    /* ---------------------------------------------------------------------*/
260
    /*     XXX to UTF8                                                      */
261
    /* ---------------------------------------------------------------------*/
262
    if (strcmp(pszDstEncoding, CPL_ENC_UTF8) == 0)
263
    {
264
        const int nCode = MapEncodingToWindowsCodePage(pszSrcEncoding);
265
        if (nCode >= 0)
266
        {
267
            return CPLWin32Recode(pszSource, nCode, CP_UTF8);
268
        }
269
    }
270
271
    /* ---------------------------------------------------------------------*/
272
    /*      UTF8 to XXX                                                     */
273
    /* ---------------------------------------------------------------------*/
274
    if (strcmp(pszSrcEncoding, CPL_ENC_UTF8) == 0)
275
    {
276
        const int nCode = MapEncodingToWindowsCodePage(pszDstEncoding);
277
        if (nCode >= 0)
278
        {
279
            return CPLWin32Recode(pszSource, CP_UTF8, nCode);
280
        }
281
    }
282
#endif
283
284
    /* -------------------------------------------------------------------- */
285
    /*      Anything else to UTF-8 is treated as ISO8859-1 to UTF-8 with    */
286
    /*      a one-time warning.                                             */
287
    /* -------------------------------------------------------------------- */
288
0
    if (strcmp(pszDstEncoding, CPL_ENC_UTF8) == 0)
289
0
    {
290
0
        const int nCharCount = static_cast<int>(strlen(pszSource));
291
0
        char *pszResult = static_cast<char *>(CPLCalloc(1, nCharCount * 2 + 1));
292
293
0
        if (!bHaveWarned1)
294
0
        {
295
0
            bHaveWarned1 = true;
296
0
            CPLError(CE_Warning, CPLE_AppDefined,
297
0
                     "Recode from %s to UTF-8 not supported, "
298
0
                     "treated as ISO-8859-1 to UTF-8.",
299
0
                     pszSrcEncoding);
300
0
        }
301
302
0
        utf8froma(pszResult, nCharCount * 2 + 1, pszSource, nCharCount);
303
304
0
        return pszResult;
305
0
    }
306
307
    /* -------------------------------------------------------------------- */
308
    /*      Everything else is treated as a no-op with a warning.           */
309
    /* -------------------------------------------------------------------- */
310
0
    {
311
0
        if (!bHaveWarned3)
312
0
        {
313
0
            bHaveWarned3 = true;
314
0
            CPLError(CE_Warning, CPLE_AppDefined,
315
0
                     "Recode from %s to %s not supported, no change applied.",
316
0
                     pszSrcEncoding, pszDstEncoding);
317
0
        }
318
319
0
        return CPLStrdup(pszSource);
320
0
    }
321
0
}
322
323
/************************************************************************/
324
/*                       CPLRecodeFromWCharStub()                       */
325
/************************************************************************/
326
327
/**
328
 * Convert wchar_t string to UTF-8.
329
 *
330
 * Convert a wchar_t string into a multibyte utf-8 string.  The only
331
 * guaranteed supported source encoding is CPL_ENC_UCS2, and the only
332
 * guaranteed supported destination encodings are CPL_ENC_UTF8, CPL_ENC_ASCII
333
 * and CPL_ENC_ISO8859_1.  In some cases (i.e. using iconv()) other encodings
334
 * may also be supported.
335
 *
336
 * Note that the wchar_t type varies in size on different systems. On
337
 * win32 it is normally 2 bytes, and on unix 4 bytes.
338
 *
339
 * If an error occurs an error may, or may not be posted with CPLError().
340
 *
341
 * @param pwszSource the source wchar_t string, terminated with a 0 wchar_t.
342
 * @param pszSrcEncoding the source encoding, typically CPL_ENC_UCS2.
343
 * @param pszDstEncoding the destination encoding, typically CPL_ENC_UTF8.
344
 *
345
 * @return a zero terminated multi-byte string which should be freed with
346
 * CPLFree(), or NULL if an error occurs.
347
 */
348
349
char *CPLRecodeFromWCharStub(const wchar_t *pwszSource,
350
                             const char *pszSrcEncoding,
351
                             const char *pszDstEncoding)
352
353
5.08k
{
354
    /* -------------------------------------------------------------------- */
355
    /*      We try to avoid changes of character set.  We are just          */
356
    /*      providing for unicode to unicode.                               */
357
    /* -------------------------------------------------------------------- */
358
5.08k
    if (strcmp(pszSrcEncoding, "WCHAR_T") != 0 &&
359
0
        strcmp(pszSrcEncoding, CPL_ENC_UTF8) != 0 &&
360
0
        strcmp(pszSrcEncoding, CPL_ENC_UTF16) != 0 &&
361
0
        strcmp(pszSrcEncoding, CPL_ENC_UCS2) != 0 &&
362
0
        strcmp(pszSrcEncoding, CPL_ENC_UCS4) != 0)
363
0
    {
364
0
        CPLError(CE_Failure, CPLE_AppDefined,
365
0
                 "Stub recoding implementation does not support "
366
0
                 "CPLRecodeFromWCharStub(...,%s,%s)",
367
0
                 pszSrcEncoding, pszDstEncoding);
368
0
        return nullptr;
369
0
    }
370
371
    /* -------------------------------------------------------------------- */
372
    /*      What is the source length.                                      */
373
    /* -------------------------------------------------------------------- */
374
5.08k
    int nSrcLen = 0;
375
376
7.92k
    while (pwszSource[nSrcLen] != 0)
377
2.84k
        nSrcLen++;
378
379
    /* -------------------------------------------------------------------- */
380
    /*      Allocate destination buffer plenty big.                         */
381
    /* -------------------------------------------------------------------- */
382
5.08k
    const int nDstBufSize = nSrcLen * 4 + 1;
383
    // Nearly worst case.
384
5.08k
    char *pszResult = static_cast<char *>(CPLMalloc(nDstBufSize));
385
386
5.08k
    if (nSrcLen == 0)
387
2.23k
    {
388
2.23k
        pszResult[0] = '\0';
389
2.23k
        return pszResult;
390
2.23k
    }
391
392
    /* -------------------------------------------------------------------- */
393
    /*      Convert, and confirm we had enough space.                       */
394
    /* -------------------------------------------------------------------- */
395
2.84k
    const int nDstLen = utf8fromwc(pszResult, nDstBufSize, pwszSource, nSrcLen);
396
2.84k
    if (nDstLen >= nDstBufSize)
397
0
    {
398
0
        CPLAssert(false);  // too small!
399
0
        return nullptr;
400
0
    }
401
402
    /* -------------------------------------------------------------------- */
403
    /*      If something other than UTF-8 was requested, recode now.        */
404
    /* -------------------------------------------------------------------- */
405
2.84k
    if (strcmp(pszDstEncoding, CPL_ENC_UTF8) == 0)
406
2.84k
        return pszResult;
407
408
0
    char *pszFinalResult =
409
0
        CPLRecodeStub(pszResult, CPL_ENC_UTF8, pszDstEncoding);
410
411
0
    CPLFree(pszResult);
412
413
0
    return pszFinalResult;
414
2.84k
}
415
416
/************************************************************************/
417
/*                        CPLRecodeToWCharStub()                        */
418
/************************************************************************/
419
420
/**
421
 * Convert UTF-8 string to a wchar_t string.
422
 *
423
 * Convert a 8bit, multi-byte per character input string into a wide
424
 * character (wchar_t) string.  The only guaranteed supported source encodings
425
 * are CPL_ENC_UTF8, CPL_ENC_ASCII and CPL_ENC_ISO8869_1 (LATIN1).  The only
426
 * guaranteed supported destination encoding is CPL_ENC_UCS2.  Other source
427
 * and destination encodings may be supported depending on the underlying
428
 * implementation.
429
 *
430
 * Note that the wchar_t type varies in size on different systems. On
431
 * win32 it is normally 2 bytes, and on unix 4 bytes.
432
 *
433
 * If an error occurs an error may, or may not be posted with CPLError().
434
 *
435
 * @param pszSource input multi-byte character string.
436
 * @param pszSrcEncoding source encoding, typically CPL_ENC_UTF8.
437
 * @param pszDstEncoding destination encoding, typically CPL_ENC_UCS2.
438
 *
439
 * @return the zero terminated wchar_t string (to be freed with CPLFree()) or
440
 * NULL on error.
441
 *
442
 */
443
444
wchar_t *CPLRecodeToWCharStub(const char *pszSource, const char *pszSrcEncoding,
445
                              const char *pszDstEncoding)
446
447
0
{
448
0
    char *pszUTF8Source = const_cast<char *>(pszSource);
449
450
0
    if (strcmp(pszSrcEncoding, CPL_ENC_UTF8) != 0 &&
451
0
        strcmp(pszSrcEncoding, CPL_ENC_ASCII) != 0)
452
0
    {
453
0
        pszUTF8Source = CPLRecodeStub(pszSource, pszSrcEncoding, CPL_ENC_UTF8);
454
0
        if (pszUTF8Source == nullptr)
455
0
            return nullptr;
456
0
    }
457
458
    /* -------------------------------------------------------------------- */
459
    /*      We try to avoid changes of character set.  We are just          */
460
    /*      providing for unicode to unicode.                               */
461
    /* -------------------------------------------------------------------- */
462
0
    if (strcmp(pszDstEncoding, "WCHAR_T") != 0 &&
463
0
        strcmp(pszDstEncoding, CPL_ENC_UCS2) != 0 &&
464
0
        strcmp(pszDstEncoding, CPL_ENC_UCS4) != 0 &&
465
0
        strcmp(pszDstEncoding, CPL_ENC_UTF16) != 0)
466
0
    {
467
0
        CPLError(CE_Failure, CPLE_AppDefined,
468
0
                 "Stub recoding implementation does not support "
469
0
                 "CPLRecodeToWCharStub(...,%s,%s)",
470
0
                 pszSrcEncoding, pszDstEncoding);
471
0
        if (pszUTF8Source != pszSource)
472
0
            CPLFree(pszUTF8Source);
473
0
        return nullptr;
474
0
    }
475
476
    /* -------------------------------------------------------------------- */
477
    /*      Do the UTF-8 to UCS-2 recoding.                                 */
478
    /* -------------------------------------------------------------------- */
479
0
    int nSrcLen = static_cast<int>(strlen(pszUTF8Source));
480
0
    wchar_t *pwszResult =
481
0
        static_cast<wchar_t *>(CPLCalloc(sizeof(wchar_t), nSrcLen + 1));
482
483
0
    utf8towc(pszUTF8Source, nSrcLen, pwszResult, nSrcLen + 1);
484
485
0
    if (pszUTF8Source != pszSource)
486
0
        CPLFree(pszUTF8Source);
487
488
0
    return pwszResult;
489
0
}
490
491
/************************************************************************/
492
/*                             CPLIsUTF8()                              */
493
/************************************************************************/
494
495
/**
496
 * Test if a string is encoded as UTF-8.
497
 *
498
 * @param pabyData input string to test
499
 * @param nLen length of the input string, or -1 if the function must compute
500
 *             the string length. In which case it must be null terminated.
501
 * @return TRUE if the string is encoded as UTF-8. FALSE otherwise
502
 *
503
 */
504
int CPLIsUTF8(const char *pabyData, int nLen)
505
0
{
506
0
    if (nLen < 0)
507
0
        nLen = static_cast<int>(strlen(pabyData));
508
0
    return utf8test(pabyData, static_cast<unsigned>(nLen)) != 0;
509
0
}
510
511
/************************************************************************/
512
/* ==================================================================== */
513
/*      UTF.C code from FLTK with some modifications.                   */
514
/* ==================================================================== */
515
/************************************************************************/
516
517
/* Set to 1 to turn bad UTF8 bytes into ISO-8859-1. If this is to zero
518
   they are instead turned into the Unicode REPLACEMENT CHARACTER, of
519
   value 0xfffd.
520
   If this is on utf8decode will correctly map most (perhaps all)
521
   human-readable text that is in ISO-8859-1. This may allow you
522
   to completely ignore character sets in your code because virtually
523
   everything is either ISO-8859-1 or UTF-8.
524
*/
525
#define ERRORS_TO_ISO8859_1 1
526
527
/* Set to 1 to turn bad UTF8 bytes in the 0x80-0x9f range into the
528
   Unicode index for Microsoft's CP1252 character set. You should
529
   also set ERRORS_TO_ISO8859_1. With this a huge amount of more
530
   available text (such as all web pages) are correctly converted
531
   to Unicode.
532
*/
533
#define ERRORS_TO_CP1252 1
534
535
/* A number of Unicode code points are in fact illegal and should not
536
   be produced by a UTF-8 converter. Turn this on will replace the
537
   bytes in those encodings with errors. If you do this then converting
538
   arbitrary 16-bit data to UTF-8 and then back is not an identity,
539
   which will probably break a lot of software.
540
*/
541
#define STRICT_RFC3629 0
542
543
#if ERRORS_TO_CP1252
544
// Codes 0x80..0x9f from the Microsoft CP1252 character set, translated
545
// to Unicode:
546
constexpr unsigned short cp1252[32] = {
547
    0x20ac, 0x0081, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
548
    0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008d, 0x017d, 0x008f,
549
    0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
550
    0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x009d, 0x017e, 0x0178};
551
#endif
552
553
/************************************************************************/
554
/*                             utf8decode()                             */
555
/************************************************************************/
556
557
/*
558
    Decode a single UTF-8 encoded character starting at \e p. The
559
    resulting Unicode value (in the range 0-0x10ffff) is returned,
560
    and \e len is set the number of bytes in the UTF-8 encoding
561
    (adding \e len to \e p will point at the next character).
562
563
    If \a p points at an illegal UTF-8 encoding, including one that
564
    would go past \e end, or where a code is uses more bytes than
565
    necessary, then *reinterpret_cast<const unsigned char*>(p) is translated as
566
though it is in the Microsoft CP1252 character set and \e len is set to 1.
567
    Treating errors this way allows this to decode almost any
568
    ISO-8859-1 or CP1252 text that has been mistakenly placed where
569
    UTF-8 is expected, and has proven very useful.
570
571
    If you want errors to be converted to error characters (as the
572
    standards recommend), adding a test to see if the length is
573
    unexpectedly 1 will work:
574
575
\code
576
    if( *p & 0x80 )
577
    {  // What should be a multibyte encoding.
578
      code = utf8decode(p, end, &len);
579
      if( len<2 ) code = 0xFFFD;  // Turn errors into REPLACEMENT CHARACTER.
580
    }
581
    else
582
    {  // Handle the 1-byte utf8 encoding:
583
      code = *p;
584
      len = 1;
585
    }
586
\endcode
587
588
    Direct testing for the 1-byte case (as shown above) will also
589
    speed up the scanning of strings where the majority of characters
590
    are ASCII.
591
*/
592
static unsigned utf8decode(const char *p, const char *end, int *len)
593
0
{
594
0
    unsigned char c = *reinterpret_cast<const unsigned char *>(p);
595
0
    if (c < 0x80)
596
0
    {
597
0
        *len = 1;
598
0
        return c;
599
0
#if ERRORS_TO_CP1252
600
0
    }
601
0
    else if (c < 0xa0)
602
0
    {
603
0
        *len = 1;
604
0
        return cp1252[c - 0x80];
605
0
#endif
606
0
    }
607
0
    else if (c < 0xc2)
608
0
    {
609
0
        goto FAIL;
610
0
    }
611
0
    if (p + 1 >= end || (p[1] & 0xc0) != 0x80)
612
0
        goto FAIL;
613
0
    if (c < 0xe0)
614
0
    {
615
0
        *len = 2;
616
0
        return ((p[0] & 0x1f) << 6) + ((p[1] & 0x3f));
617
0
    }
618
0
    else if (c == 0xe0)
619
0
    {
620
0
        if ((reinterpret_cast<const unsigned char *>(p))[1] < 0xa0)
621
0
            goto FAIL;
622
0
        goto UTF8_3;
623
#if STRICT_RFC3629
624
    }
625
    else if (c == 0xed)
626
    {
627
        // RFC 3629 says surrogate chars are illegal.
628
        if ((reinterpret_cast<const unsigned char *>(p))[1] >= 0xa0)
629
            goto FAIL;
630
        goto UTF8_3;
631
    }
632
    else if (c == 0xef)
633
    {
634
        // 0xfffe and 0xffff are also illegal characters.
635
        if ((reinterpret_cast<const unsigned char *>(p))[1] == 0xbf &&
636
            (reinterpret_cast<const unsigned char *>(p))[2] >= 0xbe)
637
            goto FAIL;
638
        goto UTF8_3;
639
#endif
640
0
    }
641
0
    else if (c < 0xf0)
642
0
    {
643
0
    UTF8_3:
644
0
        if (p + 2 >= end || (p[2] & 0xc0) != 0x80)
645
0
            goto FAIL;
646
0
        *len = 3;
647
0
        return ((p[0] & 0x0f) << 12) + ((p[1] & 0x3f) << 6) + ((p[2] & 0x3f));
648
0
    }
649
0
    else if (c == 0xf0)
650
0
    {
651
0
        if ((reinterpret_cast<const unsigned char *>(p))[1] < 0x90)
652
0
            goto FAIL;
653
0
        goto UTF8_4;
654
0
    }
655
0
    else if (c < 0xf4)
656
0
    {
657
0
    UTF8_4:
658
0
        if (p + 3 >= end || (p[2] & 0xc0) != 0x80 || (p[3] & 0xc0) != 0x80)
659
0
            goto FAIL;
660
0
        *len = 4;
661
#if STRICT_RFC3629
662
        // RFC 3629 says all codes ending in fffe or ffff are illegal:
663
        if ((p[1] & 0xf) == 0xf &&
664
            (reinterpret_cast<const unsigned char *>(p))[2] == 0xbf &&
665
            (reinterpret_cast<const unsigned char *>(p))[3] >= 0xbe)
666
            goto FAIL;
667
#endif
668
0
        return ((p[0] & 0x07) << 18) + ((p[1] & 0x3f) << 12) +
669
0
               ((p[2] & 0x3f) << 6) + ((p[3] & 0x3f));
670
0
    }
671
0
    else if (c == 0xf4)
672
0
    {
673
0
        if ((reinterpret_cast<const unsigned char *>(p))[1] > 0x8f)
674
0
            goto FAIL;  // After 0x10ffff.
675
0
        goto UTF8_4;
676
0
    }
677
0
    else
678
0
    {
679
0
    FAIL:
680
0
        *len = 1;
681
0
#if ERRORS_TO_ISO8859_1
682
0
        return c;
683
#else
684
        return 0xfffd;  // Unicode REPLACEMENT CHARACTER
685
#endif
686
0
    }
687
0
}
688
689
/************************************************************************/
690
/*                              utf8towc()                              */
691
/************************************************************************/
692
693
/*  Convert a UTF-8 sequence into an array of wchar_t. These
694
    are used by some system calls, especially on Windows.
695
696
    \a src points at the UTF-8, and \a srclen is the number of bytes to
697
    convert.
698
699
    \a dst points at an array to write, and \a dstlen is the number of
700
    locations in this array. At most \a dstlen-1 words will be
701
    written there, plus a 0 terminating word. Thus this function
702
    will never overwrite the buffer and will always return a
703
    zero-terminated string. If \a dstlen is zero then \a dst can be
704
    null and no data is written, but the length is returned.
705
706
    The return value is the number of words that \e would be written
707
    to \a dst if it were long enough, not counting the terminating
708
    zero. If the return value is greater or equal to \a dstlen it
709
    indicates truncation, you can then allocate a new array of size
710
    return+1 and call this again.
711
712
    Errors in the UTF-8 are converted as though each byte in the
713
    erroneous string is in the Microsoft CP1252 encoding. This allows
714
    ISO-8859-1 text mistakenly identified as UTF-8 to be printed
715
    correctly.
716
717
    Notice that sizeof(wchar_t) is 2 on Windows and is 4 on Linux
718
    and most other systems. Where wchar_t is 16 bits, Unicode
719
    characters in the range 0x10000 to 0x10ffff are converted to
720
    "surrogate pairs" which take two words each (this is called UTF-16
721
    encoding). If wchar_t is 32 bits this rather nasty problem is
722
    avoided.
723
*/
724
static unsigned utf8towc(const char *src, unsigned srclen, wchar_t *dst,
725
                         unsigned dstlen)
726
0
{
727
0
    const char *p = src;
728
0
    const char *e = src + srclen;
729
0
    unsigned count = 0;
730
0
    if (dstlen)
731
0
        while (true)
732
0
        {
733
0
            if (p >= e)
734
0
            {
735
0
                dst[count] = 0;
736
0
                return count;
737
0
            }
738
0
            if (!(*p & 0x80))
739
0
            {
740
                // ASCII
741
0
                dst[count] = *p++;
742
0
            }
743
0
            else
744
0
            {
745
0
                int len = 0;
746
0
                unsigned ucs = utf8decode(p, e, &len);
747
0
                p += len;
748
#ifdef _WIN32
749
                if (ucs < 0x10000)
750
                {
751
                    dst[count] = static_cast<wchar_t>(ucs);
752
                }
753
                else
754
                {
755
                    // Make a surrogate pair:
756
                    if (count + 2 >= dstlen)
757
                    {
758
                        dst[count] = 0;
759
                        count += 2;
760
                        break;
761
                    }
762
                    dst[count] = static_cast<wchar_t>(
763
                        (((ucs - 0x10000u) >> 10) & 0x3ff) | 0xd800);
764
                    dst[++count] = static_cast<wchar_t>((ucs & 0x3ff) | 0xdc00);
765
                }
766
#else
767
0
                dst[count] = static_cast<wchar_t>(ucs);
768
0
#endif
769
0
            }
770
0
            if (++count == dstlen)
771
0
            {
772
0
                dst[count - 1] = 0;
773
0
                break;
774
0
            }
775
0
        }
776
    // We filled dst, measure the rest:
777
0
    while (p < e)
778
0
    {
779
0
        if (!(*p & 0x80))
780
0
        {
781
0
            p++;
782
0
        }
783
0
        else
784
0
        {
785
0
            int len = 0;
786
#ifdef _WIN32
787
            const unsigned ucs = utf8decode(p, e, &len);
788
            p += len;
789
            if (ucs >= 0x10000)
790
                ++count;
791
#else
792
0
            utf8decode(p, e, &len);
793
0
            p += len;
794
0
#endif
795
0
        }
796
0
        ++count;
797
0
    }
798
799
0
    return count;
800
0
}
801
802
/************************************************************************/
803
/*                              utf8toa()                               */
804
/************************************************************************/
805
/* Convert a UTF-8 sequence into an array of 1-byte characters.
806
807
    If the UTF-8 decodes to a character greater than 0xff then it is
808
    replaced with '?'.
809
810
    Errors in the UTF-8 are converted as individual bytes, same as
811
    utf8decode() does. This allows ISO-8859-1 text mistakenly identified
812
    as UTF-8 to be printed correctly (and possibly CP1252 on Windows).
813
814
    \a src points at the UTF-8, and \a srclen is the number of bytes to
815
    convert.
816
817
    Up to \a dstlen bytes are written to \a dst, including a null
818
    terminator. The return value is the number of bytes that would be
819
    written, not counting the null terminator. If greater or equal to
820
    \a dstlen then if you malloc a new array of size n+1 you will have
821
    the space needed for the entire string. If \a dstlen is zero then
822
    nothing is written and this call just measures the storage space
823
    needed.
824
*/
825
static unsigned int utf8toa(const char *src, unsigned srclen, char *dst,
826
                            unsigned dstlen)
827
0
{
828
0
    const char *p = src;
829
0
    const char *e = src + srclen;
830
0
    unsigned int count = 0;
831
0
    if (dstlen)
832
0
        while (true)
833
0
        {
834
0
            if (p >= e)
835
0
            {
836
0
                dst[count] = 0;
837
0
                return count;
838
0
            }
839
0
            unsigned char c = *reinterpret_cast<const unsigned char *>(p);
840
0
            if (c < 0xC2)
841
0
            {
842
                // ASCII or bad code.
843
0
                dst[count] = c;
844
0
                p++;
845
0
            }
846
0
            else
847
0
            {
848
0
                int len = 0;
849
0
                const unsigned int ucs = utf8decode(p, e, &len);
850
0
                p += len;
851
0
                if (ucs < 0x100)
852
0
                {
853
0
                    dst[count] = static_cast<char>(ucs);
854
0
                }
855
0
                else
856
0
                {
857
0
                    if (!bHaveWarned4)
858
0
                    {
859
0
                        bHaveWarned4 = true;
860
0
                        CPLError(
861
0
                            CE_Warning, CPLE_AppDefined,
862
0
                            "One or several characters couldn't be converted "
863
0
                            "correctly from UTF-8 to ISO-8859-1.  "
864
0
                            "This warning will not be emitted anymore.");
865
0
                    }
866
0
                    dst[count] = '?';
867
0
                }
868
0
            }
869
0
            if (++count >= dstlen)
870
0
            {
871
0
                dst[count - 1] = 0;
872
0
                break;
873
0
            }
874
0
        }
875
    // We filled dst, measure the rest:
876
0
    while (p < e)
877
0
    {
878
0
        if (!(*p & 0x80))
879
0
        {
880
0
            p++;
881
0
        }
882
0
        else
883
0
        {
884
0
            int len = 0;
885
0
            utf8decode(p, e, &len);
886
0
            p += len;
887
0
        }
888
0
        ++count;
889
0
    }
890
0
    return count;
891
0
}
892
893
/************************************************************************/
894
/*                             utf8fromwc()                             */
895
/************************************************************************/
896
/* Turn "wide characters" as returned by some system calls
897
    (especially on Windows) into UTF-8.
898
899
    Up to \a dstlen bytes are written to \a dst, including a null
900
    terminator. The return value is the number of bytes that would be
901
    written, not counting the null terminator. If greater or equal to
902
    \a dstlen then if you malloc a new array of size n+1 you will have
903
    the space needed for the entire string. If \a dstlen is zero then
904
    nothing is written and this call just measures the storage space
905
    needed.
906
907
    \a srclen is the number of words in \a src to convert. On Windows
908
    this is not necessarily the number of characters, due to there
909
    possibly being "surrogate pairs" in the UTF-16 encoding used.
910
    On Unix wchar_t is 32 bits and each location is a character.
911
912
    On Unix if a src word is greater than 0x10ffff then this is an
913
    illegal character according to RFC 3629. These are converted as
914
    though they are 0xFFFD (REPLACEMENT CHARACTER). Characters in the
915
    range 0xd800 to 0xdfff, or ending with 0xfffe or 0xffff are also
916
    illegal according to RFC 3629. However I encode these as though
917
    they are legal, so that utf8towc will return the original data.
918
919
    On Windows "surrogate pairs" are converted to a single character
920
    and UTF-8 encoded (as 4 bytes). Mismatched halves of surrogate
921
    pairs are converted as though they are individual characters.
922
*/
923
static unsigned int utf8fromwc(char *dst, unsigned dstlen, const wchar_t *src,
924
                               unsigned srclen)
925
2.84k
{
926
2.84k
    unsigned int i = 0;
927
2.84k
    unsigned int count = 0;
928
2.84k
    if (dstlen)
929
5.69k
        while (true)
930
5.69k
        {
931
5.69k
            if (i >= srclen)
932
2.84k
            {
933
2.84k
                dst[count] = 0;
934
2.84k
                return count;
935
2.84k
            }
936
2.84k
            unsigned int ucs = src[i++];
937
2.84k
            if (ucs < 0x80U)
938
1.43k
            {
939
1.43k
                dst[count++] = static_cast<char>(ucs);
940
1.43k
                if (count >= dstlen)
941
0
                {
942
0
                    dst[count - 1] = 0;
943
0
                    break;
944
0
                }
945
1.43k
            }
946
1.41k
            else if (ucs < 0x800U)
947
281
            {
948
                // 2 bytes.
949
281
                if (count + 2 >= dstlen)
950
0
                {
951
0
                    dst[count] = 0;
952
0
                    count += 2;
953
0
                    break;
954
0
                }
955
281
                dst[count++] = 0xc0 | static_cast<char>(ucs >> 6);
956
281
                dst[count++] = 0x80 | static_cast<char>(ucs & 0x3F);
957
#ifdef _WIN32
958
            }
959
            else if (ucs >= 0xd800 && ucs <= 0xdbff && i < srclen &&
960
                     src[i] >= 0xdc00 && src[i] <= 0xdfff)
961
            {
962
                // Surrogate pair.
963
                unsigned int ucs2 = src[i++];
964
                ucs = 0x10000U + ((ucs & 0x3ff) << 10) + (ucs2 & 0x3ff);
965
            // All surrogate pairs turn into 4-byte utf8.
966
#else
967
281
            }
968
1.12k
            else if (ucs >= 0x10000)
969
674
            {
970
674
                if (ucs > 0x10ffff)
971
274
                {
972
274
                    ucs = 0xfffd;
973
274
                    goto J1;
974
274
                }
975
400
#endif
976
400
                if (count + 4 >= dstlen)
977
0
                {
978
0
                    dst[count] = 0;
979
0
                    count += 4;
980
0
                    break;
981
0
                }
982
400
                dst[count++] = 0xf0 | static_cast<char>(ucs >> 18);
983
400
                dst[count++] = 0x80 | static_cast<char>((ucs >> 12) & 0x3F);
984
400
                dst[count++] = 0x80 | static_cast<char>((ucs >> 6) & 0x3F);
985
400
                dst[count++] = 0x80 | static_cast<char>(ucs & 0x3F);
986
400
            }
987
455
            else
988
455
            {
989
455
#ifndef _WIN32
990
729
            J1:
991
729
#endif
992
                // All others are 3 bytes:
993
729
                if (count + 3 >= dstlen)
994
0
                {
995
0
                    dst[count] = 0;
996
0
                    count += 3;
997
0
                    break;
998
0
                }
999
729
                dst[count++] = 0xe0 | static_cast<char>(ucs >> 12);
1000
729
                dst[count++] = 0x80 | static_cast<char>((ucs >> 6) & 0x3F);
1001
729
                dst[count++] = 0x80 | static_cast<char>(ucs & 0x3F);
1002
729
            }
1003
2.84k
        }
1004
1005
    // We filled dst, measure the rest:
1006
0
    while (i < srclen)
1007
0
    {
1008
0
        unsigned int ucs = src[i++];
1009
0
        if (ucs < 0x80U)
1010
0
        {
1011
0
            count++;
1012
0
        }
1013
0
        else if (ucs < 0x800U)
1014
0
        {
1015
            // 2 bytes.
1016
0
            count += 2;
1017
#ifdef _WIN32
1018
        }
1019
        else if (ucs >= 0xd800 && ucs <= 0xdbff && i < srclen - 1 &&
1020
                 src[i + 1] >= 0xdc00 && src[i + 1] <= 0xdfff)
1021
        {
1022
            // Surrogate pair.
1023
            ++i;
1024
#else
1025
0
        }
1026
0
        else if (ucs >= 0x10000 && ucs <= 0x10ffff)
1027
0
        {
1028
0
#endif
1029
0
            count += 4;
1030
0
        }
1031
0
        else
1032
0
        {
1033
0
            count += 3;
1034
0
        }
1035
0
    }
1036
0
    return count;
1037
2.84k
}
1038
1039
/************************************************************************/
1040
/*                             utf8froma()                              */
1041
/************************************************************************/
1042
1043
/* Convert an ISO-8859-1 (i.e. normal c-string) byte stream to UTF-8.
1044
1045
    It is possible this should convert Microsoft's CP1252 to UTF-8
1046
    instead. This would translate the codes in the range 0x80-0x9f
1047
    to different characters. Currently it does not do this.
1048
1049
    Up to \a dstlen bytes are written to \a dst, including a null
1050
    terminator. The return value is the number of bytes that would be
1051
    written, not counting the null terminator. If greater or equal to
1052
    \a dstlen then if you malloc a new array of size n+1 you will have
1053
    the space needed for the entire string. If \a dstlen is zero then
1054
    nothing is written and this call just measures the storage space
1055
    needed.
1056
1057
    \a srclen is the number of bytes in \a src to convert.
1058
1059
    If the return value equals \a srclen then this indicates that
1060
    no conversion is necessary, as only ASCII characters are in the
1061
    string.
1062
*/
1063
static unsigned utf8froma(char *dst, unsigned dstlen, const char *src,
1064
                          unsigned srclen)
1065
0
{
1066
0
    const char *p = src;
1067
0
    const char *e = src + srclen;
1068
0
    unsigned count = 0;
1069
0
    if (dstlen)
1070
0
        while (true)
1071
0
        {
1072
0
            if (p >= e)
1073
0
            {
1074
0
                dst[count] = 0;
1075
0
                return count;
1076
0
            }
1077
0
            unsigned char ucs = *reinterpret_cast<const unsigned char *>(p);
1078
0
            p++;
1079
0
            if (ucs < 0x80U)
1080
0
            {
1081
0
                dst[count++] = ucs;
1082
0
                if (count >= dstlen)
1083
0
                {
1084
0
                    dst[count - 1] = 0;
1085
0
                    break;
1086
0
                }
1087
0
            }
1088
0
            else
1089
0
            {
1090
                // 2 bytes (note that CP1252 translate could make 3 bytes!)
1091
0
                if (count + 2 >= dstlen)
1092
0
                {
1093
0
                    dst[count] = 0;
1094
0
                    count += 2;
1095
0
                    break;
1096
0
                }
1097
0
                dst[count++] = 0xc0 | (ucs >> 6);
1098
0
                dst[count++] = 0x80 | (ucs & 0x3F);
1099
0
            }
1100
0
        }
1101
1102
    // We filled dst, measure the rest:
1103
0
    while (p < e)
1104
0
    {
1105
0
        unsigned char ucs = *reinterpret_cast<const unsigned char *>(p);
1106
0
        p++;
1107
0
        if (ucs < 0x80U)
1108
0
        {
1109
0
            count++;
1110
0
        }
1111
0
        else
1112
0
        {
1113
0
            count += 2;
1114
0
        }
1115
0
    }
1116
1117
0
    return count;
1118
0
}
1119
1120
#ifdef _WIN32
1121
1122
/************************************************************************/
1123
/*                           CPLWin32Recode()                           */
1124
/************************************************************************/
1125
1126
/* Convert an CODEPAGE (i.e. normal c-string) byte stream
1127
     to another CODEPAGE (i.e. normal c-string) byte stream.
1128
1129
    \a src is target c-string byte stream (including a null terminator).
1130
    \a src_code_page is target c-string byte code page.
1131
    \a dst_code_page is destination c-string byte code page.
1132
1133
   UTF7          65000
1134
   UTF8          65001
1135
   OEM-US          437
1136
   OEM-ALABIC      720
1137
   OEM-GREEK       737
1138
   OEM-BALTIC      775
1139
   OEM-MLATIN1     850
1140
   OEM-LATIN2      852
1141
   OEM-CYRILLIC    855
1142
   OEM-TURKISH     857
1143
   OEM-MLATIN1P    858
1144
   OEM-HEBREW      862
1145
   OEM-RUSSIAN     866
1146
1147
   THAI            874
1148
   SJIS            932
1149
   GBK             936
1150
   KOREA           949
1151
   BIG5            950
1152
1153
   EUROPE         1250
1154
   CYRILLIC       1251
1155
   LATIN1         1252
1156
   GREEK          1253
1157
   TURKISH        1254
1158
   HEBREW         1255
1159
   ARABIC         1256
1160
   BALTIC         1257
1161
   VIETNAM        1258
1162
1163
   ISO-LATIN1    28591
1164
   ISO-LATIN2    28592
1165
   ISO-LATIN3    28593
1166
   ISO-BALTIC    28594
1167
   ISO-CYRILLIC  28595
1168
   ISO-ARABIC    28596
1169
   ISO-HEBREW    28598
1170
   ISO-TURKISH   28599
1171
   ISO-LATIN9    28605
1172
1173
   ISO-2022-JP   50220
1174
1175
*/
1176
1177
char *CPLWin32Recode(const char *src, unsigned src_code_page,
1178
                     unsigned dst_code_page)
1179
{
1180
    // Convert from source code page to Unicode.
1181
1182
    // Compute the length in wide characters.
1183
    int wlen = MultiByteToWideChar(src_code_page, MB_ERR_INVALID_CHARS, src, -1,
1184
                                   nullptr, 0);
1185
    if (wlen == 0 && GetLastError() == ERROR_NO_UNICODE_TRANSLATION)
1186
    {
1187
        if (!bHaveWarned5)
1188
        {
1189
            bHaveWarned5 = true;
1190
            CPLError(
1191
                CE_Warning, CPLE_AppDefined,
1192
                "One or several characters could not be translated from CP%d. "
1193
                "This warning will not be emitted anymore.",
1194
                src_code_page);
1195
        }
1196
1197
        // Retry now without MB_ERR_INVALID_CHARS flag.
1198
        wlen = MultiByteToWideChar(src_code_page, 0, src, -1, nullptr, 0);
1199
    }
1200
1201
    // Do the actual conversion.
1202
    wchar_t *tbuf =
1203
        static_cast<wchar_t *>(CPLCalloc(sizeof(wchar_t), wlen + 1));
1204
    tbuf[wlen] = 0;
1205
    MultiByteToWideChar(src_code_page, 0, src, -1, tbuf, wlen + 1);
1206
1207
    // Convert from Unicode to destination code page.
1208
1209
    // Compute the length in chars.
1210
    BOOL bUsedDefaultChar = FALSE;
1211
    int len = 0;
1212
    if (dst_code_page == CP_UTF7 || dst_code_page == CP_UTF8)
1213
        len = WideCharToMultiByte(dst_code_page, 0, tbuf, -1, nullptr, 0,
1214
                                  nullptr, nullptr);
1215
    else
1216
        len = WideCharToMultiByte(dst_code_page, 0, tbuf, -1, nullptr, 0,
1217
                                  nullptr, &bUsedDefaultChar);
1218
    if (bUsedDefaultChar)
1219
    {
1220
        if (!bHaveWarned6)
1221
        {
1222
            bHaveWarned6 = true;
1223
            CPLError(
1224
                CE_Warning, CPLE_AppDefined,
1225
                "One or several characters could not be translated to CP%d. "
1226
                "This warning will not be emitted anymore.",
1227
                dst_code_page);
1228
        }
1229
    }
1230
1231
    // Do the actual conversion.
1232
    char *pszResult = static_cast<char *>(CPLCalloc(sizeof(char), len + 1));
1233
    WideCharToMultiByte(dst_code_page, 0, tbuf, -1, pszResult, len + 1, nullptr,
1234
                        nullptr);
1235
    pszResult[len] = 0;
1236
1237
    CPLFree(tbuf);
1238
1239
    return pszResult;
1240
}
1241
1242
#endif
1243
1244
/*
1245
** For now we disable the rest which is locale() related.  We may need
1246
** parts of it later.
1247
*/
1248
1249
#ifdef notdef
1250
1251
#ifdef _WIN32
1252
#include <windows.h>
1253
#endif
1254
1255
/*! Return true if the "locale" seems to indicate that UTF-8 encoding
1256
    is used. If true the utf8tomb and utf8frommb don't do anything
1257
    useful.
1258
1259
    <i>It is highly recommended that you change your system so this
1260
    does return true.</i> On Windows this is done by setting the
1261
    "codepage" to CP_UTF8.  On Unix this is done by setting $LC_CTYPE
1262
    to a string containing the letters "utf" or "UTF" in it, or by
1263
    deleting all $LC* and $LANG environment variables. In the future
1264
    it is likely that all non-Asian Unix systems will return true,
1265
    due to the compatibility of UTF-8 with ISO-8859-1.
1266
*/
1267
int utf8locale(void)
1268
{
1269
    static int ret = 2;
1270
    if (ret == 2)
1271
    {
1272
#ifdef _WIN32
1273
        ret = GetACP() == CP_UTF8;
1274
#else
1275
        char *s;
1276
        ret = 1;  // assume UTF-8 if no locale
1277
        if (((s = getenv("LC_CTYPE")) && *s) ||
1278
            ((s = getenv("LC_ALL")) && *s) || ((s = getenv("LANG")) && *s))
1279
        {
1280
            ret = strstr(s, "utf") || strstr(s, "UTF");
1281
        }
1282
#endif
1283
    }
1284
1285
    return ret;
1286
}
1287
1288
/*! Convert the UTF-8 used by FLTK to the locale-specific encoding
1289
    used for filenames (and sometimes used for data in files).
1290
    Unfortunately due to stupid design you will have to do this as
1291
    needed for filenames. This is a bug on both Unix and Windows.
1292
1293
    Up to \a dstlen bytes are written to \a dst, including a null
1294
    terminator. The return value is the number of bytes that would be
1295
    written, not counting the null terminator. If greater or equal to
1296
    \a dstlen then if you malloc a new array of size n+1 you will have
1297
    the space needed for the entire string. If \a dstlen is zero then
1298
    nothing is written and this call just measures the storage space
1299
    needed.
1300
1301
    If utf8locale() returns true then this does not change the data.
1302
    It is copied and truncated as necessary to
1303
    the destination buffer and \a srclen is always returned.  */
1304
unsigned utf8tomb(const char *src, unsigned srclen, char *dst, unsigned dstlen)
1305
{
1306
    if (!utf8locale())
1307
    {
1308
#ifdef _WIN32
1309
        wchar_t lbuf[1024] = {};
1310
        wchar_t *buf = lbuf;
1311
        unsigned length = utf8towc(src, srclen, buf, 1024);
1312
        unsigned ret;
1313
        if (length >= 1024)
1314
        {
1315
            buf =
1316
                static_cast<wchar_t *>(malloc((length + 1) * sizeof(wchar_t)));
1317
            utf8towc(src, srclen, buf, length + 1);
1318
        }
1319
        if (dstlen)
1320
        {
1321
            // apparently this does not null-terminate, even though msdn
1322
            // documentation claims it does:
1323
            ret = WideCharToMultiByte(GetACP(), 0, buf, length, dst, dstlen, 0,
1324
                                      0);
1325
            dst[ret] = 0;
1326
        }
1327
        // if it overflows or measuring length, get the actual length:
1328
        if (dstlen == 0 || ret >= dstlen - 1)
1329
            ret = WideCharToMultiByte(GetACP(), 0, buf, length, 0, 0, 0, 0);
1330
        if (buf != lbuf)
1331
            free((void *)buf);
1332
        return ret;
1333
#else
1334
        wchar_t lbuf[1024] = {};
1335
        wchar_t *buf = lbuf;
1336
        unsigned length = utf8towc(src, srclen, buf, 1024);
1337
        if (length >= 1024)
1338
        {
1339
            buf =
1340
                static_cast<wchar_t *>(malloc((length + 1) * sizeof(wchar_t)));
1341
            utf8towc(src, srclen, buf, length + 1);
1342
        }
1343
        int ret = 0;
1344
        if (dstlen)
1345
        {
1346
            ret = wcstombs(dst, buf, dstlen);
1347
            if (ret >= dstlen - 1)
1348
                ret = wcstombs(0, buf, 0);
1349
        }
1350
        else
1351
        {
1352
            ret = wcstombs(0, buf, 0);
1353
        }
1354
        if (buf != lbuf)
1355
            free((void *)buf);
1356
        if (ret >= 0)
1357
            return (unsigned)ret;
1358
        // On any errors we return the UTF-8 as raw text...
1359
#endif
1360
    }
1361
    // Identity transform:
1362
    if (srclen < dstlen)
1363
    {
1364
        memcpy(dst, src, srclen);
1365
        dst[srclen] = 0;
1366
    }
1367
    else
1368
    {
1369
        memcpy(dst, src, dstlen - 1);
1370
        dst[dstlen - 1] = 0;
1371
    }
1372
    return srclen;
1373
}
1374
1375
/*! Convert a filename from the locale-specific multibyte encoding
1376
    used by Windows to UTF-8 as used by FLTK.
1377
1378
    Up to \a dstlen bytes are written to \a dst, including a null
1379
    terminator. The return value is the number of bytes that would be
1380
    written, not counting the null terminator. If greater or equal to
1381
    \a dstlen then if you malloc a new array of size n+1 you will have
1382
    the space needed for the entire string. If \a dstlen is zero then
1383
    nothing is written and this call just measures the storage space
1384
    needed.
1385
1386
    On Unix or on Windows when a UTF-8 locale is in effect, this
1387
    does not change the data. It is copied and truncated as necessary to
1388
    the destination buffer and \a srclen is always returned.
1389
    You may also want to check if utf8test() returns non-zero, so that
1390
    the filesystem can store filenames in UTF-8 encoding regardless of
1391
    the locale.
1392
*/
1393
unsigned utf8frommb(char *dst, unsigned dstlen, const char *src,
1394
                    unsigned srclen)
1395
{
1396
    if (!utf8locale())
1397
    {
1398
#ifdef _WIN32
1399
        wchar_t lbuf[1024] = {};
1400
        wchar_t *buf = lbuf;
1401
        unsigned ret;
1402
        const unsigned length =
1403
            MultiByteToWideChar(GetACP(), 0, src, srclen, buf, 1024);
1404
        if (length >= 1024)
1405
        {
1406
            length = MultiByteToWideChar(GetACP(), 0, src, srclen, 0, 0);
1407
            buf = static_cast<wchar_t *>(malloc(length * sizeof(wchar_t)));
1408
            MultiByteToWideChar(GetACP(), 0, src, srclen, buf, length);
1409
        }
1410
        ret = utf8fromwc(dst, dstlen, buf, length);
1411
        if (buf != lbuf)
1412
            free(buf);
1413
        return ret;
1414
#else
1415
        wchar_t lbuf[1024] = {};
1416
        wchar_t *buf = lbuf;
1417
        const int length = mbstowcs(buf, src, 1024);
1418
        if (length >= 1024)
1419
        {
1420
            length = mbstowcs(0, src, 0) + 1;
1421
            buf =
1422
                static_cast<wchar_t *>(malloc(length * sizeof(unsigned short)));
1423
            mbstowcs(buf, src, length);
1424
        }
1425
        if (length >= 0)
1426
        {
1427
            const unsigned ret = utf8fromwc(dst, dstlen, buf, length);
1428
            if (buf != lbuf)
1429
                free(buf);
1430
            return ret;
1431
        }
1432
        // Errors in conversion return the UTF-8 unchanged.
1433
#endif
1434
    }
1435
    // Identity transform:
1436
    if (srclen < dstlen)
1437
    {
1438
        memcpy(dst, src, srclen);
1439
        dst[srclen] = 0;
1440
    }
1441
    else
1442
    {
1443
        memcpy(dst, src, dstlen - 1);
1444
        dst[dstlen - 1] = 0;
1445
    }
1446
    return srclen;
1447
}
1448
1449
#endif  // def notdef - disabled locale specific stuff.
1450
1451
/*! Examines the first \a srclen bytes in \a src and return a verdict
1452
    on whether it is UTF-8 or not.
1453
    - Returns 0 if there is any illegal UTF-8 sequences, using the
1454
      same rules as utf8decode(). Note that some UCS values considered
1455
      illegal by RFC 3629, such as 0xffff, are considered legal by this.
1456
    - Returns 1 if there are only single-byte characters (i.e. no bytes
1457
      have the high bit set). This is legal UTF-8, but also indicates
1458
      plain ASCII. It also returns 1 if \a srclen is zero.
1459
    - Returns 2 if there are only characters less than 0x800.
1460
    - Returns 3 if there are only characters less than 0x10000.
1461
    - Returns 4 if there are characters in the 0x10000 to 0x10ffff range.
1462
1463
    Because there are many illegal sequences in UTF-8, it is almost
1464
    impossible for a string in another encoding to be confused with
1465
    UTF-8. This is very useful for transitioning Unix to UTF-8
1466
    filenames, you can simply test each filename with this to decide
1467
    if it is UTF-8 or in the locale encoding. My hope is that if
1468
    this is done we will be able to cleanly transition to a locale-less
1469
    encoding.
1470
*/
1471
1472
static int utf8test(const char *src, unsigned srclen)
1473
0
{
1474
0
    int ret = 1;
1475
0
    const char *p = src;
1476
0
    const char *e = src + srclen;
1477
0
    while (p < e)
1478
0
    {
1479
0
        if (*p == 0)
1480
0
            return 0;
1481
0
        if (*p & 0x80)
1482
0
        {
1483
0
            int len = 0;
1484
0
            utf8decode(p, e, &len);
1485
0
            if (len < 2)
1486
0
                return 0;
1487
0
            if (len > ret)
1488
0
                ret = len;
1489
0
            p += len;
1490
0
        }
1491
0
        else
1492
0
        {
1493
0
            p++;
1494
0
        }
1495
0
    }
1496
0
    return ret;
1497
0
}