/src/libunistring/lib/unistr/u32-to-u8.c
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | /* Convert UTF-32 string to UTF-8 string. | 
| 2 |  |    Copyright (C) 2002, 2006-2007, 2009-2023 Free Software Foundation, Inc. | 
| 3 |  |    Written by Bruno Haible <bruno@clisp.org>, 2002. | 
| 4 |  |  | 
| 5 |  |    This file is free software: you can redistribute it and/or modify | 
| 6 |  |    it under the terms of the GNU Lesser General Public License as | 
| 7 |  |    published by the Free Software Foundation; either version 2.1 of the | 
| 8 |  |    License, or (at your option) any later version. | 
| 9 |  |  | 
| 10 |  |    This file is distributed in the hope that it will be useful, | 
| 11 |  |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| 12 |  |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
| 13 |  |    GNU Lesser General Public License for more details. | 
| 14 |  |  | 
| 15 |  |    You should have received a copy of the GNU Lesser General Public License | 
| 16 |  |    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */ | 
| 17 |  |  | 
| 18 |  | #include <config.h> | 
| 19 |  |  | 
| 20 |  | /* Specification.  */ | 
| 21 |  | #include "unistr.h" | 
| 22 |  |  | 
| 23 |  | #define FUNC u32_to_u8 | 
| 24 |  | #define SRC_UNIT uint32_t | 
| 25 | 0 | #define DST_UNIT uint8_t | 
| 26 |  |  | 
| 27 |  | #include <errno.h> | 
| 28 |  | #include <stdlib.h> | 
| 29 |  | #include <string.h> | 
| 30 |  |  | 
| 31 |  | DST_UNIT * | 
| 32 |  | FUNC (const SRC_UNIT *s, size_t n, DST_UNIT *resultbuf, size_t *lengthp) | 
| 33 | 0 | { | 
| 34 | 0 |   const SRC_UNIT *s_end = s + n; | 
| 35 |  |   /* Output string accumulator.  */ | 
| 36 | 0 |   DST_UNIT *result; | 
| 37 | 0 |   size_t allocated; | 
| 38 | 0 |   size_t length; | 
| 39 |  | 
 | 
| 40 | 0 |   if (resultbuf != NULL) | 
| 41 | 0 |     { | 
| 42 | 0 |       result = resultbuf; | 
| 43 | 0 |       allocated = *lengthp; | 
| 44 | 0 |     } | 
| 45 | 0 |   else | 
| 46 | 0 |     { | 
| 47 | 0 |       result = NULL; | 
| 48 | 0 |       allocated = 0; | 
| 49 | 0 |     } | 
| 50 | 0 |   length = 0; | 
| 51 |  |   /* Invariants: | 
| 52 |  |      result is either == resultbuf or == NULL or malloc-allocated. | 
| 53 |  |      If length > 0, then result != NULL.  */ | 
| 54 |  | 
 | 
| 55 | 0 |   while (s < s_end) | 
| 56 | 0 |     { | 
| 57 | 0 |       ucs4_t uc; | 
| 58 | 0 |       int count; | 
| 59 |  |  | 
| 60 |  |       /* Fetch a Unicode character from the input string.  */ | 
| 61 | 0 |       uc = *s++; | 
| 62 |  |       /* No need to call the safe variant u32_mbtouc, because | 
| 63 |  |          u8_uctomb will verify uc anyway.  */ | 
| 64 |  |  | 
| 65 |  |       /* Store it in the output string.  */ | 
| 66 | 0 |       count = u8_uctomb (result + length, uc, allocated - length); | 
| 67 | 0 |       if (count == -1) | 
| 68 | 0 |         { | 
| 69 | 0 |           if (!(result == resultbuf || result == NULL)) | 
| 70 | 0 |             free (result); | 
| 71 | 0 |           errno = EILSEQ; | 
| 72 | 0 |           return NULL; | 
| 73 | 0 |         } | 
| 74 | 0 |       if (count == -2) | 
| 75 | 0 |         { | 
| 76 | 0 |           DST_UNIT *memory; | 
| 77 |  | 
 | 
| 78 | 0 |           allocated = (allocated > 0 ? 2 * allocated : 12); | 
| 79 | 0 |           if (length + 6 > allocated) | 
| 80 | 0 |             allocated = length + 6; | 
| 81 | 0 |           if (result == resultbuf || result == NULL) | 
| 82 | 0 |             memory = (DST_UNIT *) malloc (allocated * sizeof (DST_UNIT)); | 
| 83 | 0 |           else | 
| 84 | 0 |             memory = | 
| 85 | 0 |               (DST_UNIT *) realloc (result, allocated * sizeof (DST_UNIT)); | 
| 86 |  | 
 | 
| 87 | 0 |           if (memory == NULL) | 
| 88 | 0 |             { | 
| 89 | 0 |               if (!(result == resultbuf || result == NULL)) | 
| 90 | 0 |                 free (result); | 
| 91 | 0 |               errno = ENOMEM; | 
| 92 | 0 |               return NULL; | 
| 93 | 0 |             } | 
| 94 | 0 |           if (result == resultbuf && length > 0) | 
| 95 | 0 |             memcpy ((char *) memory, (char *) result, | 
| 96 | 0 |                     length * sizeof (DST_UNIT)); | 
| 97 | 0 |           result = memory; | 
| 98 | 0 |           count = u8_uctomb (result + length, uc, allocated - length); | 
| 99 | 0 |           if (count < 0) | 
| 100 | 0 |             abort (); | 
| 101 | 0 |         } | 
| 102 | 0 |       length += count; | 
| 103 | 0 |     } | 
| 104 |  |  | 
| 105 | 0 |   if (length == 0) | 
| 106 | 0 |     { | 
| 107 | 0 |       if (result == NULL) | 
| 108 | 0 |         { | 
| 109 |  |           /* Return a non-NULL value.  NULL means error.  */ | 
| 110 | 0 |           result = (DST_UNIT *) malloc (1); | 
| 111 | 0 |           if (result == NULL) | 
| 112 | 0 |             { | 
| 113 | 0 |               errno = ENOMEM; | 
| 114 | 0 |               return NULL; | 
| 115 | 0 |             } | 
| 116 | 0 |         } | 
| 117 | 0 |     } | 
| 118 | 0 |   else if (result != resultbuf && length < allocated) | 
| 119 | 0 |     { | 
| 120 |  |       /* Shrink the allocated memory if possible.  */ | 
| 121 | 0 |       DST_UNIT *memory; | 
| 122 |  | 
 | 
| 123 | 0 |       memory = (DST_UNIT *) realloc (result, length * sizeof (DST_UNIT)); | 
| 124 | 0 |       if (memory != NULL) | 
| 125 | 0 |         result = memory; | 
| 126 | 0 |     } | 
| 127 |  |  | 
| 128 | 0 |   *lengthp = length; | 
| 129 | 0 |   return result; | 
| 130 | 0 | } |