Coverage Report

Created: 2026-10-31 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython/Python/codecs.c
Line
Count
Source
1
/* ------------------------------------------------------------------------
2
3
   Python Codec Registry and support functions
4
5
Written by Marc-Andre Lemburg (mal@lemburg.com).
6
7
Copyright (c) Corporation for National Research Initiatives.
8
9
   ------------------------------------------------------------------------ */
10
11
#include "Python.h"
12
#include "pycore_call.h"          // _PyObject_CallNoArgs()
13
#include "pycore_codecs.h"        // export _PyCodec_LookupTextEncoding()
14
#include "pycore_initconfig.h"    // _Py_DumpPathConfig()
15
#include "pycore_interp.h"        // PyInterpreterState.codec_search_path
16
#include "pycore_pyerrors.h"      // _PyErr_FormatNote()
17
#include "pycore_pystate.h"       // _PyInterpreterState_GET()
18
#include "pycore_runtime.h"       // _Py_ID()
19
#include "pycore_ucnhash.h"       // _PyUnicode_Name_CAPI
20
#include "pycore_unicodeobject.h" // _PyUnicode_InternMortal()
21
#include "pycore_pyatomic_ft_wrappers.h"
22
23
static const char *codecs_builtin_error_handlers[] = {
24
    "strict", "ignore", "replace",
25
    "xmlcharrefreplace", "backslashreplace", "namereplace",
26
    "surrogatepass", "surrogateescape",
27
};
28
29
const char *Py_hexdigits = "0123456789abcdef";
30
31
/* --- Codec Registry ----------------------------------------------------- */
32
33
int PyCodec_Register(PyObject *search_function)
34
74
{
35
74
    PyInterpreterState *interp = _PyInterpreterState_GET();
36
74
    assert(interp->codecs.initialized);
37
74
    if (search_function == NULL) {
38
0
        PyErr_BadArgument();
39
0
        goto onError;
40
0
    }
41
74
    if (!PyCallable_Check(search_function)) {
42
0
        PyErr_SetString(PyExc_TypeError, "argument must be callable");
43
0
        goto onError;
44
0
    }
45
74
    FT_MUTEX_LOCK(&interp->codecs.search_path_mutex);
46
74
    int ret = PyList_Append(interp->codecs.search_path, search_function);
47
74
    FT_MUTEX_UNLOCK(&interp->codecs.search_path_mutex);
48
49
74
    return ret;
50
51
0
 onError:
52
0
    return -1;
53
74
}
54
55
int
56
PyCodec_Unregister(PyObject *search_function)
57
0
{
58
0
    PyInterpreterState *interp = _PyInterpreterState_GET();
59
0
    if (interp->codecs.initialized != 1) {
60
        /* Do nothing if codecs state was cleared (only possible during
61
           interpreter shutdown). */
62
0
        return 0;
63
0
    }
64
65
0
    PyObject *codec_search_path = interp->codecs.search_path;
66
0
    assert(PyList_CheckExact(codec_search_path));
67
0
    FT_MUTEX_LOCK(&interp->codecs.search_path_mutex);
68
0
    for (Py_ssize_t i = 0; i < PyList_GET_SIZE(codec_search_path); i++) {
69
0
        if (PyList_GET_ITEM(codec_search_path, i) == search_function) {
70
            // Keep the function alive until after releasing the mutex.
71
0
            Py_INCREF(search_function);
72
0
            int ret = PyList_SetSlice(codec_search_path, i, i+1, NULL);
73
0
            FT_MUTEX_UNLOCK(&interp->codecs.search_path_mutex);
74
0
            Py_DECREF(search_function);
75
0
            assert(interp->codecs.search_cache != NULL);
76
0
            assert(PyDict_CheckExact(interp->codecs.search_cache));
77
0
            PyDict_Clear(interp->codecs.search_cache);
78
0
            return ret;
79
0
        }
80
0
    }
81
0
    FT_MUTEX_UNLOCK(&interp->codecs.search_path_mutex);
82
0
    return 0;
83
0
}
84
85
/* Convert a string to a normalized Python string: all ASCII letters are
86
   converted to lower case, spaces are replaced with hyphens. */
87
88
static PyObject*
89
normalizestring(const char *string)
90
4.58M
{
91
4.58M
    size_t i;
92
4.58M
    size_t len = strlen(string);
93
4.58M
    char *p;
94
4.58M
    PyObject *v;
95
96
4.58M
    if (len > PY_SSIZE_T_MAX) {
97
0
        PyErr_SetString(PyExc_OverflowError, "string is too large");
98
0
        return NULL;
99
0
    }
100
101
4.58M
    p = PyMem_Malloc(len + 1);
102
4.58M
    if (p == NULL)
103
0
        return PyErr_NoMemory();
104
59.7M
    for (i = 0; i < len; i++) {
105
55.2M
        char ch = string[i];
106
55.2M
        if (ch == ' ')
107
237k
            ch = '-';
108
54.9M
        else
109
54.9M
            ch = Py_TOLOWER(Py_CHARMASK(ch));
110
55.2M
        p[i] = ch;
111
55.2M
    }
112
4.58M
    p[i] = '\0';
113
4.58M
    v = PyUnicode_FromString(p);
114
4.58M
    PyMem_Free(p);
115
4.58M
    return v;
116
4.58M
}
117
118
/* Lookup the given encoding and return a tuple providing the codec
119
   facilities.
120
121
   ASCII letters in the encoding string is looked up converted to all
122
   lower case. This makes encodings looked up through this mechanism
123
   effectively case-insensitive. Spaces are replaced with hyphens for
124
   names like "US ASCII" and "ISO 8859-1".
125
126
   If no codec is found, a LookupError is set and NULL returned.
127
128
   As side effect, this tries to load the encodings package, if not
129
   yet done. This is part of the lazy load strategy for the encodings
130
   package.
131
132
*/
133
134
PyObject *_PyCodec_Lookup(const char *encoding)
135
4.58M
{
136
4.58M
    if (encoding == NULL) {
137
0
        PyErr_BadArgument();
138
0
        return NULL;
139
0
    }
140
141
4.58M
    PyInterpreterState *interp = _PyInterpreterState_GET();
142
4.58M
    assert(interp->codecs.initialized);
143
144
    /* Convert the encoding to a normalized Python string: all
145
       ASCII letters are converted to lower case, spaces are
146
       replaced with hyphens. */
147
4.58M
    PyObject *v = normalizestring(encoding);
148
4.58M
    if (v == NULL) {
149
0
        return NULL;
150
0
    }
151
152
    /* Intern the string. We'll make it immortal later if lookup succeeds. */
153
4.58M
    _PyUnicode_InternMortal(interp, &v);
154
155
    /* First, try to lookup the name in the registry dictionary */
156
4.58M
    PyObject *result;
157
4.58M
    if (PyDict_GetItemRef(interp->codecs.search_cache, v, &result) < 0) {
158
0
        goto onError;
159
0
    }
160
4.58M
    if (result != NULL) {
161
4.51M
        Py_DECREF(v);
162
4.51M
        return result;
163
4.51M
    }
164
165
    /* Next, scan the search functions in order of registration */
166
71.7k
    const Py_ssize_t len = PyList_Size(interp->codecs.search_path);
167
71.7k
    if (len < 0)
168
0
        goto onError;
169
71.7k
    if (len == 0) {
170
0
        PyErr_SetString(PyExc_LookupError,
171
0
                        "no codec search functions registered: "
172
0
                        "can't find encoding");
173
0
        goto onError;
174
0
    }
175
176
71.7k
    Py_ssize_t i;
177
210k
    for (i = 0; i < len; i++) {
178
141k
        PyObject *func;
179
180
141k
        func = PyList_GetItemRef(interp->codecs.search_path, i);
181
141k
        if (func == NULL)
182
0
            goto onError;
183
141k
        result = PyObject_CallOneArg(func, v);
184
141k
        Py_DECREF(func);
185
141k
        if (result == NULL)
186
0
            goto onError;
187
141k
        if (result == Py_None) {
188
139k
            Py_CLEAR(result);
189
139k
            continue;
190
139k
        }
191
2.39k
        if (!PyTuple_Check(result) || PyTuple_GET_SIZE(result) != 4) {
192
0
            PyErr_SetString(PyExc_TypeError,
193
0
                            "codec search functions must return 4-tuples");
194
0
            Py_DECREF(result);
195
0
            goto onError;
196
0
        }
197
2.39k
        break;
198
2.39k
    }
199
71.7k
    if (result == NULL) {
200
        /* XXX Perhaps we should cache misses too ? */
201
69.3k
        PyErr_Format(PyExc_LookupError,
202
69.3k
                     "unknown encoding: %s", encoding);
203
69.3k
        goto onError;
204
69.3k
    }
205
206
2.39k
    _PyUnicode_InternImmortal(interp, &v);
207
208
    /* Cache and return the result */
209
2.39k
    if (PyDict_SetItem(interp->codecs.search_cache, v, result) < 0) {
210
0
        Py_DECREF(result);
211
0
        goto onError;
212
0
    }
213
2.39k
    Py_DECREF(v);
214
2.39k
    return result;
215
216
69.3k
 onError:
217
69.3k
    Py_DECREF(v);
218
69.3k
    return NULL;
219
2.39k
}
220
221
/* Codec registry encoding check API. */
222
223
int PyCodec_KnownEncoding(const char *encoding)
224
0
{
225
0
    PyObject *codecs;
226
227
0
    codecs = _PyCodec_Lookup(encoding);
228
0
    if (!codecs) {
229
0
        PyErr_Clear();
230
0
        return 0;
231
0
    }
232
0
    else {
233
0
        Py_DECREF(codecs);
234
0
        return 1;
235
0
    }
236
0
}
237
238
static
239
PyObject *args_tuple(PyObject *object,
240
                     const char *errors)
