Coverage Report

Created: 2026-11-12 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnutls/lib/str-iconv.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2010-2016 Free Software Foundation, Inc.
3
 * Copyright (C) 2015-2016 Red Hat, Inc.
4
 *
5
 * Author: Nikos Mavrogiannopoulos
6
 *
7
 * This file is part of GnuTLS.
8
 *
9
 * The GnuTLS is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public License
11
 * as published by the Free Software Foundation; either version 2.1 of
12
 * the License, or (at your option) any later version.
13
 *
14
 * This library is distributed in the hope that it will be useful, but
15
 * WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
21
 *
22
 */
23
24
#include "config.h"
25
#include "system.h"
26
#include "gnutls_int.h"
27
#include "errors.h"
28
29
#include <sys/socket.h>
30
#include <errno.h>
31
#include <sys/stat.h>
32
#include <sys/types.h>
33
#include <unistr.h>
34
#include <uninorm.h>
35
#include "num.h"
36
37
/* Copies @units 16-bit code units from @src to @dst, converting them
38
 * from or to the requested endianness. @src and @dst must not overlap,
39
 * unless they are the same buffer, as the copy is done with memcpy().
40
 */
41
static void change_u16_endianness(uint8_t *dst, const uint8_t *src,
42
          size_t units, unsigned be)
43
25.6k
{
44
25.6k
  unsigned convert = 0;
45
25.6k
  size_t i;
46
25.6k
  uint8_t tmp;
47
48
#ifdef WORDS_BIGENDIAN
49
  if (!be)
50
    convert = 1;
51
#else
52
25.6k
  if (be)
53
25.6k
    convert = 1;
54
25.6k
#endif
55
56
  /* convert to LE */
57
25.6k
  if (convert) {
58
136k
    for (i = 0; i < units; i++) {
59
110k
      tmp = src[2 * i];
60
110k
      dst[2 * i] = src[2 * i + 1];
61
110k
      dst[2 * i + 1] = tmp;
62
110k
    }
63
25.6k
  } else {
64
0
    if (dst != src)
65
0
      memcpy(dst, src, units * 2);
66
0
  }
67
25.6k
}
68
69
int _gnutls_ucs2_to_utf8(const void *data, size_t size, gnutls_datum_t *output,
70
       unsigned be)
71
25.8k
{
72
25.8k
  int ret;
73
25.8k
  size_t dstlen;
74
25.8k
  void *src;
75
25.8k
  uint8_t *tmp_dst = NULL;
76
25.8k
  uint8_t *dst = NULL;
77
78
25.8k
  if (size > 2 && ((uint8_t *)data)[size - 1] == 0 &&
79
6.84k
      ((uint8_t *)data)[size - 2] == 0) {
80
2.85k
    size -= 2;
81
2.85k
  }
82
83
25.8k
  if (size == 0 || size % 2 != 0)
84
10.3k
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
85
86
15.5k
  src = gnutls_malloc(size + 2);
87
15.5k
  if (src == NULL)
88
0
    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
89
90
  /* convert to LE if needed */
91
15.5k
  change_u16_endianness(src, data, size / 2, be);
92
93
15.5k
  dstlen = 0;
94
15.5k
  tmp_dst = u16_to_u8((uint16_t *)src, size / 2, NULL, &dstlen);
95
15.5k
  if (tmp_dst == NULL) {
96
5.79k
    ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
97
5.79k
    goto fail;
98
5.79k
  }
99
100
9.72k
  dst = gnutls_malloc(dstlen + 1);
101
9.72k
  if (dst == NULL) {
102
0
    gnutls_assert();
103
0
    ret = GNUTLS_E_MEMORY_ERROR;
104
0
    goto fail;
105
0
  }
106
107
9.72k
  memcpy(dst, tmp_dst, dstlen);
108
9.72k
  dst[dstlen] = 0;
109
110
9.72k
  output->data = (void *)dst;
111
9.72k
  output->size = dstlen;
112
113
9.72k
  ret = 0;
114
9.72k
  goto cleanup;
115
116
5.79k
fail:
117
5.79k
  gnutls_free(dst);
118
119
15.5k
cleanup:
120
15.5k
  gnutls_free(src);
121
15.5k
  free(tmp_dst);
122
123
15.5k
  return ret;
124
5.79k
}
125
126
int _gnutls_utf8_to_ucs2(const void *data, size_t size, gnutls_datum_t *output,
127
       unsigned be)
128
10.1k
{
129
10.1k
  int ret;
130
10.1k
  size_t dstlen, nrm_size = 0, tmp_size = 0;
131
10.1k
  uint16_t *tmp_dst = NULL;
132
10.1k
  uint16_t *nrm_dst = NULL;
133
10.1k
  uint8_t *dst = NULL;
134
135
10.1k
  if (size == 0)
136
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
137
138
10.1k
  tmp_dst = u8_to_u16(data, size, NULL, &tmp_size);
139
10.1k
  if (tmp_dst == NULL)
140
0
    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
141
142
10.1k
  nrm_dst =
143
10.1k
    u16_normalize(UNINORM_NFC, tmp_dst, tmp_size, NULL, &nrm_size);
144
10.1k
  if (nrm_dst == NULL) {
145
0
    ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
146
0
    goto fail;
147
0
  }
148
149
10.1k
  dstlen = nrm_size * 2; /* convert to bytes */
150
151
10.1k
  dst = gnutls_malloc(dstlen + 2);
152
10.1k
  if (dst == NULL) {
153
0
    gnutls_assert();
154
0
    ret = GNUTLS_E_MEMORY_ERROR;
155
0
    goto fail;
156
0
  }
157
158
  /* convert to BE */
159
10.1k
  change_u16_endianness(dst, (uint8_t *)nrm_dst, nrm_size, be);
160
10.1k
  dst[dstlen] = 0;
161
10.1k
  dst[dstlen + 1] = 0;
162
163
10.1k
  output->data = (void *)dst;
164
10.1k
  output->size = dstlen;
165
166
10.1k
  ret = 0;
167
10.1k
  goto cleanup;
168
169
0
fail:
170
0
  gnutls_free(dst);
171
172
10.1k
cleanup:
173
10.1k
  free(tmp_dst);
174
10.1k
  free(nrm_dst);
175
176
10.1k
  return ret;
177
0
}