LCOV - code coverage report
Current view: | top level - Objects/stringlib - codecs.h (source / functions) |  |  | Hit | Total | Coverage
Test: | CPython 3.12 LCOV report [commit 5e6661bce9] |  | Lines: | 129 | 414 | 31.2 %
Date: | 2023-03-20 08:15:36 |  | Functions: | 7 | 20 | 35.0 %
|  |  | Branches: | 60 | 235 | 25.5 %

               Branch data     Line data    Source code
           1                 :            : /* stringlib: codec implementations */
           2                 :            :
           3                 :            : #if !STRINGLIB_IS_UNICODE
           4                 :            : # error "codecs.h is specific to Unicode"
           5                 :            : #endif
           6                 :            :
           7                 :            : #include "pycore_bitutils.h"      // _Py_bswap32()
           8                 :            :
           9                 :            : /* Mask to quickly check whether a C 'size_t' contains a
          10                 :            :    non-ASCII, UTF8-encoded char. */
          11                 :            : #if (SIZEOF_SIZE_T == 8)
          12                 :            : # define ASCII_CHAR_MASK 0x8080808080808080ULL
          13                 :            : #elif (SIZEOF_SIZE_T == 4)
          14                 :            : # define ASCII_CHAR_MASK 0x80808080U
          15                 :            : #else
          16                 :            : # error C 'size_t' size should be either 4 or 8!
          17                 :            : #endif
          18                 :            :
          19                 :            : /* 10xxxxxx */
          20                 :            : #define IS_CONTINUATION_BYTE(ch) ((ch) >= 0x80 && (ch) < 0xC0)
          21                 :            :
          22                 :            : Py_LOCAL_INLINE(Py_UCS4)
          23                 :        200 : STRINGLIB(utf8_decode)(const char **inptr, const char *end,
          24                 :            :                        STRINGLIB_CHAR *dest,
          25                 :            :                        Py_ssize_t *outpos)
          26                 :            : {
          27                 :            :     Py_UCS4 ch;
          28                 :        200 :     const char *s = *inptr;
          29                 :        200 :     STRINGLIB_CHAR *p = dest + *outpos;
          30                 :            :
          31         [ +  + ]:       3380 :     while (s < end) {
          32                 :       3328 :         ch = (unsigned char)*s;
          33                 :            :
          34         [ +  + ]:       3328 :         if (ch < 0x80) {
          35                 :            :             /* Fast path for runs of ASCII characters. Given that common UTF-8
          36                 :            :                input will consist of an overwhelming majority of ASCII
          37                 :            :                characters, we try to optimize for this case by checking
          38                 :            :                as many characters as a C 'size_t' can contain.
          39                 :            :                First, check if we can do an aligned read, as most CPUs have
          40                 :            :                a penalty for unaligned reads.
          41                 :            :             */
          42         [ +  + ]:        364 :             if (_Py_IS_ALIGNED(s, ALIGNOF_SIZE_T)) {
          43                 :            :                 /* Help register allocation */
          44                 :         66 :                 const char *_s = s;
          45                 :         66 :                 STRINGLIB_CHAR *_p = p;
          46         [ +  + ]:      27327 :                 while (_s + SIZEOF_SIZE_T <= end) {
          47                 :            :                     /* Read a whole size_t at a time (either 4 or 8 bytes),
          48                 :            :                        and do a fast unrolled copy if it only contains ASCII
          49                 :            :                        characters. */
          50                 :      27273 :                     size_t value = *(const size_t *) _s;
          51         [ +  + ]:      27273 :                     if (value & ASCII_CHAR_MASK)
          52                 :         12 :                         break;
          53                 :            : #if PY_LITTLE_ENDIAN
          54                 :      27261 :                     _p[0] = (STRINGLIB_CHAR)(value & 0xFFu);
          55                 :      27261 :                     _p[1] = (STRINGLIB_CHAR)((value >> 8) & 0xFFu);
          56                 :      27261 :                     _p[2] = (STRINGLIB_CHAR)((value >> 16) & 0xFFu);
          57                 :      27261 :                     _p[3] = (STRINGLIB_CHAR)((value >> 24) & 0xFFu);
          58                 :            : # if SIZEOF_SIZE_T == 8
          59                 :      27261 :                     _p[4] = (STRINGLIB_CHAR)((value >> 32) & 0xFFu);
          60                 :      27261 :                     _p[5] = (STRINGLIB_CHAR)((value >> 40) & 0xFFu);
          61                 :      27261 :                     _p[6] = (STRINGLIB_CHAR)((value >> 48) & 0xFFu);
          62                 :      27261 :                     _p[7] = (STRINGLIB_CHAR)((value >> 56) & 0xFFu);
          63                 :            : # endif
          64                 :            : #else
          65                 :            : # if SIZEOF_SIZE_T == 8
          66                 :            :                     _p[0] = (STRINGLIB_CHAR)((value >> 56) & 0xFFu);
          67                 :            :                     _p[1] = (STRINGLIB_CHAR)((value >> 48) & 0xFFu);
          68                 :            :                     _p[2] = (STRINGLIB_CHAR)((value >> 40) & 0xFFu);
          69                 :            :                     _p[3] = (STRINGLIB_CHAR)((value >> 32) & 0xFFu);
          70                 :            :                     _p[4] = (STRINGLIB_CHAR)((value >> 24) & 0xFFu);
          71                 :            :                     _p[5] = (STRINGLIB_CHAR)((value >> 16) & 0xFFu);
          72                 :            :                     _p[6] = (STRINGLIB_CHAR)((value >> 8) & 0xFFu);
          73                 :            :                     _p[7] = (STRINGLIB_CHAR)(value & 0xFFu);
          74                 :            : # else
          75                 :            :                     _p[0] = (STRINGLIB_CHAR)((value >> 24) & 0xFFu);
          76                 :            :                     _p[1] = (STRINGLIB_CHAR)((value >> 16) & 0xFFu);
          77                 :            :                     _p[2] = (STRINGLIB_CHAR)((value >> 8) & 0xFFu);
          78                 :            :                     _p[3] = (STRINGLIB_CHAR)(value & 0xFFu);
          79                 :            : # endif
          80                 :            : #endif
          81                 :      27261 :                     _s += SIZEOF_SIZE_T;
          82                 :      27261 :                     _p += SIZEOF_SIZE_T;
          83                 :            :                 }
          84                 :         66 :                 s = _s;
          85                 :         66 :                 p = _p;
          86         [ +  + ]:         66 :                 if (s == end)
          87                 :         28 :                     break;
          88                 :         38 :                 ch = (unsigned char)*s;
          89                 :            :             }
          90         [ +  + ]:        336 :             if (ch < 0x80) {
          91                 :        335 :                 s++;
          92                 :        335 :                 *p++ = ch;
          93                 :        335 :                 continue;
          94                 :            :             }
          95                 :            :         }
          96                 :            :
          97         [ +  + ]:       2965 :         if (ch < 0xE0) {
          98                 :            :             /* \xC2\x80-\xDF\xBF -- 0080-07FF */
          99                 :            :             Py_UCS4 ch2;
         100         [ -  + ]:       1566 :             if (ch < 0xC2) {
         101                 :            :                 /* invalid sequence
         102                 :            :                 \x80-\xBF -- continuation byte
         103                 :            :                 \xC0-\xC1 -- fake 0000-007F */
         104                 :          0 :                 goto InvalidStart;
         105                 :            :             }
         106         [ -  + ]:       1566 :             if (end - s < 2) {
         107                 :            :                 /* unexpected end of data: the caller will decide whether
         108                 :            :                    it's an error or not */
         109                 :          0 :                 break;
         110                 :            :             }
         111                 :       1566 :             ch2 = (unsigned char)s[1];
         112   [ +  -  -  + ]:       1566 :             if (!IS_CONTINUATION_BYTE(ch2))
         113                 :            :                 /* invalid continuation byte */
         114                 :          0 :                 goto InvalidContinuation1;
         115                 :       1566 :             ch = (ch << 6) + ch2 -
         116                 :            :                  ((0xC0 << 6) + 0x80);
         117                 :            :             assert ((ch > 0x007F) && (ch <= 0x07FF));
         118                 :       1566 :             s += 2;
         119         [ -  + ]:        701 :             if (STRINGLIB_MAX_CHAR <= 0x007F ||
         120                 :            :                 (STRINGLIB_MAX_CHAR < 0x07FF && ch > STRINGLIB_MAX_CHAR))
         121                 :            :                 /* Out-of-range */
         122                 :         71 :                 goto Return;
         123                 :       1495 :             *p++ = ch;
         124                 :       1495 :             continue;
         125                 :            :         }
         126                 :            :
         127         [ +  + ]:       1399 :         if (ch < 0xF0) {
         128                 :            :             /* \xE0\xA0\x80-\xEF\xBF\xBF -- 0800-FFFF */
         129                 :            :             Py_UCS4 ch2, ch3;
         130         [ -  + ]:       1391 :             if (end - s < 3) {
         131                 :            :                 /* unexpected end of data: the caller will decide whether
         132                 :            :                    it's an error or not */
         133         [ #  # ]:          0 :                 if (end - s < 2)
         134                 :          0 :                     break;
         135                 :          0 :                 ch2 = (unsigned char)s[1];
         136   [ #  #  #  #  :          0 :                 if (!IS_CONTINUATION_BYTE(ch2) ||
              #  #  #  #  #
                          # ]
         137                 :            :                     (ch2 < 0xA0 ? ch == 0xE0 : ch == 0xED))
         138                 :            :                     /* for clarification see comments below */
         139                 :          0 :                     goto InvalidContinuation1;
         140                 :          0 :                 break;
         141                 :            :             }
         142                 :       1391 :             ch2 = (unsigned char)s[1];
         143                 :       1391 :             ch3 = (unsigned char)s[2];
         144   [ +  +  -  + ]:       1391 :             if (!IS_CONTINUATION_BYTE(ch2)) {
         145                 :            :                 /* invalid continuation byte */
         146                 :          6 :                 goto InvalidContinuation1;
         147                 :            :             }
         148         [ -  + ]:       1385 :             if (ch == 0xE0) {
         149         [ #  # ]:          0 :                 if (ch2 < 0xA0)
         150                 :            :                     /* invalid sequence
         151                 :            :                        \xE0\x80\x80-\xE0\x9F\xBF -- fake 0000-0800 */
         152                 :          0 :                     goto InvalidContinuation1;
         153   [ -  +  -  - ]:       1385 :             } else if (ch == 0xED && ch2 >= 0xA0) {
         154                 :            :                 /* Decoding UTF-8 sequences in range \xED\xA0\x80-\xED\xBF\xBF
         155                 :            :                    will result in surrogates in range D800-DFFF. Surrogates are
         156                 :            :                    not valid UTF-8 so they are rejected.
         157                 :            :                    See https://www.unicode.org/versions/Unicode5.2.0/ch03.pdf
         158                 :            :                    (table 3-7) and http://www.rfc-editor.org/rfc/rfc3629.txt */
         159                 :          0 :                 goto InvalidContinuation1;
         160                 :            :             }
         161   [ +  -  -  + ]:       1385 :             if (!IS_CONTINUATION_BYTE(ch3)) {
         162                 :            :                 /* invalid continuation byte */
         163                 :          0 :                 goto InvalidContinuation2;
         164                 :            :             }
         165                 :       1385 :             ch = (ch << 12) + (ch2 << 6) + ch3 -
         166                 :            :                  ((0xE0 << 12) + (0x80 << 6) + 0x80);
         167                 :            :             assert ((ch > 0x07FF) && (ch <= 0xFFFF));
         168                 :       1385 :             s += 3;
         169                 :            :             if (STRINGLIB_MAX_CHAR <= 0x07FF ||
         170                 :            :                 (STRINGLIB_MAX_CHAR < 0xFFFF && ch > STRINGLIB_MAX_CHAR))
         171                 :            :                 /* Out-of-range */
         172                 :         35 :                 goto Return;
         173                 :       1350 :             *p++ = ch;
         174                 :       1350 :             continue;
         175                 :            :         }
         176                 :            :
         177         [ +  + ]:          8 :         if (ch < 0xF5) {
         178                 :            :             /* \xF0\x90\x80\x80-\xF4\x8F\xBF\xBF -- 10000-10FFFF */
         179                 :            :             Py_UCS4 ch2, ch3, ch4;
         180         [ +  + ]:          6 :             if (end - s < 4) {
         181                 :            :                 /* unexpected end of data: the caller will decide whether
         182                 :            :                    it's an error or not */
         183         [ +  - ]:          5 :                 if (end - s < 2)
         184                 :          5 :                     break;
         185                 :          0 :                 ch2 = (unsigned char)s[1];
         186   [ #  #  #  #  :          0 :                 if (!IS_CONTINUATION_BYTE(ch2) ||
              #  #  #  #  #
                          # ]
         187                 :            :                     (ch2 < 0x90 ? ch == 0xF0 : ch == 0xF4))
         188                 :            :                     /* for clarification see comments below */
         189                 :          0 :                     goto InvalidContinuation1;
         190         [ #  # ]:          0 :                 if (end - s < 3)
         191                 :          0 :                     break;
         192                 :          0 :                 ch3 = (unsigned char)s[2];
         193   [ #  #  #  # ]:          0 :                 if (!IS_CONTINUATION_BYTE(ch3))
         194                 :          0 :                     goto InvalidContinuation2;
         195                 :          0 :                 break;
         196                 :            :             }
         197                 :          1 :             ch2 = (unsigned char)s[1];
         198                 :          1 :             ch3 = (unsigned char)s[2];
         199                 :          1 :             ch4 = (unsigned char)s[3];
         200   [ +  -  -  + ]:          1 :             if (!IS_CONTINUATION_BYTE(ch2)) {
         201                 :            :                 /* invalid continuation byte */
         202                 :          0 :                 goto InvalidContinuation1;
         203                 :            :             }
         204         [ +  - ]:          1 :             if (ch == 0xF0) {
         205         [ -  + ]:          1 :                 if (ch2 < 0x90)
         206                 :            :                     /* invalid sequence
         207                 :            :                        \xF0\x80\x80\x80-\xF0\x8F\xBF\xBF -- fake 0000-FFFF */
         208                 :          0 :                     goto InvalidContinuation1;
         209   [ #  #  #  # ]:          0 :             } else if (ch == 0xF4 && ch2 >= 0x90) {
         210                 :            :                 /* invalid sequence
         211                 :            :                    \xF4\x90\x80\x80- -- 110000- overflow */
         212                 :          0 :                 goto InvalidContinuation1;
         213                 :            :             }
         214   [ +  -  -  + ]:          1 :             if (!IS_CONTINUATION_BYTE(ch3)) {
         215                 :            :                 /* invalid continuation byte */
         216                 :          0 :                 goto InvalidContinuation2;
         217                 :            :             }
         218   [ +  -  -  + ]:          1 :             if (!IS_CONTINUATION_BYTE(ch4)) {
         219                 :            :                 /* invalid continuation byte */
         220                 :          0 :                 goto InvalidContinuation3;
         221                 :            :             }
         222                 :          1 :             ch = (ch << 18) + (ch2 << 12) + (ch3 << 6) + ch4 -
         223                 :            :                  ((0xF0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80);
         224                 :            :             assert ((ch > 0xFFFF) && (ch <= 0x10FFFF));
         225                 :          1 :             s += 4;
         226                 :            :             if (STRINGLIB_MAX_CHAR <= 0xFFFF ||
         227                 :            :                 (STRINGLIB_MAX_CHAR < 0x10FFFF && ch > STRINGLIB_MAX_CHAR))
         228                 :            :                 /* Out-of-range */
         229                 :          1 :                 goto Return;
         230                 :          0 :             *p++ = ch;
         231                 :          0 :             continue;
         232                 :            :         }
         233                 :          2 :         goto InvalidStart;
         234                 :            :     }
         235                 :         85 :     ch = 0;
         236                 :        200 : Return:
         237                 :        200 :     *inptr = s;
         238                 :        200 :     *outpos = p - dest;
         239                 :        200 :     return ch;
         240                 :          2 : InvalidStart:
         241                 :          2 :     ch = 1;
         242                 :          2 :     goto Return;
         243                 :          6 : InvalidContinuation1:
         244                 :          6 :     ch = 2;
         245                 :          6 :     goto Return;
         246                 :          0 : InvalidContinuation2:
         247                 :          0 :     ch = 3;
         248                 :          0 :     goto Return;
         249                 :          0 : InvalidContinuation3:
         250                 :          0 :     ch = 4;
         251                 :          0 :     goto Return;
         252                 :            : }
         253                 :            :
         254                 :            : #undef ASCII_CHAR_MASK
         255                 :            :
         256                 :            :
         257                 :            : /* UTF-8 encoder specialized for a Unicode kind to avoid the slow
         258                 :            :    PyUnicode_READ() macro. Delete some parts of the code depending on the kind:
         259                 :            :    UCS-1 strings don't need to handle surrogates for example. */
         260                 :            : Py_LOCAL_INLINE(char *)
         261                 :         33 : STRINGLIB(utf8_encoder)(_PyBytesWriter *writer,
         262                 :            :                         PyObject *unicode,
         263                 :            :                         const STRINGLIB_CHAR *data,
         264                 :            :                         Py_ssize_t size,
         265                 :            :                         _Py_error_handler error_handler,
         266                 :            :                         const char *errors)
         267                 :            : {
         268                 :            :     Py_ssize_t i;                /* index into data of next input character */
         269                 :            :     char *p;                     /* next free byte in output buffer */
         270                 :            : #if STRINGLIB_SIZEOF_CHAR > 1
         271                 :         21 :     PyObject *error_handler_obj = NULL;
         272                 :         21 :     PyObject *exc = NULL;
         273                 :         21 :     PyObject *rep = NULL;
         274                 :            : #endif
         275                 :            : #if STRINGLIB_SIZEOF_CHAR == 1
         276                 :         12 :     const Py_ssize_t max_char_size = 2;
         277                 :            : #elif STRINGLIB_SIZEOF_CHAR == 2
         278                 :         19 :     const Py_ssize_t max_char_size = 3;
         279                 :            : #else /*  STRINGLIB_SIZEOF_CHAR == 4 */
         280                 :          2 :     const Py_ssize_t max_char_size = 4;
         281                 :            : #endif
         282                 :            :
         283                 :            :     assert(size >= 0);
         284         [ -  + ]:         33 :     if (size > PY_SSIZE_T_MAX / max_char_size) {
         285                 :            :         /* integer overflow */
         286                 :          0 :         PyErr_NoMemory();
         287                 :          0 :         return NULL;
         288                 :            :     }
         289                 :            :
         290                 :         33 :     _PyBytesWriter_Init(writer);
         291                 :         33 :     p = _PyBytesWriter_Alloc(writer, size * max_char_size);
         292         [ -  + ]:         33 :     if (p == NULL)
         293                 :          0 :         return NULL;
         294                 :            :
         295         [ +  + ]:       8329 :     for (i = 0; i < size;) {
         296                 :       8296 :         Py_UCS4 ch = data[i++];
         297                 :            :
         298         [ +  + ]:       8296 :         if (ch < 0x80) {
         299                 :            :             /* Encode ASCII */
         300                 :       7938 :             *p++ = (char) ch;
         301                 :            :
         302                 :            :         }
         303                 :            :         else
         304                 :            : #if STRINGLIB_SIZEOF_CHAR > 1
         305         [ +  + ]:        283 :         if (ch < 0x0800)
         306                 :            : #endif
         307                 :            :         {
         308                 :            :             /* Encode Latin-1 */
         309                 :        223 :             *p++ = (char)(0xc0 | (ch >> 6));
         310                 :        223 :             *p++ = (char)(0x80 | (ch & 0x3f));
         311                 :            :         }
         312                 :            : #if STRINGLIB_SIZEOF_CHAR > 1
         313         [ +  + ]:        135 :         else if (Py_UNICODE_IS_SURROGATE(ch)) {
         314                 :            :             Py_ssize_t startpos, endpos, newpos;
         315                 :            :             Py_ssize_t k;
         316         [ +  - ]:          1 :             if (error_handler == _Py_ERROR_UNKNOWN) {
         317                 :          1 :                 error_handler = _Py_GetErrorHandler(errors);
         318                 :            :             }
         319                 :            :
         320                 :          1 :             startpos = i-1;
         321                 :          1 :             endpos = startpos+1;
         322                 :            :
         323   [ -  +  -  - ]:          1 :             while ((endpos < size) && Py_UNICODE_IS_SURROGATE(data[endpos]))
         324                 :          0 :                 endpos++;
         325                 :            :
         326                 :            :             /* Only overallocate the buffer if it's not the last write */
         327                 :          1 :             writer->overallocate = (endpos < size);
         328                 :            :
         329   [ -  -  +  -  :          1 :             switch (error_handler)
                    -  -  - ]
         330                 :            :             {
         331                 :          0 :             case _Py_ERROR_REPLACE:
         332                 :          0 :                 memset(p, '?', endpos - startpos);
         333                 :          0 :                 p += (endpos - startpos);
         334                 :            :                 /* fall through */
         335                 :          0 :             case _Py_ERROR_IGNORE:
         336                 :          0 :                 i += (endpos - startpos - 1);
         337                 :          0 :                 break;
         338                 :            :
         339                 :          1 :             case _Py_ERROR_SURROGATEPASS:
         340         [ +  + ]:          2 :                 for (k=startpos; k<endpos; k++) {
         341                 :          1 :                     ch = data[k];
         342                 :          1 :                     *p++ = (char)(0xe0 | (ch >> 12));
         343                 :          1 :                     *p++ = (char)(0x80 | ((ch >> 6) & 0x3f));
         344                 :          1 :                     *p++ = (char)(0x80 | (ch & 0x3f));
         345                 :            :                 }
         346                 :          1 :                 i += (endpos - startpos - 1);
         347                 :          1 :                 break;
         348                 :            :
         349                 :          0 :             case _Py_ERROR_BACKSLASHREPLACE:
         350                 :            :                 /* subtract preallocated bytes */
         351                 :          0 :                 writer->min_size -= max_char_size * (endpos - startpos);
         352                 :          0 :                 p = backslashreplace(writer, p,
         353                 :            :                                      unicode, startpos, endpos);
         354         [ #  # ]:          0 :                 if (p == NULL)
         355                 :          0 :                     goto error;
         356                 :          0 :                 i += (endpos - startpos - 1);
         357                 :          0 :                 break;
         358                 :            :
         359                 :          0 :             case _Py_ERROR_XMLCHARREFREPLACE:
         360                 :            :                 /* subtract preallocated bytes */
         361                 :          0 :                 writer->min_size -= max_char_size * (endpos - startpos);
         362                 :          0 :                 p = xmlcharrefreplace(writer, p,
         363                 :            :                                       unicode, startpos, endpos);
         364         [ #  # ]:          0 :                 if (p == NULL)
         365                 :          0 :                     goto error;
         366                 :          0 :                 i += (endpos - startpos - 1);
         367                 :          0 :                 break;
         368                 :            :
         369                 :          0 :             case _Py_ERROR_SURROGATEESCAPE:
         370         [ #  # ]:          0 :                 for (k=startpos; k<endpos; k++) {
         371                 :          0 :                     ch = data[k];
         372   [ #  #  #  # ]:          0 :                     if (!(0xDC80 <= ch && ch <= 0xDCFF))
         373                 :            :                         break;
         374                 :          0 :                     *p++ = (char)(ch & 0xff);
         375                 :            :                 }
         376         [ #  # ]:          0 :                 if (k >= endpos) {
         377                 :          0 :                     i += (endpos - startpos - 1);
         378                 :          0 :                     break;
         379                 :            :                 }
         380                 :          0 :                 startpos = k;
         381                 :            :                 assert(startpos < endpos);
         382                 :            :                 /* fall through */
         383                 :          0 :             default:
         384                 :          0 :                 rep = unicode_encode_call_errorhandler(
         385                 :            :                       errors, &error_handler_obj, "utf-8", "surrogates not allowed",
         386                 :            :                       unicode, &exc, startpos, endpos, &newpos);
         387         [ #  # ]:          0 :                 if (!rep)
         388                 :          0 :                     goto error;
         389                 :            :
         390         [ #  # ]:          0 :                 if (newpos < startpos) {
         391                 :          0 :                     writer->overallocate = 1;
         392                 :          0 :                     p = _PyBytesWriter_Prepare(writer, p,
         393                 :          0 :                                                max_char_size * (startpos - newpos));
         394         [ #  # ]:          0 :                     if (p == NULL)
         395                 :          0 :                         goto error;
         396                 :            :                 }
         397                 :            :                 else {
         398                 :            :                     /* subtract preallocated bytes */
         399                 :          0 :                     writer->min_size -= max_char_size * (newpos - startpos);
         400                 :            :                     /* Only overallocate the buffer if it's not the last write */
         401                 :          0 :                     writer->overallocate = (newpos < size);
         402                 :            :                 }
         403                 :            :
         404         [ #  # ]:          0 :                 if (PyBytes_Check(rep)) {
         405                 :          0 :                     p = _PyBytesWriter_WriteBytes(writer, p,
         406                 :          0 :                                                   PyBytes_AS_STRING(rep),
         407                 :            :                                                   PyBytes_GET_SIZE(rep));
         408                 :            :                 }
         409                 :            :                 else {
         410                 :            :                     /* rep is unicode */
         411         [ #  # ]:          0 :                     if (PyUnicode_READY(rep) < 0)
         412                 :          0 :                         goto error;
         413                 :            :
         414         [ #  # ]:          0 :                     if (!PyUnicode_IS_ASCII(rep)) {
         415                 :          0 :                         raise_encode_exception(&exc, "utf-8", unicode,
         416                 :            :                                                startpos, endpos,
         417                 :            :                                                "surrogates not allowed");
         418                 :          0 :                         goto error;
         419                 :            :                     }
         420                 :            :
         421                 :          0 :                     p = _PyBytesWriter_WriteBytes(writer, p,
         422                 :          0 :                                                   PyUnicode_DATA(rep),
         423                 :            :                                                   PyUnicode_GET_LENGTH(rep));
         424                 :            :                 }
         425                 :            :
         426         [ #  # ]:          0 :                 if (p == NULL)
         427                 :          0 :                     goto error;
         428         [ #  # ]:          0 :                 Py_CLEAR(rep);
         429                 :            :
         430                 :          0 :                 i = newpos;
         431                 :            :             }
         432                 :            :
         433                 :            :             /* If overallocation was disabled, ensure that it was the last
         434                 :            :                write. Otherwise, we missed an optimization */
         435                 :            :             assert(writer->overallocate || i == size);
         436                 :            :         }
         437                 :            :         else
         438                 :            : #if STRINGLIB_SIZEOF_CHAR > 2
         439         [ -  + ]:          2 :         if (ch < 0x10000)
         440                 :            : #endif
         441                 :            :         {
         442                 :        132 :             *p++ = (char)(0xe0 | (ch >> 12));
         443                 :        132 :             *p++ = (char)(0x80 | ((ch >> 6) & 0x3f));
         444                 :        132 :             *p++ = (char)(0x80 | (ch & 0x3f));
         445                 :            :         }
         446                 :            : #if STRINGLIB_SIZEOF_CHAR > 2
         447                 :            :         else /* ch >= 0x10000 */
         448                 :            :         {
         449                 :            :             assert(ch <= MAX_UNICODE);
         450                 :            :             /* Encode UCS4 Unicode ordinals */
         451                 :          2 :             *p++ = (char)(0xf0 | (ch >> 18));
         452                 :          2 :             *p++ = (char)(0x80 | ((ch >> 12) & 0x3f));
         453                 :          2 :             *p++ = (char)(0x80 | ((ch >> 6) & 0x3f));
         454                 :          2 :             *p++ = (char)(0x80 | (ch & 0x3f));
         455                 :            :         }
         456                 :            : #endif /* STRINGLIB_SIZEOF_CHAR > 2 */
         457                 :            : #endif /* STRINGLIB_SIZEOF_CHAR > 1 */
         458                 :            :     }
         459                 :            :
         460                 :            : #if STRINGLIB_SIZEOF_CHAR > 1
         461                 :         21 :     Py_XDECREF(error_handler_obj);
         462                 :         21 :     Py_XDECREF(exc);
         463                 :            : #endif
         464                 :         33 :     return p;
         465                 :            :
         466                 :            : #if STRINGLIB_SIZEOF_CHAR > 1
         467                 :          0 :  error:
         468                 :          0 :     Py_XDECREF(rep);
         469                 :          0 :     Py_XDECREF(error_handler_obj);
         470                 :          0 :     Py_XDECREF(exc);
         471                 :          0 :     return NULL;
         472                 :            : #endif
         473                 :            : }
         474                 :            :
         475                 :            : /* The pattern for constructing UCS2-repeated masks. */
         476                 :            : #if SIZEOF_LONG == 8
         477                 :            : # define UCS2_REPEAT_MASK 0x0001000100010001ul
         478                 :            : #elif SIZEOF_LONG == 4
         479                 :            : # define UCS2_REPEAT_MASK 0x00010001ul
         480                 :            : #else
         481                 :            : # error C 'long' size should be either 4 or 8!
         482                 :            : #endif
         483                 :            :
         484                 :            : /* The mask for fast checking. */
         485                 :            : #if STRINGLIB_SIZEOF_CHAR == 1
         486                 :            : /* The mask for fast checking of whether a C 'long' contains a
         487                 :            :    non-ASCII or non-Latin1 UTF16-encoded characters. */
         488                 :            : # define FAST_CHAR_MASK         (UCS2_REPEAT_MASK * (0xFFFFu & ~STRINGLIB_MAX_CHAR))
         489                 :            : #else
         490                 :            : /* The mask for fast checking of whether a C 'long' may contain
         491                 :            :    UTF16-encoded surrogate characters. This is an efficient heuristic,
         492                 :            :    assuming that non-surrogate characters with a code point >= 0x8000 are
         493                 :            :    rare in most input.
         494                 :            : */
         495                 :            : # define FAST_CHAR_MASK         (UCS2_REPEAT_MASK * 0x8000u)
         496                 :            : #endif
         497                 :            : /* The mask for fast byte-swapping. */
         498                 :            : #define STRIPPED_MASK           (UCS2_REPEAT_MASK * 0x00FFu)
         499                 :            : /* Swap bytes. */
         500                 :            : #define SWAB(value)             ((((value) >> 8) & STRIPPED_MASK) | \
         501                 :            :                                  (((value) & STRIPPED_MASK) << 8))
         502                 :            :
         503                 :            : Py_LOCAL_INLINE(Py_UCS4)
         504                 :          0 : STRINGLIB(utf16_decode)(const unsigned char **inptr, const unsigned char *e,
         505                 :            :                         STRINGLIB_CHAR *dest, Py_ssize_t *outpos,
         506                 :            :                         int native_ordering)
         507                 :            : {
         508                 :            :     Py_UCS4 ch;
         509                 :          0 :     const unsigned char *q = *inptr;
         510                 :          0 :     STRINGLIB_CHAR *p = dest + *outpos;
         511                 :            :     /* Offsets from q for retrieving byte pairs in the right order. */
         512                 :            : #if PY_LITTLE_ENDIAN
         513                 :          0 :     int ihi = !!native_ordering, ilo = !native_ordering;
         514                 :            : #else
         515                 :            :     int ihi = !native_ordering, ilo = !!native_ordering;
         516                 :            : #endif
         517                 :          0 :     --e;
         518                 :            :
         519         [ #  # ]:          0 :     while (q < e) {
         520                 :            :         Py_UCS4 ch2;
         521                 :            :         /* First check for possible aligned read of a C 'long'. Unaligned
         522                 :            :            reads are more expensive, better to defer to another iteration. */
         523         [ #  # ]:          0 :         if (_Py_IS_ALIGNED(q, ALIGNOF_LONG)) {
         524                 :            :             /* Fast path for runs of in-range non-surrogate chars. */
         525                 :          0 :             const unsigned char *_q = q;
         526         [ #  # ]:          0 :             while (_q + SIZEOF_LONG <= e) {
         527                 :          0 :                 unsigned long block = * (const unsigned long *) _q;
         528         [ #  # ]:          0 :                 if (native_ordering) {
         529                 :            :                     /* Can use buffer directly */
         530         [ #  # ]:          0 :                     if (block & FAST_CHAR_MASK)
         531                 :          0 :                         break;
         532                 :            :                 }
         533                 :            :                 else {
         534                 :            :                     /* Need to byte-swap */
         535         [ #  # ]:          0 :                     if (block & SWAB(FAST_CHAR_MASK))
         536                 :          0 :                         break;
         537                 :            : #if STRINGLIB_SIZEOF_CHAR == 1
         538                 :          0 :                     block >>= 8;
         539                 :            : #else
         540                 :          0 :                     block = SWAB(block);
         541                 :            : #endif
         542                 :            :                 }
         543                 :            : #if PY_LITTLE_ENDIAN
         544                 :            : # if SIZEOF_LONG == 4
         545                 :            :                 p[0] = (STRINGLIB_CHAR)(block & 0xFFFFu);
         546                 :            :                 p[1] = (STRINGLIB_CHAR)(block >> 16);
         547                 :            : # elif SIZEOF_LONG == 8
         548                 :          0 :                 p[0] = (STRINGLIB_CHAR)(block & 0xFFFFu);
         549                 :          0 :                 p[1] = (STRINGLIB_CHAR)((block >> 16) & 0xFFFFu);
         550                 :          0 :                 p[2] = (STRINGLIB_CHAR)((block >> 32) & 0xFFFFu);
         551                 :          0 :                 p[3] = (STRINGLIB_CHAR)(block >> 48);
         552                 :            : # endif
         553                 :            : #else
         554                 :            : # if SIZEOF_LONG == 4
         555                 :            :                 p[0] = (STRINGLIB_CHAR)(block >> 16);
         556                 :            :                 p[1] = (STRINGLIB_CHAR)(block & 0xFFFFu);
         557                 :            : # elif SIZEOF_LONG == 8
         558                 :            :                 p[0] = (STRINGLIB_CHAR)(block >> 48);
         559                 :            :                 p[1] = (STRINGLIB_CHAR)((block >> 32) & 0xFFFFu);
         560                 :            :                 p[2] = (STRINGLIB_CHAR)((block >> 16) & 0xFFFFu);
         561                 :            :                 p[3] = (STRINGLIB_CHAR)(block & 0xFFFFu);
         562                 :            : # endif
         563                 :            : #endif
         564                 :          0 :                 _q += SIZEOF_LONG;
         565                 :          0 :                 p += SIZEOF_LONG / 2;
         566                 :            :             }
         567                 :          0 :             q = _q;
         568         [ #  # ]:          0 :             if (q >= e)
         569                 :          0 :                 break;
         570                 :            :         }
         571                 :            :
         572                 :          0 :         ch = (q[ihi] << 8) | q[ilo];
         573                 :          0 :         q += 2;
         574         [ #  # ]:          0 :         if (!Py_UNICODE_IS_SURROGATE(ch)) {
         575                 :            : #if STRINGLIB_SIZEOF_CHAR < 2
         576         [ #  # ]:          0 :             if (ch > STRINGLIB_MAX_CHAR)
         577                 :            :                 /* Out-of-range */
         578                 :          0 :                 goto Return;
         579                 :            : #endif
         580                 :          0 :             *p++ = (STRINGLIB_CHAR)ch;
         581                 :          0 :             continue;
         582                 :            :         }
         583                 :            :
         584                 :            :         /* UTF-16 code pair: */
         585         [ #  # ]:          0 :         if (!Py_UNICODE_IS_HIGH_SURROGATE(ch))
         586                 :          0 :             goto IllegalEncoding;
         587         [ #  # ]:          0 :         if (q >= e)
         588                 :          0 :             goto UnexpectedEnd;
         589                 :          0 :         ch2 = (q[ihi] << 8) | q[ilo];
         590                 :          0 :         q += 2;
         591         [ #  # ]:          0 :         if (!Py_UNICODE_IS_LOW_SURROGATE(ch2))
         592                 :          0 :             goto IllegalSurrogate;
         593                 :          0 :         ch = Py_UNICODE_JOIN_SURROGATES(ch, ch2);
         594                 :            : #if STRINGLIB_SIZEOF_CHAR < 4
         595                 :            :         /* Out-of-range */
         596                 :          0 :         goto Return;
         597                 :            : #else
         598                 :          0 :         *p++ = (STRINGLIB_CHAR)ch;
         599                 :            : #endif
         600                 :            :     }
         601                 :          0 :     ch = 0;
         602                 :          0 : Return:
         603                 :          0 :     *inptr = q;
         604                 :          0 :     *outpos = p - dest;
         605                 :          0 :     return ch;
         606                 :          0 : UnexpectedEnd:
         607                 :          0 :     ch = 1;
         608                 :          0 :     goto Return;
         609                 :          0 : IllegalEncoding:
         610                 :          0 :     ch = 2;
         611                 :          0 :     goto Return;
         612                 :          0 : IllegalSurrogate:
         613                 :          0 :     ch = 3;
         614                 :          0 :     goto Return;
         615                 :            : }
         616                 :            : #undef UCS2_REPEAT_MASK
         617                 :            : #undef FAST_CHAR_MASK
         618                 :            : #undef STRIPPED_MASK
         619                 :            : #undef SWAB
         620                 :            :
         621                 :            :
         622                 :            : #if STRINGLIB_MAX_CHAR >= 0x80
         623                 :            : Py_LOCAL_INLINE(Py_ssize_t)
         624                 :          0 : STRINGLIB(utf16_encode)(const STRINGLIB_CHAR *in,
         625                 :            :                         Py_ssize_t len,
         626                 :            :                         unsigned short **outptr,
         627                 :            :                         int native_ordering)
         628                 :            : {
         629                 :          0 :     unsigned short *out = *outptr;
         630                 :          0 :     const STRINGLIB_CHAR *end = in + len;
         631                 :            : #if STRINGLIB_SIZEOF_CHAR == 1
         632         [ #  # ]:          0 :     if (native_ordering) {
         633                 :          0 :         const STRINGLIB_CHAR *unrolled_end = in + _Py_SIZE_ROUND_DOWN(len, 4);
         634         [ #  # ]:          0 :         while (in < unrolled_end) {
         635                 :          0 :             out[0] = in[0];
         636                 :          0 :             out[1] = in[1];
         637                 :          0 :             out[2] = in[2];
         638                 :          0 :             out[3] = in[3];
         639                 :          0 :             in += 4; out += 4;
         640                 :            :         }
         641         [ #  # ]:          0 :         while (in < end) {
         642                 :          0 :             *out++ = *in++;
         643                 :            :         }
         644                 :            :     } else {
         645                 :            : # define SWAB2(CH)  ((CH) << 8) /* high byte is zero */
         646                 :          0 :         const STRINGLIB_CHAR *unrolled_end = in + _Py_SIZE_ROUND_DOWN(len, 4);
         647         [ #  # ]:          0 :         while (in < unrolled_end) {
         648                 :          0 :             out[0] = SWAB2(in[0]);
         649                 :          0 :             out[1] = SWAB2(in[1]);
         650                 :          0 :             out[2] = SWAB2(in[2]);
         651                 :          0 :             out[3] = SWAB2(in[3]);
         652                 :          0 :             in += 4; out += 4;
         653                 :            :         }
         654         [ #  # ]:          0 :         while (in < end) {
         655                 :          0 :             Py_UCS4 ch = *in++;
         656                 :          0 :             *out++ = SWAB2((Py_UCS2)ch);
         657                 :            :         }
         658                 :            : #undef SWAB2
         659                 :            :     }
         660                 :          0 :     *outptr = out;
         661                 :          0 :     return len;
         662                 :            : #else
         663         [ #  # ]:          0 :     if (native_ordering) {
         664                 :            : #if STRINGLIB_MAX_CHAR < 0x10000
         665                 :          0 :         const STRINGLIB_CHAR *unrolled_end = in + _Py_SIZE_ROUND_DOWN(len, 4);
         666         [ #  # ]:          0 :         while (in < unrolled_end) {
         667                 :            :             /* check if any character is a surrogate character */
         668                 :          0 :             if (((in[0] ^ 0xd800) &
         669                 :          0 :                  (in[1] ^ 0xd800) &
         670                 :          0 :                  (in[2] ^ 0xd800) &
         671         [ #  # ]:          0 :                  (in[3] ^ 0xd800) & 0xf800) == 0)
         672                 :          0 :                 break;
         673                 :          0 :             out[0] = in[0];
         674                 :          0 :             out[1] = in[1];
         675                 :          0 :             out[2] = in[2];
         676                 :          0 :             out[3] = in[3];
         677                 :          0 :             in += 4; out += 4;
         678                 :            :         }
         679                 :            : #endif
         680         [ #  # ]:          0 :         while (in < end) {
         681                 :            :             Py_UCS4 ch;
         682                 :          0 :             ch = *in++;
         683         [ #  # ]:          0 :             if (ch < 0xd800)
         684                 :          0 :                 *out++ = ch;
         685         [ #  # ]:          0 :             else if (ch < 0xe000)
         686                 :            :                 /* reject surrogate characters (U+D800-U+DFFF) */
         687                 :          0 :                 goto fail;
         688                 :            : #if STRINGLIB_MAX_CHAR >= 0x10000
         689         [ #  # ]:          0 :             else if (ch >= 0x10000) {
         690                 :          0 :                 out[0] = Py_UNICODE_HIGH_SURROGATE(ch);
         691                 :          0 :                 out[1] = Py_UNICODE_LOW_SURROGATE(ch);
         692                 :          0 :                 out += 2;
         693                 :            :             }
         694                 :            : #endif
         695                 :            :             else
         696                 :          0 :                 *out++ = ch;
         697                 :            :         }
         698                 :            :     } else {
         699                 :            : #define SWAB2(CH)  (((CH) << 8) | ((CH) >> 8))
         700                 :            : #if STRINGLIB_MAX_CHAR < 0x10000
         701                 :          0 :         const STRINGLIB_CHAR *unrolled_end = in + _Py_SIZE_ROUND_DOWN(len, 4);
         702         [ #  # ]:          0 :         while (in < unrolled_end) {
         703                 :            :             /* check if any character is a surrogate character */
         704                 :          0 :             if (((in[0] ^ 0xd800) &
         705                 :          0 :                  (in[1] ^ 0xd800) &
         706                 :          0 :                  (in[2] ^ 0xd800) &
         707         [ #  # ]:          0 :                  (in[3] ^ 0xd800) & 0xf800) == 0)
         708                 :          0 :                 break;
         709                 :          0 :             out[0] = SWAB2(in[0]);
         710                 :          0 :             out[1] = SWAB2(in[1]);
         711                 :          0 :             out[2] = SWAB2(in[2]);
         712                 :          0 :             out[3] = SWAB2(in[3]);
         713                 :          0 :             in += 4; out += 4;
         714                 :            :         }
         715                 :            : #endif
         716         [ #  # ]:          0 :         while (in < end) {
         717                 :          0 :             Py_UCS4 ch = *in++;
         718         [ #  # ]:          0 :             if (ch < 0xd800)
         719                 :          0 :                 *out++ = SWAB2((Py_UCS2)ch);
         720         [ #  # ]:          0 :             else if (ch < 0xe000)
         721                 :            :                 /* reject surrogate characters (U+D800-U+DFFF) */
         722                 :          0 :                 goto fail;
         723                 :            : #if STRINGLIB_MAX_CHAR >= 0x10000
         724         [ #  # ]:          0 :             else if (ch >= 0x10000) {
         725                 :          0 :                 Py_UCS2 ch1 = Py_UNICODE_HIGH_SURROGATE(ch);
         726                 :          0 :                 Py_UCS2 ch2 = Py_UNICODE_LOW_SURROGATE(ch);
         727                 :          0 :                 out[0] = SWAB2(ch1);
         728                 :          0 :                 out[1] = SWAB2(ch2);
         729                 :          0 :                 out += 2;
         730                 :            :             }
         731                 :            : #endif
         732                 :            :             else
         733                 :          0 :                 *out++ = SWAB2((Py_UCS2)ch);
         734                 :            :         }
         735                 :            : #undef SWAB2
         736                 :            :     }
         737                 :          0 :     *outptr = out;
         738                 :          0 :     return len;
         739                 :          0 :   fail:
         740                 :          0 :     *outptr = out;
         741                 :          0 :     return len - (end - in + 1);
         742                 :            : #endif
         743                 :            : }
         744                 :            :
         745                 :            : static inline uint32_t
         746                 :          0 : STRINGLIB(SWAB4)(STRINGLIB_CHAR ch)
         747                 :            : {
         748                 :          0 :     uint32_t word = ch;
         749                 :            : #if STRINGLIB_SIZEOF_CHAR == 1
         750                 :            :     /* high bytes are zero */
         751                 :          0 :     return (word << 24);
         752                 :            : #elif STRINGLIB_SIZEOF_CHAR == 2
         753                 :            :     /* high bytes are zero */
         754                 :          0 :     return ((word & 0x00FFu) << 24) | ((word & 0xFF00u) << 8);
         755                 :            : #else
         756                 :          0 :     return _Py_bswap32(word);
         757                 :            : #endif
         758                 :            : }
         759                 :            :
         760                 :            : Py_LOCAL_INLINE(Py_ssize_t)
         761                 :          0 : STRINGLIB(utf32_encode)(const STRINGLIB_CHAR *in,
         762                 :            :                         Py_ssize_t len,
         763                 :            :                         uint32_t **outptr,
         764                 :            :                         int native_ordering)
         765                 :            : {
         766                 :          0 :     uint32_t *out = *outptr;
         767                 :          0 :     const STRINGLIB_CHAR *end = in + len;
         768         [ #  # ]:          0 :     if (native_ordering) {
         769                 :          0 :         const STRINGLIB_CHAR *unrolled_end = in + _Py_SIZE_ROUND_DOWN(len, 4);
         770         [ #  # ]:          0 :         while (in < unrolled_end) {
         771                 :            : #if STRINGLIB_SIZEOF_CHAR > 1
         772                 :            :             /* check if any character is a surrogate character */
         773                 :          0 :             if (((in[0] ^ 0xd800) &
         774                 :          0 :                  (in[1] ^ 0xd800) &
         775                 :          0 :                  (in[2] ^ 0xd800) &
         776         [ #  # ]:          0 :                  (in[3] ^ 0xd800) & 0xf800) == 0)
         777                 :          0 :                 break;
         778                 :            : #endif
         779                 :          0 :             out[0] = in[0];
         780                 :          0 :             out[1] = in[1];
         781                 :          0 :             out[2] = in[2];
         782                 :          0 :             out[3] = in[3];
         783                 :          0 :             in += 4; out += 4;
         784                 :            :         }
         785         [ #  # ]:          0 :         while (in < end) {
         786                 :            :             Py_UCS4 ch;
         787                 :          0 :             ch = *in++;
         788                 :            : #if STRINGLIB_SIZEOF_CHAR > 1
         789         [ #  # ]:          0 :             if (Py_UNICODE_IS_SURROGATE(ch)) {
         790                 :            :                 /* reject surrogate characters (U+D800-U+DFFF) */
         791                 :          0 :                 goto fail;
         792                 :            :             }
         793                 :            : #endif
         794                 :          0 :             *out++ = ch;
         795                 :            :         }
         796                 :            :     } else {
         797                 :          0 :         const STRINGLIB_CHAR *unrolled_end = in + _Py_SIZE_ROUND_DOWN(len, 4);
         798         [ #  # ]:          0 :         while (in < unrolled_end) {
         799                 :            : #if STRINGLIB_SIZEOF_CHAR > 1
         800                 :            :             /* check if any character is a surrogate character */
         801                 :          0 :             if (((in[0] ^ 0xd800) &
         802                 :          0 :                  (in[1] ^ 0xd800) &
         803                 :          0 :                  (in[2] ^ 0xd800) &
         804         [ #  # ]:          0 :                  (in[3] ^ 0xd800) & 0xf800) == 0)
         805                 :          0 :                 break;
         806                 :            : #endif
         807                 :          0 :             out[0] = STRINGLIB(SWAB4)(in[0]);
         808                 :          0 :             out[1] = STRINGLIB(SWAB4)(in[1]);
         809                 :          0 :             out[2] = STRINGLIB(SWAB4)(in[2]);
         810                 :          0 :             out[3] = STRINGLIB(SWAB4)(in[3]);
         811                 :          0 :             in += 4; out += 4;
         812                 :            :         }
         813         [ #  # ]:          0 :         while (in < end) {
         814                 :          0 :             Py_UCS4 ch = *in++;
         815                 :            : #if STRINGLIB_SIZEOF_CHAR > 1
         816         [ #  # ]:          0 :             if (Py_UNICODE_IS_SURROGATE(ch)) {
         817                 :            :                 /* reject surrogate characters (U+D800-U+DFFF) */
         818                 :          0 :                 goto fail;
         819                 :            :             }
         820                 :            : #endif
         821                 :          0 :             *out++ = STRINGLIB(SWAB4)(ch);
         822                 :            :         }
         823                 :            :     }
         824                 :          0 :     *outptr = out;
         825                 :          0 :     return len;
         826                 :            : #if STRINGLIB_SIZEOF_CHAR > 1
         827                 :          0 :   fail:
         828                 :          0 :     *outptr = out;
         829                 :          0 :     return len - (end - in + 1);
         830                 :            : #endif
         831                 :            : }
         832                 :            :
         833                 :            : #endif

Generated by: LCOV version 1.14