241
4.21M
{
242
4.21M
    PyObject *args;
243
244
4.21M
    args = PyTuple_New(1 + (errors != NULL));
245
4.21M
    if (args == NULL)
246
0
        return NULL;
247
4.21M
    PyTuple_SET_ITEM(args, 0, Py_NewRef(object));
248
4.21M
    if (errors) {
249
200k
        PyObject *v;
250
251
200k
        v = PyUnicode_FromString(errors);
252
200k
        if (v == NULL) {
253
0
            Py_DECREF(args);
254
0
            return NULL;
255
0
        }
256
200k
        PyTuple_SET_ITEM(args, 1, v);
257
200k
    }
258
4.21M
    return args;
259
4.21M
}
260
261
/* Helper function to get a codec item */
262
263
static
264
PyObject *codec_getitem(const char *encoding, int index)
265
0
{
266
0
    PyObject *codecs;
267
0
    PyObject *v;
268
269
0
    codecs = _PyCodec_Lookup(encoding);
270
0
    if (codecs == NULL)
271
0
        return NULL;
272
0
    v = Py_NewRef(PyTuple_GET_ITEM(codecs, index));
273
0
    Py_DECREF(codecs);
274
0
    return v;
275
0
}
276
277
/* Helper functions to create an incremental codec. */
278
static
279
PyObject *codec_makeincrementalcodec(PyObject *codec_info,
280
                                     const char *errors,
281
                                     const char *attrname)
282
130
{
283
130
    PyObject *ret, *inccodec;
284
285
130
    inccodec = PyObject_GetAttrString(codec_info, attrname);
286
130
    if (inccodec == NULL)
287
0
        return NULL;
288
130
    if (errors)
289
130
        ret = PyObject_CallFunction(inccodec, "s", errors);
290
0
    else
291
0
        ret = _PyObject_CallNoArgs(inccodec);
292
130
    Py_DECREF(inccodec);
293
130
    return ret;
294
130
}
295
296
static
297
PyObject *codec_getincrementalcodec(const char *encoding,
298
                                    const char *errors,
299
                                    const char *attrname)
300
0
{
301
0
    PyObject *codec_info, *ret;
302
303
0
    codec_info = _PyCodec_Lookup(encoding);
304
0
    if (codec_info == NULL)
305
0
        return NULL;
306
0
    ret = codec_makeincrementalcodec(codec_info, errors, attrname);
307
0
    Py_DECREF(codec_info);
308
0
    return ret;
309
0
}
310
311
/* Helper function to create a stream codec. */
312
313
static
314
PyObject *codec_getstreamcodec(const char *encoding,
315
                               PyObject *stream,
316
                               const char *errors,
317
                               const int index)
318
0
{
319
0
    PyObject *codecs, *streamcodec, *codeccls;
320
321
0
    codecs = _PyCodec_Lookup(encoding);
322
0
    if (codecs == NULL)
323
0
        return NULL;
324
325
0
    codeccls = PyTuple_GET_ITEM(codecs, index);
326
0
    if (errors != NULL)
327
0
        streamcodec = PyObject_CallFunction(codeccls, "Os", stream, errors);
328
0
    else
329
0
        streamcodec = PyObject_CallOneArg(codeccls, stream);
330
0
    Py_DECREF(codecs);
331
0
    return streamcodec;
332
0
}
333
334
/* Helpers to work with the result of _PyCodec_Lookup
335
336
 */
337
PyObject *_PyCodecInfo_GetIncrementalDecoder(PyObject *codec_info,
338
                                             const char *errors)
339
55
{
340
55
    return codec_makeincrementalcodec(codec_info, errors,
341
55
                                      "incrementaldecoder");
342
55
}
343
344
PyObject *_PyCodecInfo_GetIncrementalEncoder(PyObject *codec_info,
345
                                             const char *errors)
346
75
{
347
75
    return codec_makeincrementalcodec(codec_info, errors,
348
75
                                      "incrementalencoder");
349
75
}
350
351
352
/* Convenience APIs to query the Codec registry.
353
354
   All APIs return a codec object with incremented refcount.
355
356
 */
357
358
PyObject *PyCodec_Encoder(const char *encoding)
359
0
{
360
0
    return codec_getitem(encoding, 0);
361
0
}
362
363
PyObject *PyCodec_Decoder(const char *encoding)
364
0
{
365
0
    return codec_getitem(encoding, 1);
366
0
}
367
368
PyObject *PyCodec_IncrementalEncoder(const char *encoding,
369
                                     const char *errors)
370
0
{
371
0
    return codec_getincrementalcodec(encoding, errors, "incrementalencoder");
372
0
}
373
374
PyObject *PyCodec_IncrementalDecoder(const char *encoding,
375
                                     const char *errors)
376
0
{
377
0
    return codec_getincrementalcodec(encoding, errors, "incrementaldecoder");
378
0
}
379
380
PyObject *PyCodec_StreamReader(const char *encoding,
381
                               PyObject *stream,
382
                               const char *errors)
383
0
{
384
0
    return codec_getstreamcodec(encoding, stream, errors, 2);
385
0
}
386
387
PyObject *PyCodec_StreamWriter(const char *encoding,
388
                               PyObject *stream,
389
                               const char *errors)
390
0
{
391
0
    return codec_getstreamcodec(encoding, stream, errors, 3);
392
0
}
393
394
/* Encode an object (e.g. a Unicode object) using the given encoding
395
   and return the resulting encoded object (usually a Python string).
396
397
   errors is passed to the encoder factory as argument if non-NULL. */
398
399
static PyObject *
400
_PyCodec_EncodeInternal(PyObject *object,
401
                        PyObject *encoder,
402
                        const char *encoding,
403
                        const char *errors)
404
2.07M
{
405
2.07M
    PyObject *args = NULL, *result = NULL;
406
2.07M
    PyObject *v = NULL;
407
408
2.07M
    args = args_tuple(object, errors);
409
2.07M
    if (args == NULL)
410
0
        goto onError;
411
412
2.07M
    result = PyObject_Call(encoder, args, NULL);
413
2.07M
    if (result == NULL) {
414
0
        _PyErr_FormatNote("%s with '%s' codec failed", "encoding", encoding);
415
0
        goto onError;
416
0
    }
417
418
2.07M
    if (!PyTuple_Check(result) ||
419
2.07M
        PyTuple_GET_SIZE(result) != 2) {
420
0
        PyErr_SetString(PyExc_TypeError,
421
0
                        "encoder must return a tuple (object, integer)");
422
0
        goto onError;
423
0
    }
424
2.07M
    v = Py_NewRef(PyTuple_GET_ITEM(result,0));
425
    /* We don't check or use the second (integer) entry. */
426
427
2.07M
    Py_DECREF(args);
428
2.07M
    Py_DECREF(encoder);
429
2.07M
    Py_DECREF(result);
430
2.07M
    return v;
431
432
0
 onError:
433
0
    Py_XDECREF(result);
434
0
    Py_XDECREF(args);
435
0
    Py_XDECREF(encoder);
436
0
    return NULL;
437
2.07M
}
438
439
/* Decode an object (usually a Python string) using the given encoding
440
   and return an equivalent object (e.g. a Unicode object).
441
442
   errors is passed to the decoder factory as argument if non-NULL. */
443
444
static PyObject *
445
_PyCodec_DecodeInternal(PyObject *object,
446
                        PyObject *decoder,
447
                        const char *encoding,
448
                        const char *errors)
