Coverage Report

Created: 2026-10-17 06:15

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