449
2.14M
{
450
2.14M
    PyObject *args = NULL, *result = NULL;
451
2.14M
    PyObject *v;
452
453
2.14M
    args = args_tuple(object, errors);
454
2.14M
    if (args == NULL)
455
0
        goto onError;
456
457
2.14M
    result = PyObject_Call(decoder, args, NULL);
458
2.14M
    if (result == NULL) {
459
47.0k
        _PyErr_FormatNote("%s with '%s' codec failed", "decoding", encoding);
460
47.0k
        goto onError;
461
47.0k
    }
462
2.09M
    if (!PyTuple_Check(result) ||
463
2.09M
        PyTuple_GET_SIZE(result) != 2) {
464
0
        PyErr_SetString(PyExc_TypeError,
465
0
                        "decoder must return a tuple (object,integer)");
466
0
        goto onError;
467
0
    }
468
2.09M
    v = Py_NewRef(PyTuple_GET_ITEM(result,0));
469
    /* We don't check or use the second (integer) entry. */
470
471
2.09M
    Py_DECREF(args);
472
2.09M
    Py_DECREF(decoder);
473
2.09M
    Py_DECREF(result);
474
2.09M
    return v;
475
476
47.0k
 onError:
477
47.0k
    Py_XDECREF(args);
478
47.0k
    Py_XDECREF(decoder);
479
47.0k
    Py_XDECREF(result);
480
47.0k
    return NULL;
481
2.09M
}
482
483
/* Generic encoding/decoding API */
484
PyObject *PyCodec_Encode(PyObject *object,
485
                         const char *encoding,
486
                         const char *errors)
487
0
{
488
0
    PyObject *encoder;
489
490
0
    encoder = PyCodec_Encoder(encoding);
491
0
    if (encoder == NULL)
492
0
        return NULL;
493
494
0
    return _PyCodec_EncodeInternal(object, encoder, encoding, errors);
495
0
}
496
497
PyObject *PyCodec_Decode(PyObject *object,
498
                         const char *encoding,
499
                         const char *errors)
500
0
{
501
0
    PyObject *decoder;
502
503
0
    decoder = PyCodec_Decoder(encoding);
504
0
    if (decoder == NULL)
505
0
        return NULL;
506
507
0
    return _PyCodec_DecodeInternal(object, decoder, encoding, errors);
508
0
}
509
510
/* Text encoding/decoding API */
511
PyObject * _PyCodec_LookupTextEncoding(const char *encoding,
512
                                       const char *alternate_command)
513
4.22M
{
514
4.22M
    PyObject *codec;
515
4.22M
    PyObject *attr;
516
4.22M
    int is_text_codec;
517
518
4.22M
    codec = _PyCodec_Lookup(encoding);
519
4.22M
    if (codec == NULL)
520
9.29k
        return NULL;
521
522
    /* Backwards compatibility: assume any raw tuple describes a text
523
     * encoding, and the same for anything lacking the private
524
     * attribute.
525
     */
526
4.22M
    if (!PyTuple_CheckExact(codec)) {
527
4.22M
        if (PyObject_GetOptionalAttr(codec, &_Py_ID(_is_text_encoding), &attr) < 0) {
528
0
            Py_DECREF(codec);
529
0
            return NULL;
530
0
        }
531
4.22M
        if (attr != NULL) {
532
4.22M
            is_text_codec = PyObject_IsTrue(attr);
533
4.22M
            Py_DECREF(attr);
534
4.22M
            if (is_text_codec <= 0) {
535
3.51k
                Py_DECREF(codec);
536
3.51k
                if (!is_text_codec) {
537
3.51k
                    if (alternate_command != NULL) {
538
3.51k
                        PyErr_Format(PyExc_LookupError,
539
3.51k
                                     "'%.400s' is not a text encoding; "
540
3.51k
                                     "use %s to handle arbitrary codecs",
541
3.51k
                                     encoding, alternate_command);
542
3.51k
                    }
543
0
                    else {
544
0
                        PyErr_Format(PyExc_LookupError,
545
0
                                     "'%.400s' is not a text encoding",
546
0
                                     encoding);
547
0
                    }
548
3.51k
                }
549
3.51k
                return NULL;
550
3.51k
            }
551
4.22M
        }
552
4.22M
    }
553
554
    /* This appears to be a valid text encoding */
555
4.21M
    return codec;
556
4.22M
}
557
558
559
static
560
PyObject *codec_getitem_checked(const char *encoding,
561
                                const char *alternate_command,
562
                                int index)
563
4.22M
{
564
4.22M
    PyObject *codec;
565
4.22M
    PyObject *v;
566
567
4.22M
    codec = _PyCodec_LookupTextEncoding(encoding, alternate_command);
568
4.22M
    if (codec == NULL)
569
12.7k
        return NULL;
570
571
4.21M
    v = Py_NewRef(PyTuple_GET_ITEM(codec, index));
572
4.21M
    Py_DECREF(codec);
573
4.21M
    return v;
574
4.22M
}
575
576
static PyObject * _PyCodec_TextEncoder(const char *encoding)
577
2.07M
{
578
2.07M
    return codec_getitem_checked(encoding, "codecs.encode()", 0);
579
2.07M
}
580
581
static PyObject * _PyCodec_TextDecoder(const char *encoding)
582
2.15M
{
583
2.15M
    return codec_getitem_checked(encoding, "codecs.decode()", 1);
584
2.15M
}
585
586
PyObject *_PyCodec_EncodeText(PyObject *object,
587
                              const char *encoding,
588
                              const char *errors)
589
2.07M
{
590
2.07M
    PyObject *encoder;
591
592
2.07M
    encoder = _PyCodec_TextEncoder(encoding);
593
2.07M
    if (encoder == NULL)
594
0
        return NULL;
595
596
2.07M
    return _PyCodec_EncodeInternal(object, encoder, encoding, errors);
597
2.07M
}
598
599
PyObject *_PyCodec_DecodeText(PyObject *object,
600
                              const char *encoding,
601
                              const char *errors)
602
2.15M
{
603
2.15M
    PyObject *decoder;
604
605
2.15M
    decoder = _PyCodec_TextDecoder(encoding);
606
2.15M
    if (decoder == NULL)
607
12.7k
        return NULL;
608
609
2.14M
    return _PyCodec_DecodeInternal(object, decoder, encoding, errors);
610
2.15M
}
611
612
/* Register the error handling callback function error under the name
613
   name. This function will be called by the codec when it encounters
614
   an unencodable characters/undecodable bytes and doesn't know the
615
   callback name, when name is specified as the error parameter
616
   in the call to the encode/decode function.
617
   Return 0 on success, -1 on error */
618
int PyCodec_RegisterError(const char *name, PyObject *error)
619
0
{
620
0
    PyInterpreterState *interp = _PyInterpreterState_GET();
621
0
    assert(interp->codecs.initialized);
622
0
    if (!PyCallable_Check(error)) {
623
0
        PyErr_SetString(PyExc_TypeError, "handler must be callable");
624
0
        return -1;
625
0
    }
626
0
    return PyDict_SetItemString(interp->codecs.error_registry,
627
0
                                name, error);
628
0
}
629
630
int _PyCodec_UnregisterError(const char *name)
631
0
{
632
0
    for (size_t i = 0; i < Py_ARRAY_LENGTH(codecs_builtin_error_handlers); ++i) {
633
0
        if (strcmp(name, codecs_builtin_error_handlers[i]) == 0) {
634
0
            PyErr_Format(PyExc_ValueError,
635
0
                         "cannot un-register built-in error handler '%s'", name);
636
0
            return -1;
637
0
        }
638
0
    }
639
0
    PyInterpreterState *interp = _PyInterpreterState_GET();
640
0
    assert(interp->codecs.initialized);
641
0
    return PyDict_PopString(interp->codecs.error_registry, name, NULL);
642
0
}
643
644
/* Lookup the error handling callback function registered under the
645
   name error. As a special case NULL can be passed, in which case
646
   the error handling callback for strict encoding will be returned. */
647
PyObject *PyCodec_LookupError(const char *name)
648
2.81M
{
649
2.81M
    PyInterpreterState *interp = _PyInterpreterState_GET();
650
2.81M
    assert(interp->codecs.initialized);
651
652
2.81M
    if (name==NULL)
653
146k
        name = "strict";
654
2.81M
    PyObject *handler;
655
2.81M
    if (PyDict_GetItemStringRef(interp->codecs.error_registry, name, &handler) < 0) {
656
0
        return NULL;
657
0
    }
658
2.81M
    if (handler == NULL) {
659
0
        PyErr_Format(PyExc_LookupError, "unknown error handler name '%.400s'", name);
660
0
        return NULL;
661
0
    }
662
2.81M
    return handler;
663
2.81M
}
664
665
666
static inline void
667
wrong_exception_type(PyObject *exc)
668
0
{
669
0
    PyErr_Format(PyExc_TypeError,
670
0
                 "don't know how to handle %T in error callback", exc);
671
0
}
672
673
674
#define _PyIsUnicodeEncodeError(EXC)    \
675
508k
    PyObject_TypeCheck(EXC, (PyTypeObject *)PyExc_UnicodeEncodeError)
676
#define _PyIsUnicodeDecodeError(EXC)    \
677
497k
    PyObject_TypeCheck(EXC, (PyTypeObject *)PyExc_UnicodeDecodeError)
678
#define _PyIsUnicodeTranslateError(EXC) \
679
0
    PyObject_TypeCheck(EXC, (PyTypeObject *)PyExc_UnicodeTranslateError)
680
681
682
// --- codecs handlers: utilities ---------------------------------------------
683
684
/*
685
 * Return the number of characters (including special prefixes)
686
 * needed to represent 'ch' by codec_handler_write_unicode_hex().
687
 */
688
static inline Py_ssize_t
689
codec_handler_unicode_hex_width(Py_UCS4 ch)
690
0
{
691
0
    if (ch >= 0x10000) {
692
        // format: '\\' + 'U' + 8 hex digits
693
0
        return 1 + 1 + 8;
694
0
    }
695
0
    else if (ch >= 0x100) {
696
        // format: '\\' + 'u' + 4 hex digits
697
0
        return 1 + 1 + 4;
698
0
    }
699
0
    else {
700
        // format: '\\' + 'x' + 2 hex digits
701
0
        return 1 + 1 + 2;
702
0
    }
703
0
}
704
705
706
/*
707
 * Write the hexadecimal representation of 'ch' to the buffer pointed by 'p'
708
 * using 2, 4, or 8 characters prefixed by '\x', '\u', or '\U' respectively.
709
 */
710
static inline void
711
codec_handler_write_unicode_hex(Py_UCS1 **p, Py_UCS4 ch)
712
0
{
713
0
    *(*p)++ = '\\';
714
0
    if (ch >= 0x10000) {
715
0
        *(*p)++ = 'U';
716
0
        *(*p)++ = Py_hexdigits[(ch >> 28) & 0xf];
717
0
        *(*p)++ = Py_hexdigits[(ch >> 24) & 0xf];
718
0
        *(*p)++ = Py_hexdigits[(ch >> 20) & 0xf];
719
0
        *(*p)++ = Py_hexdigits[(ch >> 16) & 0xf];
720
0
        *(*p)++ = Py_hexdigits[(ch >> 12) & 0xf];
721
0
        *(*p)++ = Py_hexdigits[(ch >> 8) & 0xf];
722
0
    }
723
0
    else if (ch >= 0x100) {
724
0
        *(*p)++ = 'u';
725
0
        *(*p)++ = Py_hexdigits[(ch >> 12) & 0xf];
726
0
        *(*p)++ = Py_hexdigits[(ch >> 8) & 0xf];
727
0
    }
728
0
    else {
729
0
        *(*p)++ = 'x';
730
0
    }
731
0
    *(*p)++ = Py_hexdigits[(ch >> 4) & 0xf];
732
0
    *(*p)++ = Py_hexdigits[ch & 0xf];
733
0
}
734
735
736
/*
737
 * Determine the number of digits for a decimal representation of Unicode
738
 * codepoint 'ch' (by design, Unicode codepoints are limited to 7 digits).
739
 */
740
static inline int
741
n_decimal_digits_for_codepoint(Py_UCS4 ch)
742
0
{
743
0
    if (ch < 10) return 1;
744
0
    if (ch < 100) return 2;
745
0
    if (ch < 1000) return 3;
746
0
    if (ch < 10000) return 4;
747
0
    if (ch < 100000) return 5;
748
0
    if (ch < 1000000) return 6;
749
0
    if (ch < 10000000) return 7;
750
    // Unicode codepoints are limited to 1114111 (7 decimal digits)
751
0
    Py_UNREACHABLE();
752
0
}
753
754
755
/*
756
 * Create a Unicode string containing 'count' copies of the official
757
 * Unicode REPLACEMENT CHARACTER (0xFFFD).
758
 */
759
static PyObject *
760
codec_handler_unicode_replacement_character(Py_ssize_t count)
761
300k
{
762
300k
    PyObject *res = PyUnicode_New(count, Py_UNICODE_REPLACEMENT_CHARACTER);
763
300k
    if (res == NULL) {
764
0
        return NULL;
765
0
    }
766
300k
    assert(count == 0 || PyUnicode_KIND(res) == PyUnicode_2BYTE_KIND);
767
300k
    Py_UCS2 *outp = PyUnicode_2BYTE_DATA(res);
768
601k
    for (Py_ssize_t i = 0; i < count; ++i) {
769
300k
        outp[i] = Py_UNICODE_REPLACEMENT_CHARACTER;
770
300k
    }
771
300k
    assert(_PyUnicode_CheckConsistency(res, 1));
772
300k
    return res;
773
300k
}
774
775
776
// --- handler: 'strict' ------------------------------------------------------
777
778
PyObject *PyCodec_StrictErrors(PyObject *exc)
779
5.52M
{
780
5.52M
    if (PyExceptionInstance_Check(exc)) {
781
5.52M
        PyErr_SetObject(PyExceptionInstance_Class(exc), exc);
782
5.52M
    }
783
0
    else {
784
0
        PyErr_SetString(PyExc_TypeError, "codec must pass exception instance");
785
0
    }
786
5.52M
    return NULL;
787
5.52M
}
788
789
790
// --- handler: 'ignore' ------------------------------------------------------
791
792
static PyObject *
793
_PyCodec_IgnoreError(PyObject *exc, int as_bytes)
794
0
{
795
0
    Py_ssize_t end;
796
0
    if (_PyUnicodeError_GetParams(exc, NULL, NULL, NULL,
797
0
                                  &end, NULL, as_bytes) < 0)
798
0
    {
799
0
        return NULL;
800
0
    }
801
0
    return Py_BuildValue("(Nn)", Py_GetConstant(Py_CONSTANT_EMPTY_STR), end);
802
0
}
803
804
805
PyObject *PyCodec_IgnoreErrors(PyObject *exc)
806
0
{
807
0
    if (_PyIsUnicodeEncodeError(exc) || _PyIsUnicodeTranslateError(exc)) {
808
0
        return _PyCodec_IgnoreError(exc, false);
809
0
    }
810
0
    else if (_PyIsUnicodeDecodeError(exc)) {
811
0
        return _PyCodec_IgnoreError(exc, true);
812
0
    }
813
0
    else {
814
0
        wrong_exception_type(exc);
815
0
        return NULL;
816
0
    }
817
0
}
818
819
820
// --- handler: 'replace' -----------------------------------------------------
821
822
static PyObject *
823
_PyCodec_ReplaceUnicodeEncodeError(PyObject *exc)
824
0
{
825
0
    Py_ssize_t start, end, slen;
826
0
    if (_PyUnicodeError_GetParams(exc, NULL, NULL,
827
0
                                  &start, &end, &slen, false) < 0)
828
0
    {
829
0
        return NULL;
830
0
    }
831
0
    PyObject *res = PyUnicode_New(slen, '?');
832
0
    if (res == NULL) {
833
0
        return NULL;
834
0
    }
835
0
    assert(PyUnicode_KIND(res) == PyUnicode_1BYTE_KIND);
836
0
    Py_UCS1 *outp = PyUnicode_1BYTE_DATA(res);
837
0
    memset(outp, '?', sizeof(Py_UCS1) * slen);
838
0
    assert(_PyUnicode_CheckConsistency(res, 1));
839
0
    return Py_BuildValue("(Nn)", res, end);
840
0
}
841
842
843
static PyObject *
844
_PyCodec_ReplaceUnicodeDecodeError(PyObject *exc)
845
300k
{
846
300k
    Py_ssize_t end;
847
300k
    if (PyUnicodeDecodeError_GetEnd(exc, &end) < 0) {
848
0
        return NULL;
849
0
    }
850
300k
    PyObject *res = codec_handler_unicode_replacement_character(1);
851
300k
    if (res == NULL) {
852
0
        return NULL;
853
0
    }
854
300k
    return Py_BuildValue("(Nn)", res, end);
855
300k
}
856
857
858
static PyObject *
859
_PyCodec_ReplaceUnicodeTranslateError(PyObject *exc)
860
0
{
861
0
    Py_ssize_t start, end, slen;
862
0
    if (_PyUnicodeError_GetParams(exc, NULL, NULL,
863
0
                                  &start, &end, &slen, false) < 0)
864
0
    {
865
0
        return NULL;
866
0
    }
867
0
    PyObject *res = codec_handler_unicode_replacement_character(slen);
868
0
    if (res == NULL) {
869
0
        return NULL;
870
0
    }
871
0
    return Py_BuildValue("(Nn)", res, end);
872
0
}
873
874
875
PyObject *PyCodec_ReplaceErrors(PyObject *exc)
876
300k
{
877
300k
    if (_PyIsUnicodeEncodeError(exc)) {
878
0
        return _PyCodec_ReplaceUnicodeEncodeError(exc);
879
0
    }
880
300k
    else if (_PyIsUnicodeDecodeError(exc)) {
881
300k
        return _PyCodec_ReplaceUnicodeDecodeError(exc);
882
300k
    }
883
0
    else if (_PyIsUnicodeTranslateError(exc)) {
884
0
        return _PyCodec_ReplaceUnicodeTranslateError(exc);
885
0
    }
886
0
    else {
887
0
        wrong_exception_type(exc);
888
0
        return NULL;
889
0
    }
890
300k
}
891
892
893
// --- handler: 'xmlcharrefreplace' -------------------------------------------
894
895
PyObject *PyCodec_XMLCharRefReplaceErrors(PyObject *exc)
896
0
{
897
0
    if (!_PyIsUnicodeEncodeError(exc)) {
898
0
        wrong_exception_type(exc);
899
0
        return NULL;
900
0
    }
901
902
0
    PyObject *obj;
903
0
    Py_ssize_t objlen, start, end, slen;
904
0
    if (_PyUnicodeError_GetParams(exc,
905
0
                                  &obj, &objlen,
906
0
                                  &start, &end, &slen, false) < 0)
907
0
    {
908
0
        return NULL;
909
0
    }
910
911
    // The number of characters that each character 'ch' contributes
912
    // in the result is 2 + k + 1, where k = min{t >= 1 | 10^t > ch}
913
    // and will be formatted as "&#" + DIGITS + ";". Since the Unicode
914
    // range is below 10^7, each "block" requires at most 2 + 7 + 1
915
    // characters.
916
0
    if (slen > PY_SSIZE_T_MAX / (2 + 7 + 1)) {
917
0
        end = start + PY_SSIZE_T_MAX / (2 + 7 + 1);
918
0
        end = Py_MIN(end, objlen);
919
0
        slen = Py_MAX(0, end - start);
920
0
    }
921
922
0
    Py_ssize_t ressize = 0;
923
0
    for (Py_ssize_t i = start; i < end; ++i) {
924
0
        Py_UCS4 ch = PyUnicode_READ_CHAR(obj, i);
925
0
        int k = n_decimal_digits_for_codepoint(ch);
926
0
        assert(k != 0);
927
0
        assert(k <= 7);
928
0
        ressize += 2 + k + 1;
929
0
    }
930
931
    /* allocate replacement */
932
0
    PyObject *res = PyUnicode_New(ressize, 127);
933
0
    if (res == NULL) {
934
0
        Py_DECREF(obj);
935
0
        return NULL;
936
0
    }
937
0
    Py_UCS1 *outp = PyUnicode_1BYTE_DATA(res);
938
    /* generate replacement */
939
0
    for (Py_ssize_t i = start; i < end; ++i) {
940
0
        Py_UCS4 ch = PyUnicode_READ_CHAR(obj, i);
941
        /*
942
         * Write the decimal representation of 'ch' to the buffer pointed by 'p'
943
         * using at most 7 characters prefixed by '&#' and suffixed by ';'.
944
         */
945
0
        *outp++ = '&';
946
0
        *outp++ = '#';
947
0
        Py_UCS1 *digit_end = outp + n_decimal_digits_for_codepoint(ch);
948
0
        for (Py_UCS1 *p_digit = digit_end - 1; p_digit >= outp; --p_digit) {
949
0
            *p_digit = '0' + (ch % 10);
950
0
            ch /= 10;
951
0
        }
952
0
        assert(ch == 0);
953
0
        outp = digit_end;
954
0
        *outp++ = ';';
955
0
    }
956
0
    assert(_PyUnicode_CheckConsistency(res, 1));
957
0
    PyObject *restuple = Py_BuildValue("(Nn)", res, end);
958
0
    Py_DECREF(obj);
959
0
    return restuple;
960
0
}
961
962
963
// --- handler: 'backslashreplace' --------------------------------------------
964
965
static PyObject *
966
_PyCodec_BackslashReplaceUnicodeEncodeError(PyObject *exc)
967
0
{
968
0
    PyObject *obj;
969
0
    Py_ssize_t objlen, start, end, slen;
970
0
    if (_PyUnicodeError_GetParams(exc,
971
0
                                  &obj, &objlen,
972
0
                                  &start, &end, &slen, false) < 0)
973
0
    {
974
0
        return NULL;
975
0
    }
976
977
    // The number of characters that each character 'ch' contributes
978
    // in the result is 1 + 1 + k, where k >= min{t >= 1 | 16^t > ch}
979
    // and will be formatted as "\\" + ('U'|'u'|'x') + HEXDIGITS,
980
    // where the number of hexdigits is either 2, 4, or 8 (not 6).
981
    // Since the Unicode range is below 10^7, we choose k = 8 whence
982
    // each "block" requires at most 1 + 1 + 8 characters.
983
0
    if (slen > PY_SSIZE_T_MAX / (1 + 1 + 8)) {
984
0
        end = start + PY_SSIZE_T_MAX / (1 + 1 + 8);
985
0
        end = Py_MIN(end, objlen);
986
0
        slen = Py_MAX(0, end - start);
987
0
    }
988
989
0
    Py_ssize_t ressize = 0;
990
0
    for (Py_ssize_t i = start; i < end; ++i) {
991
0
        Py_UCS4 c = PyUnicode_READ_CHAR(obj, i);
992
0
        ressize += codec_handler_unicode_hex_width(c);
993
0
    }
994
0
    PyObject *res = PyUnicode_New(ressize, 127);
995
0
    if (res == NULL) {
996
0
        Py_DECREF(obj);
997
0
        return NULL;
998
0
    }
999
0
    Py_UCS1 *outp = PyUnicode_1BYTE_DATA(res);
1000
0
    for (Py_ssize_t i = start; i < end; ++i) {
1001
0
        Py_UCS4 c = PyUnicode_READ_CHAR(obj, i);
1002
0
        codec_handler_write_unicode_hex(&outp, c);
1003
0
    }
1004
0
    assert(_PyUnicode_CheckConsistency(res, 1));
1005
0
    Py_DECREF(obj);
1006
0
    return Py_BuildValue("(Nn)", res, end);
1007
0
}
1008
1009
1010
static PyObject *
1011
_PyCodec_BackslashReplaceUnicodeDecodeError(PyObject *exc)
1012
0
{
1013
0
    PyObject *obj;
1014
0
    Py_ssize_t objlen, start, end, slen;
1015
0
    if (_PyUnicodeError_GetParams(exc,
1016
0
                                  &obj, &objlen,
1017
0
                                  &start, &end, &slen, true) < 0)
1018
0
    {
1019
0
        return NULL;
1020
0
    }
1021
1022
0
    PyObject *res = PyUnicode_New(4 * slen, 127);
1023
0
    if (res == NULL) {
1024
0
        Py_DECREF(obj);
1025
0
        return NULL;
1026
0
    }
1027
1028
0
    Py_UCS1 *outp = PyUnicode_1BYTE_DATA(res);
1029
0
    const unsigned char *p = (const unsigned char *)PyBytes_AS_STRING(obj);
1030
0
    for (Py_ssize_t i = start; i < end; i++, outp += 4) {
1031
0
        const unsigned char ch = p[i];
1032
0
        outp[0] = '\\';
1033
0
        outp[1] = 'x';
1034
0
        outp[2] = Py_hexdigits[(ch >> 4) & 0xf];
1035
0
        outp[3] = Py_hexdigits[ch & 0xf];
1036
0
    }
1037
0
    assert(_PyUnicode_CheckConsistency(res, 1));
1038
0
    Py_DECREF(obj);
1039
0
    return Py_BuildValue("(Nn)", res, end);
1040
0
}
1041
1042
1043
static inline PyObject *
1044
_PyCodec_BackslashReplaceUnicodeTranslateError(PyObject *exc)
1045
0
{
1046
    // Same implementation as for UnicodeEncodeError objects.
1047
0
    return _PyCodec_BackslashReplaceUnicodeEncodeError(exc);
1048
0
}
1049
1050
1051
PyObject *PyCodec_BackslashReplaceErrors(PyObject *exc)
1052
0
{
1053
0
    if (_PyIsUnicodeEncodeError(exc)) {
1054
0
        return _PyCodec_BackslashReplaceUnicodeEncodeError(exc);
1055
0
    }
1056
0
    else if (_PyIsUnicodeDecodeError(exc)) {
1057
0
        return _PyCodec_BackslashReplaceUnicodeDecodeError(exc);
1058
0
    }
1059
0
    else if (_PyIsUnicodeTranslateError(exc)) {
1060
0
        return _PyCodec_BackslashReplaceUnicodeTranslateError(exc);
1061
0
    }
1062
0
    else {
1063
0
        wrong_exception_type(exc);
1064
0
        return NULL;
1065
0
    }
1066
0
}
1067
1068
1069
// --- handler: 'namereplace' -------------------------------------------------
1070
1071
PyObject *PyCodec_NameReplaceErrors(PyObject *exc)
1072
0
{
1073
0
    if (!_PyIsUnicodeEncodeError(exc)) {
1074
0
        wrong_exception_type(exc);
1075
0
        return NULL;
1076
0
    }
1077
1078
0
    _PyUnicode_Name_CAPI *ucnhash_capi = _PyUnicode_GetNameCAPI();
1079
0
    if (ucnhash_capi == NULL) {
1080
0
        return NULL;
1081
0
    }
1082
1083
0
    PyObject *obj;
1084
0
    Py_ssize_t start, end;
1085
0
    if (_PyUnicodeError_GetParams(exc,
1086
0
                                  &obj, NULL,
1087
0
                                  &start, &end, NULL, false) < 0)
1088
0
    {
1089
0
        return NULL;
1090
0
    }
1091
1092
0
    char buffer[256]; /* NAME_MAXLEN in unicodename_db.h */
1093
0
    Py_ssize_t imax = start, ressize = 0, replsize;
1094
0
    for (; imax < end; ++imax) {
1095
0
        Py_UCS4 c = PyUnicode_READ_CHAR(obj, imax);
1096
0
        if (ucnhash_capi->getname(c, buffer, sizeof(buffer), 1)) {
1097
            // If 'c' is recognized by getname(), the corresponding replacement
1098
            // is '\\' + 'N' + '{' + NAME + '}', i.e. 1 + 1 + 1 + len(NAME) + 1
1099
            // characters. Failures of getname() are ignored by the handler.
1100
0
            replsize = 1 + 1 + 1 + strlen(buffer) + 1;
1101
0
        }
1102
0
        else {
1103
0
            replsize = codec_handler_unicode_hex_width(c);
1104
0
        }
1105
0
        if (ressize > PY_SSIZE_T_MAX - replsize) {
1106
0
            break;
1107
0
        }
1108
0
        ressize += replsize;
1109
0
    }
1110
1111
0
    PyObject *res = PyUnicode_New(ressize, 127);
1112
0
    if (res == NULL) {
1113
0
        Py_DECREF(obj);
1114
0
        return NULL;
1115
0
    }
1116
1117
0
    Py_UCS1 *outp = PyUnicode_1BYTE_DATA(res);
1118
0
    for (Py_ssize_t i = start; i < imax; ++i) {
1119
0
        Py_UCS4 c = PyUnicode_READ_CHAR(obj, i);
1120
0
        if (ucnhash_capi->getname(c, buffer, sizeof(buffer), 1)) {
1121
0
            *outp++ = '\\';
1122
0
            *outp++ = 'N';
1123
0
            *outp++ = '{';
1124
0
            (void)strcpy((char *)outp, buffer);
1125
0
            outp += strlen(buffer);
1126
0
            *outp++ = '}';
1127
0
        }
1128
0
        else {
1129
0
            codec_handler_write_unicode_hex(&outp, c);
1130
0
        }
1131
0
    }
1132
1133
0
    assert(outp == PyUnicode_1BYTE_DATA(res) + ressize);
1134
0
    assert(_PyUnicode_CheckConsistency(res, 1));
1135
0
    PyObject *restuple = Py_BuildValue("(Nn)", res, imax);
1136
0
    Py_DECREF(obj);
1137
0
    return restuple;
1138
0
}
1139
1140
1141
8
#define ENC_UNKNOWN     -1
1142
16
#define ENC_UTF8        0
1143
0
#define ENC_UTF16BE     1
1144
0
#define ENC_UTF16LE     2
1145
0
#define ENC_UTF32BE     3
1146
0
#define ENC_UTF32LE     4
1147
1148
static int
1149
get_standard_encoding_impl(const char *encoding, int *bytelength)
1150
8
{
1151
8
    if (Py_TOLOWER(encoding[0]) == 'u' &&
1152
8
        Py_TOLOWER(encoding[1]) == 't' &&
1153
8
        Py_TOLOWER(encoding[2]) == 'f') {
1154
8
        encoding += 3;
1155
8
        if (*encoding == '-' || *encoding == '_' )
1156
8
            encoding++;
1157
8
        if (encoding[0] == '8' && encoding[1] == '\0') {
1158
8
            *bytelength = 3;
1159
8
            return ENC_UTF8;
1160
8
        }
1161
0
        else if (encoding[0] == '1' && encoding[1] == '6') {
1162
0
            encoding += 2;
1163
0
            *bytelength = 2;
1164
0
            if (*encoding == '\0') {
1165
#ifdef WORDS_BIGENDIAN
1166
                return ENC_UTF16BE;
1167
#else
1168
0
                return ENC_UTF16LE;
1169
0
#endif
1170
0
            }
1171
0
            if (*encoding == '-' || *encoding == '_' )
1172
0
                encoding++;
1173
0
            if (encoding[0] != '\0' &&
1174
0
                Py_TOLOWER(encoding[1]) == 'e' && encoding[2] == '\0') {
1175
0
                if (Py_TOLOWER(encoding[0]) == 'b')
1176
0
                    return ENC_UTF16BE;
1177
0
                if (Py_TOLOWER(encoding[0]) == 'l')
1178
0
                    return ENC_UTF16LE;
1179
0
            }
1180
0
        }
1181
0
        else if (encoding[0] == '3' && encoding[1] == '2') {
1182
0
            encoding += 2;
1183
0
            *bytelength = 4;
1184
0
            if (*encoding == '\0') {
1185
#ifdef WORDS_BIGENDIAN
1186
                return ENC_UTF32BE;
1187
#else
1188
0
                return ENC_UTF32LE;
1189
0
#endif
1190
0
            }
1191
0
            if (*encoding == '-' || *encoding == '_' )
1192
0
                encoding++;
1193
0
            if (encoding[0] != '\0' &&
1194
0
                Py_TOLOWER(encoding[1]) == 'e' && encoding[2] == '\0') {
1195
0
                if (Py_TOLOWER(encoding[0]) == 'b')
1196
0
                    return ENC_UTF32BE;
1197
0
                if (Py_TOLOWER(encoding[0]) == 'l')
1198
0
                    return ENC_UTF32LE;
1199
0
            }
1200
0
        }
1201
8
    }
1202
0
    else if (strcmp(encoding, "cp65001") == 0) {
1203
0
        *bytelength = 3;
1204
0
        return ENC_UTF8;
1205
0
    }
1206
0
    return ENC_UNKNOWN;
1207
8
}
1208
1209
1210
static int
1211
get_standard_encoding(PyObject *encoding, int *code, int *bytelength)
1212
8
{
1213
8
    const char *encoding_cstr = PyUnicode_AsUTF8(encoding);
1214
8
    if (encoding_cstr == NULL) {
1215
0
        return -1;
1216
0
    }
1217
8
    *code = get_standard_encoding_impl(encoding_cstr, bytelength);
1218
8
    return 0;
1219
8
}
1220
1221
1222
// --- handler: 'surrogatepass' -----------------------------------------------
1223
1224
static PyObject *
1225
_PyCodec_SurrogatePassUnicodeEncodeError(PyObject *exc)
1226
0
{
1227
0
    PyObject *encoding = PyUnicodeEncodeError_GetEncoding(exc);
1228
0
    if (encoding == NULL) {
1229
0
        return NULL;
1230
0
    }
1231
0
    int code, bytelength;
1232
0
    int rc = get_standard_encoding(encoding, &code, &bytelength);
1233
0
    Py_DECREF(encoding);
1234
0
    if (rc < 0) {
1235
0
        return NULL;
1236
0
    }
1237
0
    if (code == ENC_UNKNOWN) {
1238
0
        goto bail;
1239
0
    }
1240
1241
0
    PyObject *obj;
1242
0
    Py_ssize_t objlen, start, end, slen;
1243
0
    if (_PyUnicodeError_GetParams(exc,
1244
0
                                  &obj, &objlen,
1245
0
                                  &start, &end, &slen, false) < 0)
1246
0
    {
1247
0
        return NULL;
1248
0
    }
1249
1250
0
    if (slen > PY_SSIZE_T_MAX / bytelength) {
1251
0
        end = start + PY_SSIZE_T_MAX / bytelength;
1252
0
        end = Py_MIN(end, objlen);
1253
0
        slen = Py_MAX(0, end - start);
1254
0
    }
1255
1256
0
    PyObject *res = PyBytes_FromStringAndSize(NULL, bytelength * slen);
1257
0
    if (res == NULL) {
1258
0
        Py_DECREF(obj);
1259
0
        return NULL;
1260
0
    }
1261
1262
0
    unsigned char *outp = (unsigned char *)PyBytes_AsString(res);
1263
0
    for (Py_ssize_t i = start; i < end; i++) {
1264
0
        Py_UCS4 ch = PyUnicode_READ_CHAR(obj, i);
1265
0
        if (!Py_UNICODE_IS_SURROGATE(ch)) {
1266
            /* Not a surrogate, fail with original exception */
1267
0
            Py_DECREF(obj);
1268
0
            Py_DECREF(res);
1269
0
            goto bail;
1270
0
        }
1271
0
        switch (code) {
1272
0
            case ENC_UTF8: {
1273
0
                *outp++ = (unsigned char)(0xe0 | (ch >> 12));
1274
0
                *outp++ = (unsigned char)(0x80 | ((ch >> 6) & 0x3f));
1275
0
                *outp++ = (unsigned char)(0x80 | (ch & 0x3f));
1276
0
                break;
1277
0
            }
1278
0
            case ENC_UTF16LE: {
1279
0
                *outp++ = (unsigned char)ch;
1280
0
                *outp++ = (unsigned char)(ch >> 8);
1281
0
                break;
1282
0
            }
1283
0
            case ENC_UTF16BE: {
1284
0
                *outp++ = (unsigned char)(ch >> 8);
1285
0
                *outp++ = (unsigned char)ch;
1286
0
                break;
1287
0
            }
1288
0
            case ENC_UTF32LE: {
1289
0
                *outp++ = (unsigned char)ch;
1290
0
                *outp++ = (unsigned char)(ch >> 8);
1291
0
                *outp++ = (unsigned char)(ch >> 16);
1292
0
                *outp++ = (unsigned char)(ch >> 24);
1293
0
                break;
1294
0
            }
1295
0
            case ENC_UTF32BE: {
1296
0
                *outp++ = (unsigned char)(ch >> 24);
1297
0
                *outp++ = (unsigned char)(ch >> 16);
1298
0
                *outp++ = (unsigned char)(ch >> 8);
1299
0
                *outp++ = (unsigned char)ch;
1300
0
                break;
1301
0
            }
1302
0
        }
1303
0
    }
1304
1305
0
    Py_DECREF(obj);
1306
0
    PyObject *restuple = Py_BuildValue("(Nn)", res, end);
1307
0
    return restuple;
1308
1309
0
bail:
1310
0
    PyErr_SetObject(PyExceptionInstance_Class(exc), exc);
1311
0
    return NULL;
1312
0
}
1313
1314
1315
static PyObject *
1316
_PyCodec_SurrogatePassUnicodeDecodeError(PyObject *exc)
1317
8
{
1318
8
    PyObject *encoding = PyUnicodeDecodeError_GetEncoding(exc);
1319
8
    if (encoding == NULL) {
1320
0
        return NULL;
1321
0
    }
1322
8
    int code, bytelength;
1323
8
    int rc = get_standard_encoding(encoding, &code, &bytelength);
1324
8
    Py_DECREF(encoding);
1325
8
    if (rc < 0) {
1326
0
        return NULL;
1327
0
    }
1328
8
    if (code == ENC_UNKNOWN) {
1329
0
        goto bail;
1330
0
    }
1331
1332
8
    PyObject *obj;
1333
8
    Py_ssize_t objlen, start, end, slen;
1334
8
    if (_PyUnicodeError_GetParams(exc,
1335
8
                                  &obj, &objlen,
1336
8
                                  &start, &end, &slen, true) < 0)
1337
0
    {
1338
0
        return NULL;
1339
0
    }
1340
1341
    /* Try decoding a single surrogate character. If
1342
       there are more, let the codec call us again. */
1343
8
    Py_UCS4 ch = 0;
1344
8
    const unsigned char *p = (const unsigned char *)PyBytes_AS_STRING(obj);
1345
8
    p += start;
1346
1347
8
    if (objlen - start >= bytelength) {
1348
8
        switch (code) {
1349
8
            case ENC_UTF8: {
1350
8
                if ((p[0] & 0xf0) == 0xe0 &&
1351
8
                    (p[1] & 0xc0) == 0x80 &&
1352
8
                    (p[2] & 0xc0) == 0x80)
1353
8
                {
1354
                    /* it's a three-byte code */
1355
8
                    ch = ((p[0] & 0x0f) << 12) +
1356
8
                         ((p[1] & 0x3f) << 6)  +
1357
8
                          (p[2] & 0x3f);
1358
8
                }
1359
8
                break;
1360
0
            }
1361
0
            case ENC_UTF16LE: {
1362
0
                ch = p[1] << 8 | p[0];
1363
0
                break;
1364
0
            }
1365
0
            case ENC_UTF16BE: {
1366
0
                ch = p[0] << 8 | p[1];
1367
0
                break;
1368
0
            }
1369
0
            case ENC_UTF32LE: {
1370
0
                ch = (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
1371
0
                break;
1372
0
            }
1373
0
            case ENC_UTF32BE: {
1374
0
                ch = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
1375
0
                break;
1376
0
            }
1377
8
        }
1378
8
    }
1379
8
    Py_DECREF(obj);
1380
8
    if (!Py_UNICODE_IS_SURROGATE(ch)) {
1381
0
        goto bail;
1382
0
    }
1383
1384
8
    PyObject *res = PyUnicode_FromOrdinal(ch);
1385
8
    if (res == NULL) {
1386
0
        return NULL;
1387
0
    }
1388
8
    return Py_BuildValue("(Nn)", res, start + bytelength);
1389
1390
0
bail:
1391
0
    PyErr_SetObject(PyExceptionInstance_Class(exc), exc);
1392
0
    return NULL;
1393
8
}
1394
1395
1396
/* This handler is declared static until someone demonstrates
1397
   a need to call it directly. */
1398
static PyObject *
1399
PyCodec_SurrogatePassErrors(PyObject *exc)
1400
8
{
1401
8
    if (_PyIsUnicodeEncodeError(exc)) {
1402
0
        return _PyCodec_SurrogatePassUnicodeEncodeError(exc);
1403
0
    }
1404
8
    else if (_PyIsUnicodeDecodeError(exc)) {
1405
8
        return _PyCodec_SurrogatePassUnicodeDecodeError(exc);
1406
8
    }
1407
0
    else {
1408
0
        wrong_exception_type(exc);
1409
0
        return NULL;
1410
0
    }
1411
8
}
1412
1413
1414
// --- handler: 'surrogateescape' ---------------------------------------------
1415
1416
static PyObject *
1417
_PyCodec_SurrogateEscapeUnicodeEncodeError(PyObject *exc)
1418
11.8k
{
1419
11.8k
    PyObject *obj;
1420
11.8k
    Py_ssize_t start, end, slen;
1421
11.8k
    if (_PyUnicodeError_GetParams(exc,
1422
11.8k
                                  &obj, NULL,
1423
11.8k
                                  &start, &end, &slen, false) < 0)
1424
0
    {
1425
0
        return NULL;
1426
0
    }
1427
1428
11.8k
    PyBytesWriter *writer = PyBytesWriter_Create(slen);
1429
11.8k
    if (writer == NULL) {
1430
0
        Py_DECREF(obj);
1431
0
        return NULL;
1432
0
    }
1433
1434
11.8k
    char *outp = PyBytesWriter_GetData(writer);
1435
11.8k
    for (Py_ssize_t i = start; i < end; i++) {
1436
11.8k
        Py_UCS4 ch = PyUnicode_READ_CHAR(obj, i);
1437
11.8k
        if (ch < 0xdc80 || ch > 0xdcff) {
1438
            /* Not a UTF-8b surrogate, fail with original exception. */
1439
11.8k
            Py_DECREF(obj);
1440
11.8k
            PyBytesWriter_Discard(writer);
1441
11.8k
            PyErr_SetObject(PyExceptionInstance_Class(exc), exc);
1442
11.8k
            return NULL;
1443
11.8k
        }
1444
0
        *outp++ = ch - 0xdc00;
1445
0
    }
1446
0
    Py_DECREF(obj);
1447
1448
0
    PyObject *res = PyBytesWriter_Finish(writer);
1449
    // Py_BuildValue() propagates the exception if res is NULL
1450
0
    return Py_BuildValue("(Nn)", res, end);
1451
11.8k
}
1452
1453
1454
static PyObject *
1455
_PyCodec_SurrogateEscapeUnicodeDecodeError(PyObject *exc)
1456
196k
{
1457
196k
    PyObject *obj;
1458
196k
    Py_ssize_t start, end, slen;
1459
196k
    if (_PyUnicodeError_GetParams(exc,
1460
196k
                                  &obj, NULL,
1461
196k
                                  &start, &end, &slen, true) < 0)
1462
0
    {
1463
0
        return NULL;
1464
0
    }
1465
1466
196k
    Py_UCS2 ch[4]; /* decode up to 4 bad bytes. */
1467
196k
    int consumed = 0;
1468
196k
    const unsigned char *p = (const unsigned char *)PyBytes_AS_STRING(obj);
1469
397k
    while (consumed < 4 && consumed < slen) {
1470
        /* Refuse to escape ASCII bytes. */
1471
220k
        if (p[start + consumed] < 128) {
1472
19.3k
            break;
1473
19.3k
        }
1474
201k
        ch[consumed] = 0xdc00 + p[start + consumed];
1475
201k
        consumed++;
1476
201k
    }
1477
196k
    Py_DECREF(obj);
1478
1479
196k
    if (consumed == 0) {
1480
        /* Codec complained about ASCII byte. */
1481
12.3k
        PyErr_SetObject(PyExceptionInstance_Class(exc), exc);
1482
12.3k
        return NULL;
1483
12.3k
    }
1484
1485
184k
    PyObject *str = PyUnicode_FromKindAndData(PyUnicode_2BYTE_KIND, ch, consumed);
1486
184k
    if (str == NULL) {
1487
0
        return NULL;
1488
0
    }
1489
184k
    return Py_BuildValue("(Nn)", str, start + consumed);
1490
184k
}
1491
1492
1493
static PyObject *
1494
PyCodec_SurrogateEscapeErrors(PyObject *exc)
1495
208k
{
1496
208k
    if (_PyIsUnicodeEncodeError(exc)) {
1497
11.8k
        return _PyCodec_SurrogateEscapeUnicodeEncodeError(exc);
1498
11.8k
    }
1499
196k
    else if (_PyIsUnicodeDecodeError(exc)) {
1500
196k
        return _PyCodec_SurrogateEscapeUnicodeDecodeError(exc);
1501
196k
    }
1502
0
    else {
1503
0
        wrong_exception_type(exc);
1504
0
        return NULL;
1505
0
    }
1506
208k
}
1507
1508
1509
// --- Codecs registry handlers -----------------------------------------------
1510
1511
static inline PyObject *
1512
strict_errors(PyObject *Py_UNUSED(self), PyObject *exc)
1513
2.73M
{
1514
2.73M
    return PyCodec_StrictErrors(exc);
1515
2.73M
}
1516
1517
1518
static inline PyObject *
1519
ignore_errors(PyObject *Py_UNUSED(self), PyObject *exc)
1520
0
{
1521
0
    return PyCodec_IgnoreErrors(exc);
1522
0
}
1523
1524
1525
static inline PyObject *
1526
replace_errors(PyObject *Py_UNUSED(self), PyObject *exc)
1527
300k
{
1528
300k
    return PyCodec_ReplaceErrors(exc);
1529
300k
}
1530
1531
1532
static inline PyObject *
1533
xmlcharrefreplace_errors(PyObject *Py_UNUSED(self), PyObject *exc)
1534
0
{
1535
0
    return PyCodec_XMLCharRefReplaceErrors(exc);
1536
0
}
1537
1538
1539
static inline PyObject *
1540
backslashreplace_errors(PyObject *Py_UNUSED(self), PyObject *exc)
1541
0
{
1542
0
    return PyCodec_BackslashReplaceErrors(exc);
1543
0
}
1544
1545
1546
static inline PyObject *
1547
namereplace_errors(PyObject *Py_UNUSED(self), PyObject *exc)
1548
0
{
1549
0
    return PyCodec_NameReplaceErrors(exc);
1550
0
}
1551
1552
1553
static inline PyObject *
1554
surrogatepass_errors(PyObject *Py_UNUSED(self), PyObject *exc)
1555
8
{
1556
8
    return PyCodec_SurrogatePassErrors(exc);
1557
8
}
1558
1559
1560
static inline PyObject *
1561
surrogateescape_errors(PyObject *Py_UNUSED(self), PyObject *exc)
1562
208k
{
1563
208k
    return PyCodec_SurrogateEscapeErrors(exc);
1564
208k
}
1565
1566
1567
PyStatus
1568
_PyCodec_InitRegistry(PyInterpreterState *interp)
1569
37
{
1570
37
    static struct {
1571
37
        const char *name;
1572
37
        PyMethodDef def;
1573
37
    } methods[] =
1574
37
    {
1575
37
        {
1576
37
            "strict",
1577
37
            {
1578
37
                "strict_errors",
1579
37
                strict_errors,
1580
37
                METH_O,
1581
37
                PyDoc_STR("Implements the 'strict' error handling, which "
1582
37
                          "raises a UnicodeError on coding errors.")
1583
37
            }
1584
37
        },
1585
37
        {
1586
37
            "ignore",
1587
37
            {
1588
37
                "ignore_errors",
1589
37
                ignore_errors,
1590
37
                METH_O,
1591
37
                PyDoc_STR("Implements the 'ignore' error handling, which "
1592
37
                          "ignores malformed data and continues.")
1593
37
            }
1594
37
        },
1595
37
        {
1596
37
            "replace",
1597
37
            {
1598
37
                "replace_errors",
1599
37
                replace_errors,
1600
37
                METH_O,
1601
37
                PyDoc_STR("Implements the 'replace' error handling, which "
1602
37
                          "replaces malformed data with a replacement marker.")
1603
37
            }
1604
37
        },
1605
37
        {
1606
37
            "xmlcharrefreplace",
1607
37
            {
1608
37
                "xmlcharrefreplace_errors",
1609
37
                xmlcharrefreplace_errors,
1610
37
                METH_O,
1611
37
                PyDoc_STR("Implements the 'xmlcharrefreplace' error handling, "
1612
37
                          "which replaces an unencodable character with the "
1613
37
                          "appropriate XML character reference.")
1614
37
            }
1615
37
        },
1616
37
        {
1617
37
            "backslashreplace",
1618
37
            {
1619
37
                "backslashreplace_errors",
1620
37
                backslashreplace_errors,
1621
37
                METH_O,
1622
37
                PyDoc_STR("Implements the 'backslashreplace' error handling, "
1623
37
                          "which replaces malformed data with a backslashed "
1624
37
                          "escape sequence.")
1625
37
            }
1626
37
        },
1627
37
        {
1628
37
            "namereplace",
1629
37
            {
1630
37
                "namereplace_errors",
1631
37
                namereplace_errors,
1632
37
                METH_O,
1633
37
                PyDoc_STR("Implements the 'namereplace' error handling, "
1634
37
                          "which replaces an unencodable character with a "
1635
37
                          "\\N{...} escape sequence.")
1636
37
            }
1637
37
        },
1638
37
        {
1639
37
            "surrogatepass",
1640
37
            {
1641
37
                "surrogatepass",
1642
37
                surrogatepass_errors,
1643
37
                METH_O
1644
37
            }
1645
37
        },
1646
37
        {
1647
37
            "surrogateescape",
1648
37
            {
1649
37
                "surrogateescape",
1650
37
                surrogateescape_errors,
1651
37
                METH_O
1652
37
            }
1653
37
        }
1654
37
    };
1655
    // ensure that the built-in error handlers' names are kept in sync
1656
37
    assert(Py_ARRAY_LENGTH(methods) == Py_ARRAY_LENGTH(codecs_builtin_error_handlers));
1657
1658
37
    assert(interp->codecs.initialized == 0);
1659
37
    interp->codecs.search_path = PyList_New(0);
1660
37
    if (interp->codecs.search_path == NULL) {
1661
0
        return PyStatus_NoMemory();
1662
0
    }
1663
37
    interp->codecs.search_cache = PyDict_New();
1664
37
    if (interp->codecs.search_cache == NULL) {
1665
0
        return PyStatus_NoMemory();
1666
0
    }
1667
37
    interp->codecs.error_registry = PyDict_New();
1668
37
    if (interp->codecs.error_registry == NULL) {
1669
0
        return PyStatus_NoMemory();
1670
0
    }
1671
333
    for (size_t i = 0; i < Py_ARRAY_LENGTH(methods); ++i) {
1672
296
        PyObject *func = PyCFunction_NewEx(&methods[i].def, NULL, NULL);
1673
296
        if (func == NULL) {
1674
0
            return PyStatus_NoMemory();
1675
0
        }
1676
1677
296
        int res = PyDict_SetItemString(interp->codecs.error_registry,
1678
296
                                       methods[i].name, func);
1679
296
        Py_DECREF(func);
1680
296
        if (res < 0) {
1681
0
            return PyStatus_Error("Failed to insert into codec error registry");
1682
0
        }
1683
296
    }
1684
1685
37
    interp->codecs.initialized = 1;
1686
1687
    // Importing `encodings' will call back into this module to register codec
1688
    // search functions, so this is done after everything else is initialized.
1689
37
    PyObject *mod = PyImport_ImportModule("encodings");
1690
37
    if (mod == NULL) {
1691
0
        PyThreadState *tstate = _PyThreadState_GET();
1692
0
        _Py_DumpPathConfig(tstate);
1693
0
        return PyStatus_Error("Failed to import encodings module. "
1694
0
                              "Your environment probably has misconfigured variables! "
1695
0
                              "Please check PYTHONHOME otherwise refer to `--help-env`");
1696
0
    }
1697
37
    Py_DECREF(mod);
1698
1699
37
    return PyStatus_Ok();
1700
37
}
1701
1702
void
1703
_PyCodec_Fini(PyInterpreterState *interp)
1704
0
{
1705
0
    Py_CLEAR(interp->codecs.search_path);
1706
0
    Py_CLEAR(interp->codecs.search_cache);
1707
    Py_CLEAR(interp->codecs.error_registry);
1708
0
    interp->codecs.initialized = 0;
1709
0
}