VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/asn1/asn1-ut-string.cpp@ 77815

Last change on this file since 77815 was 77815, checked in by vboxsync, 6 years ago

IPRT/ASN.1: Allow zero terminators at the end of IA5STRING so we can load some 2018 microsoft root cert.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 68.8 KB
Line 
1/* $Id: asn1-ut-string.cpp 77815 2019-03-20 23:56:41Z vboxsync $ */
2/** @file
3 * IPRT - ASN.1, XXX STRING Types.
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include "internal/iprt.h"
32#include <iprt/asn1.h>
33
34#include <iprt/ctype.h>
35#include <iprt/err.h>
36#include <iprt/string.h>
37#include <iprt/uni.h>
38
39#include <iprt/formats/asn1.h>
40
41
42/*********************************************************************************************************************************
43* Global Variables *
44*********************************************************************************************************************************/
45static uint8_t const g_acbStringTags[] =
46{
47 /* [ASN1_TAG_EOC] = */ 0,
48 /* [ASN1_TAG_BOOLEAN] = */ 0,
49 /* [ASN1_TAG_INTEGER] = */ 0,
50 /* [ASN1_TAG_BIT_STRING] = */ 0,
51 /* [ASN1_TAG_OCTET_STRING] = */ 0,
52 /* [ASN1_TAG_NULL] = */ 0,
53 /* [ASN1_TAG_OID] = */ 0,
54 /* [ASN1_TAG_OBJECT_DESCRIPTOR] = */ 0,
55 /* [ASN1_TAG_EXTERNAL] = */ 0,
56 /* [ASN1_TAG_REAL] = */ 0,
57 /* [ASN1_TAG_ENUMERATED] = */ 0,
58 /* [ASN1_TAG_EMBEDDED_PDV] = */ 0,
59 /* [ASN1_TAG_UTF8_STRING] = */ 1,
60 /* [ASN1_TAG_RELATIVE_OID] = */ 0,
61 /* [ASN1_TAG_RESERVED_14] = */ 0,
62 /* [ASN1_TAG_RESERVED_15] = */ 0,
63 /* [ASN1_TAG_SEQUENCE] = */ 0,
64 /* [ASN1_TAG_SET] = */ 0,
65 /* [ASN1_TAG_NUMERIC_STRING] = */ 1,
66 /* [ASN1_TAG_PRINTABLE_STRING] = */ 1,
67 /* [ASN1_TAG_T61_STRING] = */ 1,
68 /* [ASN1_TAG_VIDEOTEX_STRING] = */ 1,
69 /* [ASN1_TAG_IA5_STRING] = */ 1,
70 /* [ASN1_TAG_UTC_TIME] = */ 0,
71 /* [ASN1_TAG_GENERALIZED_TIME] = */ 0,
72 /* [ASN1_TAG_GRAPHIC_STRING] = */ 1,
73 /* [ASN1_TAG_VISIBLE_STRING] = */ 1,
74 /* [ASN1_TAG_GENERAL_STRING] = */ 1,
75 /* [ASN1_TAG_UNIVERSAL_STRING] = */ 4,
76 /* [ASN1_TAG_CHARACTER_STRING] = */ 1,
77 /* [ASN1_TAG_BMP_STRING] = */ 2,
78};
79
80
81
82
83/*
84 * ISO/IEC-2022 + TeletexString mess.
85 */
86
87/**
88 * ISO-2022 codepoint mappings.
89 */
90typedef struct RTISO2022MAP
91{
92 /** The number of bytes per character. */
93 uint8_t cb;
94 /** The registration number. */
95 uint16_t uRegistration;
96 /** The size of the pauToUni table. */
97 uint16_t cToUni;
98 /** Pointer to the convertion table from ISO-2022 to Unicode.
99 * ASSUMES that unicode chars above 0xffff won't be required. */
100 uint16_t const *pauToUni;
101
102 /** Escape sequence for loading into G0 or C0 or C1 depending on the type (sans
103 * ESC). */
104 uint8_t abEscLoadXX[6];
105 /** Escape sequence for loading into G1 (sans ESC). */
106 uint8_t abEscLoadG1[6];
107 /** Escape sequence for loading into G2 (sans ESC). */
108 uint8_t abEscLoadG2[6];
109 /** Escape sequence for loading into G3 (sans ESC). */
110 uint8_t abEscLoadG3[6];
111} RTISO2022MAP;
112/** Pointer to const ISO-2022 mappings. */
113typedef RTISO2022MAP const *PCRTISO2022MAP;
114
115/** Unused codepoint value. */
116#define RTISO2022_UNUSED UINT16_C(0xffff)
117
118
119/** Dummy mappings to avoid dealing with NULL pointers in the decoder
120 * registers. */
121static const RTISO2022MAP g_DummyMap =
122{
123 1, UINT16_MAX, 0, NULL,
124 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } /* No escape into G0 */,
125 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } /* No escape into G1 */,
126 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } /* No escape into G2 */,
127 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } /* No escape into G3 */
128};
129
130
131/** GL mappings for ISO-IR-168 (Japanese, update of #87), with space and
132 * delete. */
133static const RTISO2022MAP g_IsoIr168Map =
134{
135 //2, 168, RT_ELEMENTS(g_awcIsoIr168Decode), g_awcIsoIr168Decode,
136 2, 168, 0, NULL,
137 { 0x26, 0x40, 0x2b, 0x24, 0x42, 0xff } /* Esc into G0 */,
138 { 0x26, 0x40, 0x2b, 0x24, 0x29, 0x42 } /* Esc into G1 */,
139 { 0x26, 0x40, 0x2b, 0x24, 0x2a, 0x42 } /* Esc into G2 */,
140 { 0x26, 0x40, 0x2b, 0x24, 0x2b, 0x42 } /* Esc into G3 */,
141};
142
143
144/** GL mappings for ISO-IR-165 (Chinese), with space and delete. */
145static const RTISO2022MAP g_IsoIr165Map =
146{
147 //2, 165, RT_ELEMENTS(g_awcIsoIr165Decode), g_awcIsoIr165Decode,
148 2, 165, 0, NULL,
149 { 0x24, 0x28, 0x45, 0xff, 0xff, 0xff } /* Esc into G0 */,
150 { 0x24, 0x29, 0x45, 0xff, 0xff, 0xff } /* Esc into G1 */,
151 { 0x24, 0x2a, 0x45, 0xff, 0xff, 0xff } /* Esc into G2 */,
152 { 0x24, 0x2b, 0x45, 0xff, 0xff, 0xff } /* Esc into G3 */,
153};
154
155
156/** GL mappings for ISO-IR-150 (Greek), with space and delete. */
157static const RTISO2022MAP g_IsoIr150Map =
158{
159 //1, 150, RT_ELEMENTS(g_awcIsoIr150Decode), g_awcIsoIr150Decode,
160 1, 150, 0, NULL,
161 { 0x28, 0x21, 0x40, 0xff, 0xff, 0xff } /* Esc into G0 */,
162 { 0x29, 0x21, 0x40, 0xff, 0xff, 0xff } /* Esc into G1 */,
163 { 0x2a, 0x21, 0x40, 0xff, 0xff, 0xff } /* Esc into G2 */,
164 { 0x2b, 0x21, 0x40, 0xff, 0xff, 0xff } /* Esc into G3 */,
165};
166
167
168/** GL mappings for ISO-IR-103 (Teletex supplementary), with space and
169 * delete. */
170static const RTISO2022MAP g_IsoIr103Map =
171{
172 //1, 103, RT_ELEMENTS(g_awcIsoIr103Decode), g_awcIsoIr103Decode,
173 1, 103, 0, NULL,
174 { 0x28, 0x76, 0xff, 0xff, 0xff, 0xff } /* Esc into G0 */,
175 { 0x29, 0x76, 0xff, 0xff, 0xff, 0xff } /* Esc into G1 */,
176 { 0x2a, 0x76, 0xff, 0xff, 0xff, 0xff } /* Esc into G2 */,
177 { 0x2b, 0x76, 0xff, 0xff, 0xff, 0xff } /* Esc into G3 */,
178};
179
180
181/**
182 * GL mapping from ISO-IR-102 (Teletex primary) to unicode, with space and
183 * delete.
184 *
185 * Mostly 1:1, except that (a) what would be dollar is currency sign, (b)
186 * positions 0x5c, 0x5e, 0x7b, 0x7d and 0x7e are defined not to be used.
187 */
188static uint16_t const g_awcIsoIr102Decode[0x60] =
189{
190 0x0020, 0x0021, 0x0022, 0x0023, 0x00A4, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
191 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
192 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
193 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0xffff, 0x005d, 0xffff, 0x005f,
194 0xffff, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
195 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0xffff, 0x007c, 0xffff, 0xffff, 0x007f,
196};
197
198/** GL mappings for ISO-IR-102, with space and delete. */
199static const RTISO2022MAP g_IsoIr102Map =
200{
201 1, 102, RT_ELEMENTS(g_awcIsoIr102Decode), g_awcIsoIr102Decode,
202 { 0x28, 0x75, 0xff, 0xff, 0xff, 0xff } /* Esc into G0 */,
203 { 0x29, 0x75, 0xff, 0xff, 0xff, 0xff } /* Esc into G1 */,
204 { 0x2a, 0x75, 0xff, 0xff, 0xff, 0xff } /* Esc into G2 */,
205 { 0x2b, 0x75, 0xff, 0xff, 0xff, 0xff } /* Esc into G3 */,
206};
207
208
209#if 0 /* unused */
210/** GL mappings for ISO-IR-87 (Japanese), with space and delete. */
211static const RTISO2022MAP g_IsoIr87Map =
212{
213 //1, 87, RT_ELEMENTS(g_awcIsoIr87Decode), g_awcIsoIr97Decode,
214 1, 87, 0, NULL,
215 { 0x24, 0x42, 0xff, 0xff, 0xff, 0xff } /* Esc into G0 */,
216 { 0x24, 0x29, 0x42, 0xff, 0xff, 0xff } /* Esc into G1 */,
217 { 0x24, 0x2a, 0x42, 0xff, 0xff, 0xff } /* Esc into G2 */,
218 { 0x24, 0x2b, 0x42, 0xff, 0xff, 0xff } /* Esc into G3 */,
219};
220#endif
221
222
223/**
224 * GL mapping from ISO-IR-6 (ASCII) to unicode, with space and delete.
225 *
226 * Completely 1:1.
227 */
228static uint16_t const g_awcIsoIr6Decode[0x60] =
229{
230 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
231 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
232 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
233 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
234 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
235 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x006b, 0x007c, 0x007d, 0x007e, 0x007f,
236};
237
238/** GL mappings for ISO-IR-6 (ASCII), with space and delete. */
239static const RTISO2022MAP g_IsoIr6Map =
240{
241 1, 6, RT_ELEMENTS(g_awcIsoIr6Decode), g_awcIsoIr6Decode,
242 { 0x28, 0x42, 0xff, 0xff, 0xff, 0xff } /* Esc into G0 */,
243 { 0x29, 0x42, 0xff, 0xff, 0xff, 0xff } /* Esc into G1 */,
244 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } /* Esc into G2 */,
245 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } /* Esc into G3 */,
246};
247
248
249/** GL maps. */
250static PCRTISO2022MAP g_paGLMaps[] =
251{
252 &g_IsoIr6Map,
253 &g_IsoIr102Map,
254 &g_IsoIr103Map,
255 &g_IsoIr150Map,
256 &g_IsoIr165Map,
257 &g_IsoIr168Map,
258};
259
260
261
262/** GR mappings for ISO-IR-164 (Hebrew supplementary). */
263static const RTISO2022MAP g_IsoIr164Map =
264{
265 //1, 164, RT_ELEMENTS(g_awcIsoIr164Decode), g_awcIsoIr164Decode
266 1, 164, 0, NULL,
267 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } /* Esc into G0 */,
268 { 0x2d, 0x53, 0xff, 0xff, 0xff, 0xff } /* Esc into G1 */,
269 { 0x2e, 0x53, 0xff, 0xff, 0xff, 0xff } /* Esc into G2 */,
270 { 0x2f, 0x53, 0xff, 0xff, 0xff, 0xff } /* Esc into G3 */,
271};
272
273
274/** GR mappings for ISO-IR-156 (Supplementary for ASCII (#6)). */
275static const RTISO2022MAP g_IsoIr156Map =
276{
277 //1, 156, RT_ELEMENTS(g_awcIsoIr156Decode), g_awcIsoIr156Decode
278 1, 156, 0, NULL,
279 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } /* Esc into G0 */,
280 { 0x2d, 0x52, 0xff, 0xff, 0xff, 0xff } /* Esc into G1 */,
281 { 0x2e, 0x52, 0xff, 0xff, 0xff, 0xff } /* Esc into G2 */,
282 { 0x2f, 0x52, 0xff, 0xff, 0xff, 0xff } /* Esc into G3 */,
283};
284
285
286/** GR mappings for ISO-IR-153 (Basic Cyrillic). */
287static const RTISO2022MAP g_IsoIr153Map =
288{
289 //1, 153, RT_ELEMENTS(g_awcIsoIr153Decode), g_awcIsoIr153Decode
290 1, 153, 0, NULL,
291 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } /* Esc into G0 */,
292 { 0x2d, 0x4f, 0xff, 0xff, 0xff, 0xff } /* Esc into G1 */,
293 { 0x2e, 0x4f, 0xff, 0xff, 0xff, 0xff } /* Esc into G2 */,
294 { 0x2f, 0x4f, 0xff, 0xff, 0xff, 0xff } /* Esc into G3 */,
295};
296
297
298/** GR mappings for ISO-IR-144 (Cryllic part of Latin/Cyrillic). */
299static const RTISO2022MAP g_IsoIr144Map =
300{
301 //1, 144, RT_ELEMENTS(g_awcIsoIr144Decode), g_awcIsoIr144Decode
302 1, 144, 0, NULL,
303 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } /* Esc into G0 */,
304 { 0x2d, 0x4f, 0xff, 0xff, 0xff, 0xff } /* Esc into G1 */,
305 { 0x2e, 0x4f, 0xff, 0xff, 0xff, 0xff } /* Esc into G2 */,
306 { 0x2f, 0x4f, 0xff, 0xff, 0xff, 0xff } /* Esc into G3 */,
307};
308
309
310/** GR mappings for ISO-IR-126 (Latin/Greek). */
311static const RTISO2022MAP g_IsoIr126Map =
312{
313 //1, 126, RT_ELEMENTS(g_awcIsoIr126Decode), g_awcIsoIr126Decode
314 1, 126, 0, NULL,
315 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } /* Esc into G0 */,
316 { 0x2d, 0x46, 0xff, 0xff, 0xff, 0xff } /* Esc into G1 */,
317 { 0x2e, 0x46, 0xff, 0xff, 0xff, 0xff } /* Esc into G2 */,
318 { 0x2f, 0x46, 0xff, 0xff, 0xff, 0xff } /* Esc into G3 */,
319};
320
321
322/** GR maps. */
323static PCRTISO2022MAP g_paGRMaps[] =
324{
325 &g_IsoIr126Map,
326 &g_IsoIr144Map,
327 &g_IsoIr153Map,
328 &g_IsoIr156Map,
329 &g_IsoIr164Map,
330};
331
332
333
334/** C0 mapping from ISO-IR-106 to unicode. */
335static uint16_t g_awcIsoIr106Decode[0x20] =
336{
337 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0008, 0xffff, 0x000a, 0xffff, 0x000c, 0x000d, 0x000e, 0x000f,
338 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x008e, 0x000a, 0x001b, 0xffff, 0x008f, 0xffff, 0xffff,
339};
340
341/** C0 mappings for ISO-IR-106. */
342static const RTISO2022MAP g_IsoIr106Map =
343{
344 1, 106, RT_ELEMENTS(g_awcIsoIr106Decode), g_awcIsoIr106Decode,
345 { 0x21, 0x45, 0xff, 0xff, 0xff, 0xff } /* Esc into C0 */,
346 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } /* N/A */,
347 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } /* N/A */,
348 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } /* N/A */,
349};
350
351/** C0 maps. */
352static PCRTISO2022MAP g_paC0Maps[] =
353{
354 &g_IsoIr106Map,
355};
356
357
358
359/** C1 mapping from ISO-IR-107 to unicode. */
360static uint16_t g_awcIsoIr107Decode[0x20] =
361{
362 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x008b, 0x008c, 0xffff, 0xffff, 0xffff,
363 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x009b, 0xffff, 0xffff, 0xffff, 0xffff,
364};
365
366/** C1 mappings for ISO-IR-107. */
367static const RTISO2022MAP g_IsoIr107Map =
368{
369 1, 107, RT_ELEMENTS(g_awcIsoIr107Decode), g_awcIsoIr107Decode,
370 { 0x22, 0x48, 0xff, 0xff, 0xff, 0xff } /* Esc into C1 */,
371 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } /* N/A */,
372 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } /* N/A */,
373 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } /* N/A */,
374};
375
376/** C1 maps. */
377static PCRTISO2022MAP g_paC1Maps[] =
378{
379 &g_IsoIr107Map,
380};
381
382
383static int rtIso2022Decoder_LookupAndSet(PCRTISO2022MAP *ppMapRet, uint16_t uRegistration, PCRTISO2022MAP *papMaps, uint32_t cMaps)
384{
385 uint32_t i = cMaps;
386 while (i-- > 0)
387 if (papMaps[i]->uRegistration == uRegistration)
388 {
389 /** @todo skip non-Teletex codesets if we ever add more than we need for it. */
390 *ppMapRet = papMaps[i];
391 return VINF_SUCCESS;
392 }
393 return VERR_ASN1_INVALID_T61_STRING_ENCODING;
394}
395
396
397/**
398 * ISO-2022 decoder state.
399 */
400typedef struct RTISO2022DECODERSTATE
401{
402 /** Pointer to the string */
403 uint8_t const *pabString;
404 /** The string size. */
405 uint32_t cbString;
406 /** The current string position. */
407 uint32_t offString;
408
409 /** The GL mapping. */
410 PCRTISO2022MAP pMapGL;
411 /** The GR mapping. */
412 PCRTISO2022MAP pMapGR;
413 /** The lower control set (C0) mapping. */
414 PCRTISO2022MAP pMapC0;
415 /** The higher control set (C1) mapping. */
416 PCRTISO2022MAP pMapC1;
417 /** The G0, G1, G2, and G3 mappings. */
418 PCRTISO2022MAP apMapGn[4];
419 /** Used by SS2 & SS3 to store the orignal GL value that is to be restored. */
420 PCRTISO2022MAP pRestoreGL;
421 /** Pointer to extended error info buffer, optional. */
422 PRTERRINFO pErrInfo;
423} RTISO2022DECODERSTATE;
424/** Pointer to a const ISO-2022 decoder state. */
425typedef RTISO2022DECODERSTATE *PRTISO2022DECODERSTATE;
426
427
428static int rtIso2022Decoder_SetGL(PRTISO2022DECODERSTATE pThis, PCRTISO2022MAP pNewMap)
429{
430 pThis->pMapGL = pNewMap;
431 return VINF_SUCCESS;
432}
433
434
435static int rtIso2022Decoder_SetGR(PRTISO2022DECODERSTATE pThis, PCRTISO2022MAP pNewMap)
436{
437 pThis->pMapGR = pNewMap;
438 return VINF_SUCCESS;
439}
440
441
442static int rtIso2022Decoder_SetGLForOneChar(PRTISO2022DECODERSTATE pThis, PCRTISO2022MAP pTmpMap)
443{
444 pThis->pRestoreGL = pThis->pMapGL;
445 pThis->pMapGL = pTmpMap;
446 return VINF_SUCCESS;
447}
448
449
450static int rtIso2022Decoder_SetC0(PRTISO2022DECODERSTATE pThis, uint16_t uRegistration)
451{
452 return rtIso2022Decoder_LookupAndSet(&pThis->pMapC0, uRegistration, g_paC0Maps, RT_ELEMENTS(g_paC0Maps));
453}
454
455
456static int rtIso2022Decoder_SetC1(PRTISO2022DECODERSTATE pThis, uint16_t uRegistration)
457{
458 return rtIso2022Decoder_LookupAndSet(&pThis->pMapC1, uRegistration, g_paC1Maps, RT_ELEMENTS(g_paC1Maps));
459}
460
461
462/**
463 * Worker for rtIso2022Decoder_FindEscAndSet.
464 *
465 * @returns true if match, false if not.
466 * @param pabLeft Pointer to the first string byte after the ESC.
467 * @param cbLeft The number of bytes left in the string.
468 * @param pabRight Pointer to the abEscLoad* byte array to match with.
469 * @param cbRight Size of the mapping sequence (fixed).
470 * @param pcchMatch Where to return the length of the escape sequence (sans
471 * ESC) on success.
472 */
473static bool rtIso2022Decoder_MatchEscSeqFrom2ndByte(uint8_t const *pabLeft, uint32_t cbLeft,
474 uint8_t const *pabRight, uint32_t cbRight,
475 uint32_t *pcchMatch)
476{
477 Assert(cbRight == 6);
478 uint32_t i = 1;
479 while (i < cbRight)
480 {
481 if (pabRight[i] == 0xff)
482 break;
483 if (cbLeft <= i || pabLeft[i] != pabRight[i])
484 return false;
485 i++;
486 }
487 *pcchMatch = i;
488 return true;
489}
490
491
492/**
493 * Finds a the set with a matching abEscLoad* escape sequence and loads it into
494 * the designated register.
495 *
496 * @returns The length of the sequence on success, negative error status code on
497 * failure.
498 * @param pThis The decoder instance.
499 * @param ppMapRet Used to specify C0 or C1 maps when processing
500 * escape sequences for loading these. Only the
501 * abEscLoadXX arrays will be searched if this is
502 * not NULL. For loading {G0,...,G3} pass NULL.
503 * @param pb Pointer to the start of the escape sequence.
504 * @param cb The number of bytes remaining in the string.
505 * @param papMaps The maps to search.
506 * @param cMaps The number of maps @a papMaps points to.
507 */
508static int rtIso2022Decoder_FindEscAndSet(PRTISO2022DECODERSTATE pThis,
509 PCRTISO2022MAP *ppMapRet, PCRTISO2022MAP *papMaps, uint32_t cMaps)
510{
511 /* Skip the ESC.*/
512 uint8_t const *pb = &pThis->pabString[pThis->offString + 1];
513 uint32_t cb = pThis->cbString - (pThis->offString + 1);
514
515 /* Cache the first char. */
516 uint8_t const b0 = pb[0];
517
518 /* Scan the array of maps for matching sequences. */
519 uint32_t i = cMaps;
520 while (i-- > 0)
521 {
522 uint32_t cchMatch = 0; /* (MSC maybe used uninitialized) */
523 PCRTISO2022MAP pMap = papMaps[i];
524 /** @todo skip non-Teletex codesets if we ever add more than we need for it. */
525 if ( pMap->abEscLoadXX[0] == b0
526 && rtIso2022Decoder_MatchEscSeqFrom2ndByte(pb, cb, pMap->abEscLoadXX, sizeof(pMap->abEscLoadXX), &cchMatch) )
527 {
528 if (ppMapRet)
529 *ppMapRet = pMap;
530 else
531 pThis->apMapGn[0] = pMap;
532 return cchMatch + 1;
533 }
534
535 if (!ppMapRet) /* ppMapRet is NULL if Gn. */
536 {
537 uint32_t iGn;
538 if ( pMap->abEscLoadG1[0] == b0
539 && rtIso2022Decoder_MatchEscSeqFrom2ndByte(pb, cb, pMap->abEscLoadG1, sizeof(pMap->abEscLoadG1), &cchMatch))
540 iGn = 1;
541 else if ( pMap->abEscLoadG2[0] == b0
542 && rtIso2022Decoder_MatchEscSeqFrom2ndByte(pb, cb, pMap->abEscLoadG2, sizeof(pMap->abEscLoadG2), &cchMatch))
543 iGn = 2;
544 else if ( pMap->abEscLoadG3[0] == b0
545 && rtIso2022Decoder_MatchEscSeqFrom2ndByte(pb, cb, pMap->abEscLoadG3, sizeof(pMap->abEscLoadG3), &cchMatch))
546 iGn = 3;
547 else
548 iGn = UINT32_MAX;
549 if (iGn != UINT32_MAX)
550 {
551 pThis->apMapGn[iGn] = pMap;
552 return cchMatch + 1;
553 }
554 }
555 }
556 return VERR_ASN1_TELETEX_UNSUPPORTED_CHARSET;
557}
558
559
560/**
561 * Interprets an escape sequence.
562 *
563 * @returns The length of the sequence on success, negative error status code on
564 * failure.
565 * @param pThis The decoder instance. The offString must be
566 * pointing to the escape byte.
567 */
568static int rtIso2022Decoder_InterpretEsc(PRTISO2022DECODERSTATE pThis)
569{
570 /* the first escape byte. */
571 uint32_t offString = pThis->offString;
572 if (offString + 1 >= pThis->cbString)
573 return RTErrInfoSetF(pThis->pErrInfo, VERR_ASN1_INVALID_T61_STRING_ENCODING,
574 "@%u: Unexpected EOS parsing ESC...", offString);
575 int rc;
576 switch (pThis->pabString[offString + 1])
577 {
578 /*
579 * GL selection:
580 */
581 case 0x6e: /* Lock shift two: G2 -> GL */
582 rc = rtIso2022Decoder_SetGL(pThis, pThis->apMapGn[2]);
583 break;
584 case 0x6f: /* Lock shift three: G3 -> GL */
585 rc = rtIso2022Decoder_SetGL(pThis, pThis->apMapGn[3]);
586 break;
587 case 0x4e: /* Single shift two: G2 -> GL for one char. */
588 rc = rtIso2022Decoder_SetGLForOneChar(pThis, pThis->apMapGn[2]);
589 break;
590 case 0x4f: /* Single shift three: G3 -> GL for one char. */
591 rc = rtIso2022Decoder_SetGLForOneChar(pThis, pThis->apMapGn[3]);
592 break;
593
594 /*
595 * GR selection:
596 */
597 case 0x7e: /* Locking shift one right: G1 -> GR. */
598 rc = rtIso2022Decoder_SetGR(pThis, pThis->apMapGn[1]);
599 break;
600 case 0x7d: /* Locking shift two right: G2 -> GR. */
601 rc = rtIso2022Decoder_SetGR(pThis, pThis->apMapGn[2]);
602 break;
603 case 0x7c: /* Locking shift three right: G3 -> GR. */
604 rc = rtIso2022Decoder_SetGR(pThis, pThis->apMapGn[3]);
605 break;
606
607 /*
608 * Cx selection:
609 */
610 case 0x21: /* C0-designate */
611 return rtIso2022Decoder_FindEscAndSet(pThis, &pThis->pMapC0, g_paC0Maps, RT_ELEMENTS(g_paC0Maps));
612 case 0x22: /* C1-designate */
613 return rtIso2022Decoder_FindEscAndSet(pThis, &pThis->pMapC1, g_paC1Maps, RT_ELEMENTS(g_paC1Maps));
614
615 /*
616 * Single-byte character set selection.
617 */
618 case 0x28: /* G0-designate, 94 chars. */
619 case 0x29: /* G1-designate, 94 chars. */
620 case 0x2a: /* G2-designate, 94 chars. */
621 case 0x2b: /* G3-designate, 94 chars. */
622 return rtIso2022Decoder_FindEscAndSet(pThis, NULL, g_paGLMaps, RT_ELEMENTS(g_paGLMaps));
623
624 case 0x2c: /* G0-designate, 96 chars. */
625 case 0x2d: /* G1-designate, 96 chars. */
626 case 0x2e: /* G2-designate, 96 chars. */
627 case 0x2f: /* G3-designate, 96 chars. */
628 return rtIso2022Decoder_FindEscAndSet(pThis, NULL, g_paGRMaps, RT_ELEMENTS(g_paGRMaps));
629
630 /*
631 * Multibyte character set selection.
632 */
633 case 0x24:
634 if (offString + 2 >= pThis->cbString)
635 return RTErrInfoSetF(pThis->pErrInfo, VERR_ASN1_INVALID_T61_STRING_ENCODING,
636 "@%u: Unexpected EOS parsing ESC %#x...", offString, pThis->pabString[offString + 1]);
637 switch (pThis->pabString[offString + 2])
638 {
639 case 0x28: /* G0-designate, 94^n chars. */
640 case 0x29: /* G1-designate, 94^n chars. */
641 case 0x2a: /* G2-designate, 94^n chars. */
642 case 0x2b: /* G3-designate, 94^n chars. */
643 default: /* G0-designate that skips the 0x28? (See japanese ones.) */
644 return rtIso2022Decoder_FindEscAndSet(pThis, NULL, g_paGLMaps, RT_ELEMENTS(g_paGLMaps));
645
646 case 0x2c: /* G0-designate, 96^n chars. */
647 case 0x2d: /* G1-designate, 96^n chars. */
648 case 0x2e: /* G2-designate, 96^n chars. */
649 case 0x2f: /* G3-designate, 96^n chars. */
650 return rtIso2022Decoder_FindEscAndSet(pThis, NULL, g_paGRMaps, RT_ELEMENTS(g_paGRMaps));
651 } \
652 break;
653
654 case 0x26: /* Special escape prefix for #168. */
655 return rtIso2022Decoder_FindEscAndSet(pThis, NULL, g_paGLMaps, RT_ELEMENTS(g_paGLMaps));
656
657 /*
658 * Unknown/unsupported/unimplemented.
659 */
660 case 0x25: /* Designate other coding system. */
661 return RTErrInfoSetF(pThis->pErrInfo, VERR_ASN1_TELETEX_UNSUPPORTED_ESC_SEQ,
662 "@%u: ESC DOCS not supported\n", offString);
663 default:
664 return RTErrInfoSetF(pThis->pErrInfo, VERR_ASN1_TELETEX_UNKNOWN_ESC_SEQ,
665 "@%u: Unknown escape sequence: ESC %#x...\n", offString, pThis->pabString[offString + 1]);
666 }
667
668 /* Only single byte escapes sequences for shifting ends up here. */
669 if (RT_SUCCESS(rc))
670 return 1;
671 return rc;
672}
673
674
675static int rtIso2022Decoder_ControlCharHook(PRTISO2022DECODERSTATE pThis, uint16_t wcControl)
676{
677 int rc;
678 switch (wcControl)
679 {
680 case 0x000e: /* Locking shift zero: G0 -> GL. */
681 rc = rtIso2022Decoder_SetGL(pThis, pThis->apMapGn[0]);
682 break;
683
684 case 0x000f: /* Locking shift one: G1 -> GL. */
685 rc = rtIso2022Decoder_SetGL(pThis, pThis->apMapGn[1]);
686 break;
687
688 case 0x008e: /* Single shift two: G2 -> GL for one char. */
689 rc = rtIso2022Decoder_SetGLForOneChar(pThis, pThis->apMapGn[2]);
690 break;
691
692 case 0x008f: /* Single shift three: G3 -> GL for one char. */
693 rc = rtIso2022Decoder_SetGLForOneChar(pThis, pThis->apMapGn[3]);
694 break;
695
696 case 0x002b: /* Escape should be handled by the caller. */
697 rc = rtIso2022Decoder_InterpretEsc(pThis);
698 break;
699
700 default:
701 return 0;
702 }
703
704 return RT_SUCCESS(rc) ? 1 : rc;
705}
706
707
708static int rtIso2022Decoder_Init(PRTISO2022DECODERSTATE pThis, const char *pchString, uint32_t cchString,
709 uint32_t uGL, uint32_t uC0, uint32_t uC1, uint32_t uG0,
710 PRTERRINFO pErrInfo)
711{
712 pThis->pabString = (uint8_t const *)pchString;
713 pThis->cbString = cchString;
714 pThis->offString = 0;
715
716 pThis->pMapGL = &g_DummyMap;
717 pThis->pMapGR = &g_DummyMap;
718 pThis->pMapC0 = &g_DummyMap;
719 pThis->pMapC1 = &g_DummyMap;
720 pThis->pRestoreGL = NULL;
721 pThis->apMapGn[0] = &g_DummyMap;
722 pThis->apMapGn[1] = &g_DummyMap;
723 pThis->apMapGn[2] = &g_DummyMap;
724 pThis->apMapGn[3] = &g_DummyMap;
725 pThis->pErrInfo = pErrInfo;
726
727 int rc = VINF_SUCCESS;
728 if (uGL != UINT32_MAX)
729 rc = rtIso2022Decoder_LookupAndSet(&pThis->pMapGL, uGL, g_paGLMaps, RT_ELEMENTS(g_paGLMaps));
730 if (RT_SUCCESS(rc) && uG0 != UINT32_MAX)
731 rc = rtIso2022Decoder_LookupAndSet(&pThis->apMapGn[0], uG0, g_paGLMaps, RT_ELEMENTS(g_paGLMaps));
732 if (RT_SUCCESS(rc) && uC0 != UINT32_MAX)
733 rc = rtIso2022Decoder_SetC0(pThis, uC0);
734 if (RT_SUCCESS(rc) && uC1 != UINT32_MAX)
735 rc = rtIso2022Decoder_SetC1(pThis, uC1);
736 return rc;
737}
738
739
740static int rtIso2022Decoder_GetNextUniCpSlow(PRTISO2022DECODERSTATE pThis, PRTUNICP pUniCp)
741{
742 while (pThis->offString < pThis->cbString)
743 {
744 uint8_t b = pThis->pabString[pThis->offString];
745 if (!(b & 0x80))
746 {
747 if (b >= 0x20)
748 {
749 /*
750 * GL range.
751 */
752 b -= 0x20;
753 PCRTISO2022MAP pMap = pThis->pMapGL;
754
755 /* Single byte character map. */
756 if (pMap->cb == 1)
757 {
758 if (RT_LIKELY(b < pMap->cToUni))
759 {
760 uint16_t wc = pMap->pauToUni[b];
761 if (RT_LIKELY(wc != RTISO2022_UNUSED))
762 {
763 *pUniCp = wc;
764 pThis->offString += 1;
765 return VINF_SUCCESS;
766 }
767 *pUniCp = RTUNICP_INVALID;
768 return RTErrInfoSetF(pThis->pErrInfo, VERR_ASN1_INVALID_T61_STRING_ENCODING,
769 "@%u: GL b=%#x is marked unused in map #%u range %u.",
770 pThis->offString, b + 0x20, pMap->uRegistration, pMap->cToUni);
771 }
772 *pUniCp = RTUNICP_INVALID;
773 return RTErrInfoSetF(pThis->pErrInfo, VERR_ASN1_INVALID_T61_STRING_ENCODING,
774 "@%u: GL b=%#x is outside map #%u range %u.",
775 pThis->offString, b + 0x20, pMap->uRegistration, pMap->cToUni);
776 }
777
778 /* Double byte character set. */
779 Assert(pMap->cb == 2);
780 if (pThis->offString + 1 < pThis->cbString)
781 {
782 uint8_t b2 = pThis->pabString[pThis->offString + 1];
783 b2 -= 0x20;
784 if (RT_LIKELY(b2 < 0x60))
785 {
786 uint16_t u16 = ((uint16_t)b << 8) | b2;
787 if (RT_LIKELY(u16 < pMap->cToUni))
788 {
789 uint16_t wc = pMap->pauToUni[b];
790 if (RT_LIKELY(wc != RTISO2022_UNUSED))
791 {
792 *pUniCp = wc;
793 pThis->offString += 2;
794 return VINF_SUCCESS;
795 }
796 *pUniCp = RTUNICP_INVALID;
797 return RTErrInfoSetF(pThis->pErrInfo, VERR_ASN1_INVALID_T61_STRING_ENCODING,
798 "@%u: GL b=%#x is marked unused in map #%u.",
799 pThis->offString, b + 0x20, pMap->uRegistration);
800 }
801 if (u16 >= 0x7f00)
802 {
803 *pUniCp = 0x7f; /* delete */
804 pThis->offString += 2;
805 return VINF_SUCCESS;
806 }
807 *pUniCp = RTUNICP_INVALID;
808 return RTErrInfoSetF(pThis->pErrInfo, VERR_ASN1_INVALID_T61_STRING_ENCODING,
809 "@%u: GL u16=%#x (b0=%#x b1=%#x) is outside map #%u range %u.",
810 pThis->offString, u16, b + 0x20, b2 + 0x20, pMap->uRegistration, pMap->cToUni);
811 }
812 return RTErrInfoSetF(pThis->pErrInfo, VERR_ASN1_INVALID_T61_STRING_ENCODING,
813 "@%u: 2nd GL byte outside GL range: b0=%#x b1=%#x (map #%u)",
814 pThis->offString, b + 0x20, b2 + 0x20, pMap->uRegistration);
815
816 }
817 return RTErrInfoSetF(pThis->pErrInfo, VERR_ASN1_INVALID_T61_STRING_ENCODING,
818 "@%u: EOS reading 2nd byte for GL b=%#x (map #%u).",
819 pThis->offString, b + 0x20, pMap->uRegistration);
820 }
821 else
822 {
823 /*
824 * C0 range.
825 */
826 Assert(pThis->pMapC0->cb == 0x20);
827 uint16_t wc = pThis->pMapC0->pauToUni[b];
828 if (wc != RTISO2022_UNUSED)
829 {
830 int rc;
831 if (b == 0x1b || wc == 0x1b) /* ESC is hardcoded, or so they say. */
832 rc = rtIso2022Decoder_InterpretEsc(pThis);
833 else
834 rc = rtIso2022Decoder_ControlCharHook(pThis, wc);
835 if (RT_SUCCESS(rc))
836 {
837 if (rc == 0)
838 {
839 pThis->offString += 1;
840 *pUniCp = wc;
841 return VINF_SUCCESS;
842 }
843 pThis->offString += rc;
844 }
845 else
846 return rc;
847 }
848 else
849 return RTErrInfoSetF(pThis->pErrInfo, VERR_ASN1_INVALID_T61_STRING_ENCODING,
850 "@%u: C0 b=%#x is marked unused in map #%u.",
851 pThis->offString, b, pThis->pMapC0->uRegistration);
852 }
853 }
854 else
855 {
856 if (b >= 0xa0)
857 {
858 /*
859 * GR range.
860 */
861 b -= 0xa0;
862 PCRTISO2022MAP pMap = pThis->pMapGR;
863
864 /* Single byte character map. */
865 if (pMap->cb == 1)
866 {
867 /** @todo 0xa0 = SPACE and 0xff = DELETE if it's a 94 charater map... */
868 if (RT_LIKELY(b < pMap->cToUni))
869 {
870 uint16_t wc = pMap->pauToUni[b];
871 if (RT_LIKELY(wc != RTISO2022_UNUSED))
872 {
873 *pUniCp = wc;
874 pThis->offString += 1;
875 return VINF_SUCCESS;
876 }
877
878 *pUniCp = RTUNICP_INVALID;
879 return RTErrInfoSetF(pThis->pErrInfo, VERR_ASN1_INVALID_T61_STRING_ENCODING,
880 "@%u: GR b=%#x is marked unused in map #%u.",
881 pThis->offString, b + 0xa0, pMap->uRegistration);
882 }
883 *pUniCp = RTUNICP_INVALID;
884 return RTErrInfoSetF(pThis->pErrInfo, VERR_ASN1_INVALID_T61_STRING_ENCODING,
885 "@%u: GR b=%#x is outside map #%u range %u",
886 pThis->offString, b + 0xa0, pMap->uRegistration, pMap->cToUni);
887 }
888
889 /* Double byte character set. */
890 Assert(pMap->cb == 2);
891 if (pThis->offString + 1 < pThis->cbString)
892 {
893 uint8_t b2 = pThis->pabString[pThis->offString + 1];
894 b2 -= 0xa0;
895 if (RT_LIKELY(b2 < 0x60))
896 {
897 uint16_t u16 = ((uint16_t)b << 8) | b2;
898 if (RT_LIKELY(u16 < pMap->cToUni))
899 {
900 uint16_t wc = pMap->pauToUni[b];
901 if (RT_LIKELY(wc != RTISO2022_UNUSED))
902 {
903 *pUniCp = wc;
904 pThis->offString += 2;
905 return VINF_SUCCESS;
906 }
907
908 *pUniCp = RTUNICP_INVALID;
909 return RTErrInfoSetF(pThis->pErrInfo, VERR_ASN1_INVALID_T61_STRING_ENCODING,
910 "@%u: GR b=%#x is marked unused in map #%u.",
911 pThis->offString, b + 0xa0, pMap->uRegistration);
912 }
913 *pUniCp = RTUNICP_INVALID;
914 return RTErrInfoSetF(pThis->pErrInfo, VERR_ASN1_INVALID_T61_STRING_ENCODING,
915 "@%u: GR u16=%#x (b0=%#x b1=%#x) is outside map #%u range %u.",
916 pThis->offString, u16, b + 0xa0, b2 + 0xa0, pMap->uRegistration, pMap->cToUni);
917 }
918 return RTErrInfoSetF(pThis->pErrInfo, VERR_ASN1_INVALID_T61_STRING_ENCODING,
919 "@%u: 2nd GR byte outside GR range: b0=%#x b1=%#x (map #%u).",
920 pThis->offString, b + 0xa0, b2 + 0xa0, pMap->uRegistration);
921
922 }
923 return RTErrInfoSetF(pThis->pErrInfo, VERR_ASN1_INVALID_T61_STRING_ENCODING,
924 "@%u: EOS reading 2nd byte for GR b=%#x (map #%u).",
925 pThis->offString, b + 0xa0, pMap->uRegistration);
926 }
927 else
928 {
929 /*
930 * C2 range.
931 */
932 Assert(pThis->pMapC1->cb == 0x20);
933 b -= 0x80;
934 uint16_t wc = pThis->pMapC1->pauToUni[b];
935 if (wc != RTISO2022_UNUSED)
936 {
937 int rc = rtIso2022Decoder_ControlCharHook(pThis, wc);
938 if (RT_SUCCESS(rc))
939 {
940 if (rc == 0)
941 {
942 pThis->offString += 1;
943 *pUniCp = wc;
944 return VINF_SUCCESS;
945 }
946 pThis->offString += rc;
947 }
948 else
949 return rc;
950 }
951 else
952 return RTErrInfoSetF(pThis->pErrInfo, VERR_ASN1_INVALID_T61_STRING_ENCODING,
953 "@%u: C1 b=%#x is marked unused in map #%u.",
954 pThis->offString, b + 0x80, pThis->pMapC1->uRegistration);
955 }
956 }
957 }
958
959 /* End of string. */
960 *pUniCp = RTUNICP_INVALID;
961 return VERR_END_OF_STRING;
962}
963
964DECLINLINE(int) rtIso2022Decoder_GetNextUniCp(PRTISO2022DECODERSTATE pThis, PRTUNICP pUniCp)
965{
966 /*
967 * Deal with single byte GL.
968 */
969 uint32_t const offString = pThis->offString;
970 if (pThis->offString < pThis->cbString)
971 {
972 PCRTISO2022MAP const pMapGL = pThis->pMapGL;
973 if (pMapGL->cb == 1)
974 {
975 uint8_t const b = pThis->pabString[offString] - (uint8_t)0x20;
976 if (b < pMapGL->cToUni)
977 {
978 uint16_t wc = pMapGL->pauToUni[b];
979 if (wc != RTISO2022_UNUSED)
980 {
981 pThis->offString = offString + 1;
982 *pUniCp = wc;
983 return VINF_SUCCESS;
984 }
985 }
986 }
987
988 /*
989 * Deal with complications in the non-inline function.
990 */
991 return rtIso2022Decoder_GetNextUniCpSlow(pThis, pUniCp);
992 }
993
994 *pUniCp = RTUNICP_INVALID;
995 return VERR_END_OF_STRING;
996}
997
998
999static int rtIso2022ValidateString(uint32_t uProfile, const char *pch, uint32_t cch, size_t *pcchUtf8, PRTERRINFO pErrInfo)
1000{
1001 AssertReturn(uProfile == ASN1_TAG_T61_STRING, VERR_INVALID_PARAMETER); /* just a place holder for now. */
1002
1003 RTISO2022DECODERSTATE Decoder;
1004 int rc = rtIso2022Decoder_Init(&Decoder, pch, cch, 102, 106, 107, 102, pErrInfo);
1005 if (RT_SUCCESS(rc))
1006 {
1007 size_t cchUtf8 = 0;
1008 for (;;)
1009 {
1010 RTUNICP uc;
1011 rc = rtIso2022Decoder_GetNextUniCp(&Decoder, &uc);
1012 if (RT_SUCCESS(rc))
1013 cchUtf8 += RTStrCpSize(uc);
1014 else
1015 {
1016 if (RT_LIKELY(rc == VERR_END_OF_STRING))
1017 {
1018 *pcchUtf8 = cchUtf8;
1019 return VINF_SUCCESS;
1020 }
1021 return rc;
1022 }
1023 }
1024 }
1025 return rc;
1026}
1027
1028
1029static int rtIso2022RecodeAsUtf8(uint32_t uProfile, const char *pchSrc, uint32_t cchSrc, char *pszDst, size_t cbDst)
1030{
1031 AssertReturn(uProfile == ASN1_TAG_T61_STRING, VERR_INVALID_PARAMETER); /* just a place holder for now. */
1032 AssertReturn(cbDst > 0, VERR_INVALID_PARAMETER);
1033
1034 RTISO2022DECODERSTATE Decoder;
1035 int rc = rtIso2022Decoder_Init(&Decoder, pchSrc, cchSrc, 102, 106, 107, 102, NULL /*pErrInfo*/);
1036 if (RT_SUCCESS(rc))
1037 {
1038 for (;;)
1039 {
1040 RTUNICP uc;
1041 rc = rtIso2022Decoder_GetNextUniCp(&Decoder, &uc);
1042 if (RT_SUCCESS(rc))
1043 {
1044 if (uc < 0x80 && cbDst > 1)
1045 {
1046 *pszDst++ = (char)uc;
1047 cbDst--;
1048 }
1049 else
1050 {
1051 size_t cchUniCp = RTStrCpSize(uc);
1052 if (cbDst > cchUniCp)
1053 {
1054 cbDst -= cchUniCp;
1055 pszDst = RTStrPutCp(pszDst, uc);
1056 }
1057 else
1058 {
1059 *pszDst = '\0';
1060 return VERR_BUFFER_OVERFLOW;
1061 }
1062 }
1063 }
1064 else if (RT_LIKELY(rc == VERR_END_OF_STRING))
1065 {
1066 *pszDst = '\0';
1067 return VINF_SUCCESS;
1068 }
1069 else
1070 return rc;
1071 }
1072 }
1073 return rc;
1074}
1075
1076
1077
1078/** The unicode mapping of the C1 area of windows codepage 1252.
1079 * The rest of the code page is 1:1 with unicode. */
1080static uint16_t g_awcWin1252_C1[0x20] =
1081{
1082 0x20ac, 0x0081, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, 0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008d, 0x017d, 0x008f,
1083 0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x009d, 0x017e, 0x0178,
1084};
1085
1086
1087static size_t rtWin1252CalcUtf8Length(const char *pch, uint32_t cch)
1088{
1089 size_t cchUtf8 = 0;
1090 while (cch-- > 0)
1091 {
1092 uint8_t const b = *pch++;
1093 if (b < 0x80)
1094 cchUtf8 += 1;
1095 else if (b >= 0xa0)
1096 cchUtf8 += 2;
1097 else
1098 {
1099 uint16_t const wc = g_awcWin1252_C1[b - 0x80];
1100 cchUtf8 += RTStrCpSize(wc);
1101 }
1102 }
1103 return cchUtf8;
1104}
1105
1106
1107static int rtWin1252RecodeAsUtf8(const char *pchSrc, uint32_t cchSrc, char *pszDst, size_t cbDst)
1108{
1109 while (cchSrc-- > 0)
1110 {
1111 uint8_t b = *pchSrc++;
1112 if (b < 0x80)
1113 {
1114 if (cbDst <= 1)
1115 return VERR_BUFFER_OVERFLOW;
1116 *pszDst++ = (char)b;
1117 }
1118 else
1119 {
1120 uint16_t const wc = b >= 0xa0 ? b : g_awcWin1252_C1[b - 0x80];
1121 size_t cchCp = RTStrCpSize(wc);
1122 if (cbDst <= cchCp)
1123 return VERR_BUFFER_OVERFLOW;
1124 pszDst = RTStrPutCp(pszDst, wc);
1125 }
1126 }
1127
1128 if (!cbDst)
1129 return VERR_BUFFER_OVERFLOW;
1130 *pszDst = '\0';
1131 return VINF_SUCCESS;
1132}
1133
1134
1135
1136/*
1137 * ASN.1 STRING - Specific Methods.
1138 */
1139
1140/** rtAsn1String_IsTeletexLatin1 results. */
1141typedef enum RTASN1TELETEXVARIANT
1142{
1143 /** Couldn't find hard evidence of either. */
1144 RTASN1TELETEXVARIANT_UNDECIDED = 1,
1145 /** Pretty certain that it's real teletex. */
1146 RTASN1TELETEXVARIANT_TELETEX,
1147 /** Pretty sure it's latin-1 or Windows-1252. */
1148 RTASN1TELETEXVARIANT_LATIN1,
1149 /** Pretty sure it's Windows-1252. */
1150 RTASN1TELETEXVARIANT_WIN_1252
1151} RTASN1TELETEXVARIANT;
1152
1153/**
1154 * Takes a guess as whether TELETEX STRING (T61 STRING) is actually is Latin-1
1155 * or the real thing.
1156 *
1157 * According to RFC-2459, section 4.1.2.4, various libraries, certificate
1158 * authorities and others have perverted the TeletexString/T61String tag by
1159 * ISO-8859-1 (aka latin-1) strings (more probably these are actually Windows
1160 * CP-1252 rather than latin-1). We'll try detect incompatible latin-1
1161 * perversions by:
1162 * - The use of GR (0xf0-0xff) chars.
1163 * - The lack of ESC sequences and shifts (LS0,LS1,SS2,SS3)
1164 *
1165 * An ASSUMTION here is that GR is not loaded with anything at the start of a
1166 * teletex string, as per table 3 in section 8.23.5.2 in T-REC-X.590.200811.
1167 *
1168 * @retval @c true if chances are good that it's LATIN-1.
1169 * @retval @c false if changes are very good that it's real teletex.
1170 * @param pch The first char in the string.
1171 * @param cch The string length.
1172 *
1173 * @remarks Useful info on Teletex and ISO/IEC-2022:
1174 * https://www.mail-archive.com/[email protected]/msg00460.html
1175 * http://en.wikipedia.org/wiki/ISO/IEC_2022
1176 * http://www.open-std.org/cen/tc304/guide/GCONCEPT.HTM
1177 * http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-035.pdf
1178 */
1179static RTASN1TELETEXVARIANT rtAsn1String_IsTeletexLatin1(const char *pch, uint32_t cch)
1180{
1181 RTASN1TELETEXVARIANT enmVariant = RTASN1TELETEXVARIANT_UNDECIDED;
1182 while (cch-- > 0)
1183 {
1184 uint8_t const b = *pch;
1185 if (b >= 0x20 && b <= 0x7f)
1186 {
1187 if (g_awcIsoIr102Decode[b - 0x20] == RTISO2022_UNUSED)
1188 enmVariant = RTASN1TELETEXVARIANT_LATIN1;
1189 }
1190 else
1191 {
1192 if ( b == 0x1b /* ESC */
1193 || b == 0x0e /* LS0 / SI */
1194 || b == 0x0f /* LS1 / SO */
1195 || b == 0x19 /* SS2 */
1196 || b == 0x1d /* SS3 */ )
1197 return RTASN1TELETEXVARIANT_TELETEX;
1198
1199 if (b >= 0xa0)
1200 enmVariant = RTASN1TELETEXVARIANT_LATIN1;
1201 else if (b >= 0x80 && b <= 0x9f)
1202 {
1203 /* Any use of C1 characters defined by windows cp-1252 will
1204 lead us to believe it's the windows code rather than the
1205 ISO/IEC standard that is being used. (Not that it makes
1206 much of a difference, because we're gonna treat it as the
1207 windows codepage, anyways.) */
1208 if ( b != 0x81
1209 && b != 0x8d
1210 && b != 0x8f
1211 && b != 0x90
1212 && b != 0x9d)
1213 return RTASN1TELETEXVARIANT_WIN_1252;
1214 }
1215 }
1216 }
1217 return RTASN1TELETEXVARIANT_UNDECIDED;
1218}
1219
1220
1221/**
1222 * Checks the encoding of an ASN.1 string according to it's tag.
1223 *
1224 * @returns IPRT status code.
1225 * @param pThis The string to santity check.
1226 * @param pErrInfo Where to store extra error info. Optional.
1227 * @param pcchUtf8 Where to return the UTF-8 string length. Optional.
1228 */
1229static int rtAsn1String_CheckSanity(PCRTASN1STRING pThis, PRTERRINFO pErrInfo, const char *pszErrorTag, size_t *pcchUtf8)
1230{
1231 int rc;
1232 uint32_t cch = pThis->Asn1Core.cb;
1233 size_t cchUtf8 = cch;
1234 const char *pch = pThis->Asn1Core.uData.pch;
1235 uint32_t uTag = RTASN1CORE_GET_TAG(&pThis->Asn1Core);
1236 switch (uTag)
1237 {
1238 case ASN1_TAG_UTF8_STRING:
1239 rc = RTStrValidateEncodingEx(pch, cch, 0);
1240 if (RT_SUCCESS(rc))
1241 break;
1242 return RTErrInfoSetF(pErrInfo, VERR_ASN1_INVALID_UTF8_STRING_ENCODING, "%s: Bad UTF-8 encoding (%Rrc, %.*Rhxs)",
1243 pszErrorTag, rc, pThis->Asn1Core.cb, pThis->Asn1Core.uData.pch);
1244
1245 case ASN1_TAG_NUMERIC_STRING:
1246 while (cch-- > 0)
1247 {
1248 char ch = *pch++;
1249 if ( !RT_C_IS_DIGIT(ch)
1250 && ch != ' ')
1251 return RTErrInfoSetF(pErrInfo, VERR_ASN1_INVALID_NUMERIC_STRING_ENCODING,
1252 "%s: Bad numeric string: ch=%#x (pos %u in %.*Rhxs)", pszErrorTag, ch,
1253 pThis->Asn1Core.cb - cch + 1, pThis->Asn1Core.cb, pThis->Asn1Core.uData.pch);
1254 }
1255 break;
1256
1257 case ASN1_TAG_PRINTABLE_STRING:
1258 while (cch-- > 0)
1259 {
1260 char ch = *pch++;
1261 if ( !RT_C_IS_ALNUM(ch)
1262 && ch != ' '
1263 && ch != '\''
1264 && ch != '('
1265 && ch != ')'
1266 && ch != '+'
1267 && ch != ','
1268 && ch != '-'
1269 && ch != '.'
1270 && ch != '/'
1271 && ch != ':'
1272 && ch != '='
1273 && ch != '?'
1274 )
1275 return RTErrInfoSetF(pErrInfo, VERR_ASN1_INVALID_PRINTABLE_STRING_ENCODING,
1276 "%s: Bad printable string: ch=%#x (pos %u in %.*Rhxs)", pszErrorTag, ch,
1277 pThis->Asn1Core.cb - cch + 1, pThis->Asn1Core.cb, pThis->Asn1Core.uData.pch);
1278 }
1279 break;
1280
1281 case ASN1_TAG_IA5_STRING: /* ASCII */
1282 while (cch-- > 0)
1283 {
1284 unsigned char ch = *pch++;
1285 if (ch == 0 || ch >= 0x80)
1286 {
1287 /* Ignore C-style zero terminator as the "Microsoft ECC Product Root Certificate Authority 2018"
1288 for instance, has a policy qualifier string "http://www.microsoft.com/pkiops/Docs/Repository.htm\0" */
1289 /** @todo should '\0' really be excluded above? */
1290 if (ch != 0 || cch != 0)
1291 return RTErrInfoSetF(pErrInfo, VERR_ASN1_INVALID_IA5_STRING_ENCODING,
1292 "%s: Bad IA5 string: ch=%#x (pos %u in %.*Rhxs)", pszErrorTag, ch,
1293 pThis->Asn1Core.cb - cch + 1, pThis->Asn1Core.cb, pThis->Asn1Core.uData.pch);
1294 break;
1295 }
1296 }
1297 break;
1298
1299 case ASN1_TAG_T61_STRING:
1300 switch (rtAsn1String_IsTeletexLatin1(pch, cch))
1301 {
1302 default:
1303 rc = rtIso2022ValidateString(ASN1_TAG_T61_STRING, pch, cch, &cchUtf8, pErrInfo);
1304 if (RT_FAILURE(rc))
1305 return rc;
1306 break;
1307 case RTASN1TELETEXVARIANT_UNDECIDED:
1308 case RTASN1TELETEXVARIANT_LATIN1:
1309 case RTASN1TELETEXVARIANT_WIN_1252:
1310 cchUtf8 = rtWin1252CalcUtf8Length(pch, cch);
1311 break;
1312 }
1313 break;
1314
1315 case ASN1_TAG_VIDEOTEX_STRING:
1316 case ASN1_TAG_GRAPHIC_STRING:
1317 return VERR_ASN1_STRING_TYPE_NOT_IMPLEMENTED;
1318
1319 case ASN1_TAG_VISIBLE_STRING:
1320 while (cch-- > 0)
1321 {
1322 unsigned char ch = *pch++;
1323 if (ch < 0x20 || ch >= 0x7f)
1324 return RTErrInfoSetF(pErrInfo, VERR_ASN1_INVALID_VISIBLE_STRING_ENCODING,
1325 "%s: Bad visible string: ch=%#x (pos %u in %.*Rhxs)", pszErrorTag, ch,
1326 pThis->Asn1Core.cb - cch + 1, pThis->Asn1Core.cb, pThis->Asn1Core.uData.pch);
1327 }
1328 break;
1329
1330 case ASN1_TAG_GENERAL_STRING:
1331 return VERR_ASN1_STRING_TYPE_NOT_IMPLEMENTED;
1332
1333 case ASN1_TAG_UNIVERSAL_STRING:
1334 if (!(cch & 3))
1335 {
1336 uint8_t const *pb = (uint8_t const *)pch;
1337 cchUtf8 = 0;
1338 while (cch > 0)
1339 {
1340 RTUNICP uc = RT_MAKE_U32_FROM_U8(pb[3], pb[2], pb[1], pb[0]); /* big endian */
1341 if (!RTUniCpIsValid(uc))
1342 return RTErrInfoSetF(pErrInfo, VERR_ASN1_INVALID_UNIVERSAL_STRING_ENCODING,
1343 "%s: Bad universal string: uc=%#x (pos %u in %.*Rhxs)", pszErrorTag, uc,
1344 pThis->Asn1Core.cb - cch + 1, pThis->Asn1Core.cb, pThis->Asn1Core.uData.pch);
1345 cchUtf8 += RTUniCpCalcUtf8Len(uc);
1346
1347 /* next */
1348 pb += 4;
1349 cch -= 4;
1350 }
1351 break;
1352 }
1353 return RTErrInfoSetF(pErrInfo, VERR_ASN1_INVALID_UNIVERSAL_STRING_ENCODING,
1354 "%s: Bad universal string: size not a multiple of 4: cch=%#x (%.*Rhxs)",
1355 pszErrorTag, cch, pThis->Asn1Core.cb, pThis->Asn1Core.uData.pch);
1356
1357 case ASN1_TAG_BMP_STRING:
1358 if (!(cch & 1))
1359 {
1360 uint8_t const *pb = (uint8_t const *)pch;
1361 cchUtf8 = 0;
1362 while (cch > 0)
1363 {
1364 RTUNICP uc = RT_MAKE_U32_FROM_U8(pb[1], pb[0], 0, 0); /* big endian */
1365 if (!RTUniCpIsValid(uc))
1366 return RTErrInfoSetF(pErrInfo, VERR_ASN1_INVALID_BMP_STRING_ENCODING,
1367 "%s: Bad BMP string: uc=%#x (pos %u in %.*Rhxs)", pszErrorTag, uc,
1368 pThis->Asn1Core.cb - cch + 1, pThis->Asn1Core.cb, pThis->Asn1Core.uData.pch);
1369 cchUtf8 += RTUniCpCalcUtf8Len(uc);
1370
1371 /* next */
1372 pb += 2;
1373 cch -= 2;
1374 }
1375 break;
1376 }
1377 return RTErrInfoSetF(pErrInfo, VERR_ASN1_INVALID_BMP_STRING_ENCODING,
1378 "%s: Bad BMP string: odd number of bytes cch=%#x (pos %u in %.*Rhxs)",
1379 pszErrorTag, cch, pThis->Asn1Core.cb, pThis->Asn1Core.uData.pch);
1380
1381 default:
1382 AssertMsgFailedReturn(("uTag=%#x\n", uTag), VERR_INTERNAL_ERROR_3);
1383 }
1384
1385 if (pcchUtf8)
1386 *pcchUtf8 = cchUtf8;
1387 return VINF_SUCCESS;
1388}
1389
1390
1391RTDECL(int) RTAsn1String_CompareValues(PCRTASN1STRING pLeft, PCRTASN1STRING pRight)
1392{
1393 return RTAsn1String_CompareEx(pLeft, pRight, false /*fTypeToo*/);
1394}
1395
1396
1397RTDECL(int) RTAsn1String_CompareEx(PCRTASN1STRING pLeft, PCRTASN1STRING pRight, bool fTypeToo)
1398{
1399 Assert(pLeft && (!RTAsn1String_IsPresent(pLeft) || pLeft->Asn1Core.pOps == &g_RTAsn1String_Vtable));
1400 Assert(pRight && (!RTAsn1String_IsPresent(pRight) || pRight->Asn1Core.pOps == &g_RTAsn1String_Vtable));
1401
1402 int iDiff;
1403 if (RTAsn1String_IsPresent(pLeft))
1404 {
1405 if (RTAsn1String_IsPresent(pRight))
1406 {
1407 if (!fTypeToo || RTASN1CORE_GET_TAG(&pLeft->Asn1Core) == RTASN1CORE_GET_TAG(&pRight->Asn1Core))
1408 iDiff = RTAsn1Core_CompareEx(&pLeft->Asn1Core, &pRight->Asn1Core, true /*fIgnoreTagAndClass*/);
1409 else
1410 iDiff = RTASN1CORE_GET_TAG(&pLeft->Asn1Core) < RTASN1CORE_GET_TAG(&pRight->Asn1Core) ? -1 : 1;
1411 }
1412 else
1413 iDiff = 1;
1414 }
1415 else
1416 iDiff = 0 - RTAsn1String_IsPresent(pRight);
1417 return iDiff;
1418}
1419
1420
1421RTDECL(int) RTAsn1String_CompareWithString(PCRTASN1STRING pThis, const char *pszString, size_t cchString)
1422{
1423 Assert(pThis && (!RTAsn1String_IsPresent(pThis) || pThis->Asn1Core.pOps == &g_RTAsn1String_Vtable));
1424 AssertPtr(pszString);
1425
1426 int iDiff;
1427 if (RTAsn1String_IsPresent(pThis))
1428 {
1429 if (cchString == RTSTR_MAX)
1430 cchString = strlen(pszString);
1431
1432 /*
1433 * If there is a UTF-8 conversion available already, use it.
1434 */
1435 if (pThis->pszUtf8)
1436 {
1437 iDiff = strncmp(pThis->pszUtf8, pszString, cchString);
1438 if (!iDiff && pThis->cchUtf8 != cchString)
1439 iDiff = pThis->cchUtf8 < cchString ? -1 : 1;
1440 }
1441 else
1442 {
1443 /*
1444 * Some types are UTF-8 compatible, so try do the compare without
1445 * RTAsn1String_QueryUtf8.
1446 */
1447 uint32_t cch = pThis->Asn1Core.cb;
1448 const char *pch = pThis->Asn1Core.uData.pch;
1449 switch (RTASN1CORE_GET_TAG(&pThis->Asn1Core))
1450 {
1451 case ASN1_TAG_UTF8_STRING:
1452 case ASN1_TAG_NUMERIC_STRING:
1453 case ASN1_TAG_IA5_STRING:
1454 case ASN1_TAG_PRINTABLE_STRING:
1455 iDiff = strncmp(pch, pszString, RT_MIN(cch, cchString));
1456 if (iDiff && cch != cchString)
1457 iDiff = cch < cchString ? - 1 : 1;
1458 break;
1459
1460 /** @todo Implement comparing ASN1_TAG_BMP_STRING, ASN1_TAG_UNIVERSAL_STRING and
1461 * ASN1_TAG_T61_STRING with UTF-8 strings without conversion. */
1462
1463 default:
1464 {
1465 int rc = RTAsn1String_QueryUtf8(pThis, NULL, NULL);
1466 if (RT_SUCCESS(rc))
1467 {
1468 iDiff = strncmp(pThis->pszUtf8, pszString, cchString);
1469 if (!iDiff && pThis->cchUtf8 != cchString)
1470 iDiff = pThis->cchUtf8 < cchString ? -1 : 1;
1471 }
1472 else
1473 iDiff = -1;
1474 break;
1475 }
1476 }
1477 }
1478
1479 /* Reduce the strcmp return value. */
1480 if (iDiff != 0)
1481 iDiff = iDiff < 0 ? -1 : 1;
1482 }
1483 else
1484 iDiff = -1;
1485 return iDiff;
1486}
1487
1488
1489RTDECL(int) RTAsn1String_QueryUtf8(PCRTASN1STRING pThis, const char **ppsz, size_t *pcch)
1490{
1491 Assert(pThis->Asn1Core.pOps == &g_RTAsn1String_Vtable);
1492
1493 char *psz = (char *)pThis->pszUtf8;
1494 size_t cch = pThis->cchUtf8;
1495 if (!psz)
1496 {
1497
1498 /*
1499 * Convert the first time around. Start by validating the encoding and
1500 * calculating the length.
1501 */
1502 int rc = rtAsn1String_CheckSanity(pThis, NULL, NULL, &cch);
1503 if (RT_SUCCESS(rc))
1504 {
1505 PRTASN1STRING pThisNC = (PRTASN1STRING)pThis;
1506 rc = RTAsn1MemAllocZ(&pThisNC->Allocation, (void **)&psz, cch + 1);
1507 if (RT_SUCCESS(rc))
1508 {
1509 /*
1510 * Got memory, now do the actual convertion to UTF-8 / copying.
1511 */
1512 switch (RTASN1CORE_GET_TAG(&pThis->Asn1Core))
1513 {
1514 case ASN1_TAG_UTF8_STRING:
1515 case ASN1_TAG_NUMERIC_STRING:
1516 case ASN1_TAG_PRINTABLE_STRING:
1517 case ASN1_TAG_IA5_STRING:
1518 case ASN1_TAG_VISIBLE_STRING:
1519 Assert(cch == pThis->Asn1Core.cb);
1520 memcpy(psz, pThis->Asn1Core.uData.pch, cch);
1521 psz[cch] = '\0';
1522 break;
1523
1524 case ASN1_TAG_T61_STRING:
1525 switch (rtAsn1String_IsTeletexLatin1(pThis->Asn1Core.uData.pch, pThis->Asn1Core.cb))
1526 {
1527 default:
1528 rc = rtIso2022RecodeAsUtf8(ASN1_TAG_T61_STRING, pThis->Asn1Core.uData.pch, pThis->Asn1Core.cb,
1529 psz, cch + 1);
1530 break;
1531 case RTASN1TELETEXVARIANT_UNDECIDED:
1532 case RTASN1TELETEXVARIANT_LATIN1:
1533 case RTASN1TELETEXVARIANT_WIN_1252:
1534 rc = rtWin1252RecodeAsUtf8(pThis->Asn1Core.uData.pch, pThis->Asn1Core.cb, psz, cch + 1);
1535 break;
1536 }
1537 AssertReturnStmt(RT_SUCCESS(rc), RTAsn1MemFree(&pThisNC->Allocation, psz), VERR_INTERNAL_ERROR_3);
1538 break;
1539
1540 /* case ASN1_TAG_VIDEOTEX_STRING: */
1541 /* case ASN1_TAG_GRAPHIC_STRING: */
1542 /* case ASN1_TAG_GENERAL_STRING: */
1543
1544 case ASN1_TAG_UNIVERSAL_STRING:
1545 {
1546 char *pszDst = psz;
1547 size_t cchSrc = pThis->Asn1Core.cb;
1548 uint8_t const *pbSrc = pThis->Asn1Core.uData.pu8;
1549 while (cchSrc > 0)
1550 {
1551 RTUNICP uc = RT_MAKE_U32_FROM_U8(pbSrc[3], pbSrc[2], pbSrc[1], pbSrc[0]); /* big endian */
1552 AssertReturnStmt(RTUniCpIsValid(uc), RTAsn1MemFree(&pThisNC->Allocation, psz), VERR_INTERNAL_ERROR_2);
1553 pszDst = RTStrPutCp(pszDst, uc);
1554
1555 /* next */
1556 pbSrc += 4;
1557 cchSrc -= 4;
1558 }
1559 Assert((size_t)(pszDst - psz) == cch);
1560 break;
1561 }
1562
1563 case ASN1_TAG_BMP_STRING:
1564 {
1565 char *pszDst = psz;
1566 size_t cchSrc = pThis->Asn1Core.cb;
1567 uint8_t const *pbSrc = pThis->Asn1Core.uData.pu8;
1568 while (cchSrc > 0)
1569 {
1570 RTUNICP uc = RT_MAKE_U32_FROM_U8(pbSrc[1], pbSrc[0], 0, 0); /* big endian */
1571 AssertReturnStmt(RTUniCpIsValid(uc), RTAsn1MemFree(&pThisNC->Allocation, psz), VERR_INTERNAL_ERROR_2);
1572 pszDst = RTStrPutCp(pszDst, uc);
1573
1574 /* next */
1575 pbSrc += 2;
1576 cchSrc -= 2;
1577 }
1578 Assert((size_t)(pszDst - psz) == cch);
1579 break;
1580 }
1581
1582 default:
1583 RTAsn1MemFree(&pThisNC->Allocation, psz);
1584 AssertMsgFailedReturn(("uTag=%#x\n", RTASN1CORE_GET_TAG(&pThis->Asn1Core)), VERR_INTERNAL_ERROR_3);
1585 }
1586
1587 /*
1588 * Successfully produced UTF-8. Save it in the object.
1589 */
1590 pThisNC->pszUtf8 = psz;
1591 pThisNC->cchUtf8 = (uint32_t)cch;
1592 }
1593 else
1594 return rc;
1595 }
1596 else
1597 return rc;
1598 }
1599
1600 /*
1601 * Success.
1602 */
1603 if (ppsz)
1604 *ppsz = psz;
1605 if (pcch)
1606 *pcch = cch;
1607 return VINF_SUCCESS;
1608}
1609
1610
1611
1612RTDECL(int) RTAsn1String_QueryUtf8Len(PCRTASN1STRING pThis, size_t *pcch)
1613{
1614 Assert(pThis->Asn1Core.pOps == &g_RTAsn1String_Vtable);
1615
1616 size_t cch = pThis->cchUtf8;
1617 if (!cch && !pThis->pszUtf8)
1618 {
1619 int rc = rtAsn1String_CheckSanity(pThis, NULL, NULL, &cch);
1620 if (RT_FAILURE(rc))
1621 return rc;
1622 }
1623
1624 *pcch = cch;
1625 return VINF_SUCCESS;
1626}
1627
1628
1629
1630
1631RTDECL(int) RTAsn1String_InitEx(PRTASN1STRING pThis, uint32_t uTag, void const *pvValue, size_t cbValue,
1632 PCRTASN1ALLOCATORVTABLE pAllocator)
1633{
1634 RT_ZERO(*pThis);
1635 AssertMsgReturn(uTag < RT_ELEMENTS(g_acbStringTags) && g_acbStringTags[uTag] > 0, ("uTag=%#x\n", uTag),
1636 VERR_INVALID_PARAMETER);
1637
1638 RTAsn1MemInitAllocation(&pThis->Allocation, pAllocator);
1639 RTAsn1Core_InitEx(&pThis->Asn1Core,
1640 uTag,
1641 ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_PRIMITIVE,
1642 &g_RTAsn1String_Vtable,
1643 RTASN1CORE_F_PRESENT | RTASN1CORE_F_PRIMITE_TAG_STRUCT);
1644
1645 if (cbValue > 0)
1646 {
1647 int rc = RTAsn1ContentDup(&pThis->Asn1Core, pvValue, cbValue, pAllocator);
1648 if (RT_FAILURE(rc))
1649 return rc;
1650 }
1651
1652 return VINF_SUCCESS;
1653}
1654
1655
1656RTDECL(int) RTAsn1String_InitWithValue(PRTASN1STRING pThis, const char *pszUtf8Value, PCRTASN1ALLOCATORVTABLE pAllocator)
1657{
1658 Assert(RTStrValidateEncoding(pszUtf8Value));
1659 return RTAsn1String_InitEx(pThis, ASN1_TAG_UTF8_STRING, pszUtf8Value, strlen(pszUtf8Value), pAllocator);
1660}
1661
1662
1663RTDECL(int) RTAsn1String_RecodeAsUtf8(PRTASN1STRING pThis, PCRTASN1ALLOCATORVTABLE pAllocator)
1664{
1665 /*
1666 * Query the UTF-8 string. Do this even if it's already an
1667 * ASN1_TAG_UTF8_STRING object as it makes sure we've got a valid UTF-8
1668 * string upon successful return.
1669 */
1670 int rc = RTAsn1String_QueryUtf8(pThis, NULL, NULL);
1671 if (RT_SUCCESS(rc))
1672 {
1673 if (RTASN1CORE_GET_TAG(&pThis->Asn1Core) != ASN1_TAG_UTF8_STRING)
1674 {
1675 /*
1676 * Resize the content, copy the UTF-8 bytes in there, and change
1677 * the tag.
1678 */
1679 rc = RTAsn1ContentReallocZ(&pThis->Asn1Core, pThis->cchUtf8, pAllocator);
1680 if (RT_SUCCESS(rc))
1681 {
1682 memcpy((void *)pThis->Asn1Core.uData.pv, pThis->pszUtf8, pThis->cchUtf8);
1683 rc = RTAsn1Core_ChangeTag(&pThis->Asn1Core, ASN1_TAG_UTF8_STRING);
1684 }
1685 }
1686 }
1687 return rc;
1688}
1689
1690
1691
1692/*
1693 * ASN.1 STRING - Standard Methods.
1694 */
1695
1696RT_DECL_DATA_CONST(RTASN1COREVTABLE const) g_RTAsn1String_Vtable =
1697{
1698 "RTAsn1String",
1699 sizeof(RTASN1STRING),
1700 UINT8_MAX,
1701 ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_PRIMITIVE,
1702 0,
1703 (PFNRTASN1COREVTDTOR)RTAsn1String_Delete,
1704 NULL,
1705 (PFNRTASN1COREVTCLONE)RTAsn1String_Clone,
1706 (PFNRTASN1COREVTCOMPARE)RTAsn1String_Compare,
1707 (PFNRTASN1COREVTCHECKSANITY)RTAsn1String_CheckSanity,
1708 NULL,
1709 NULL
1710};
1711
1712
1713RTDECL(int) RTAsn1String_Init(PRTASN1STRING pThis, PCRTASN1ALLOCATORVTABLE pAllocator)
1714{
1715 return RTAsn1String_InitEx(pThis, ASN1_TAG_UTF8_STRING, NULL /*pvValue*/, 0 /*cbValue*/, pAllocator);
1716}
1717
1718
1719RTDECL(int) RTAsn1String_Clone(PRTASN1STRING pThis, PCRTASN1STRING pSrc, PCRTASN1ALLOCATORVTABLE pAllocator)
1720{
1721 AssertPtr(pSrc); AssertPtr(pThis); AssertPtr(pAllocator);
1722 RT_ZERO(*pThis);
1723 if (RTAsn1String_IsPresent(pSrc))
1724 {
1725 AssertReturn(pSrc->Asn1Core.pOps == &g_RTAsn1String_Vtable, VERR_INTERNAL_ERROR_3);
1726 int rc = RTAsn1Core_CloneContent(&pThis->Asn1Core, &pSrc->Asn1Core, pAllocator);
1727 if (RT_SUCCESS(rc))
1728 {
1729 /* Don't copy the UTF-8 representation, decode it when queried. */
1730 RTAsn1MemInitAllocation(&pThis->Allocation, pAllocator);
1731 return VINF_SUCCESS;
1732 }
1733 }
1734 return VINF_SUCCESS;
1735}
1736
1737
1738RTDECL(void) RTAsn1String_Delete(PRTASN1STRING pThis)
1739{
1740 if ( pThis
1741 && RTAsn1String_IsPresent(pThis))
1742 {
1743 Assert(pThis->Asn1Core.pOps == &g_RTAsn1String_Vtable);
1744
1745 if (pThis->Allocation.cbAllocated)
1746 RTAsn1MemFree(&pThis->Allocation, (char *)pThis->pszUtf8);
1747 RTAsn1ContentFree(&pThis->Asn1Core);
1748 RT_ZERO(*pThis);
1749 }
1750}
1751
1752
1753RTDECL(int) RTAsn1String_Enum(PRTASN1STRING pThis, PFNRTASN1ENUMCALLBACK pfnCallback, uint32_t uDepth, void *pvUser)
1754{
1755 RT_NOREF_PV(pThis); RT_NOREF_PV(pfnCallback); RT_NOREF_PV(uDepth); RT_NOREF_PV(pvUser);
1756 Assert(pThis && (!RTAsn1String_IsPresent(pThis) || pThis->Asn1Core.pOps == &g_RTAsn1String_Vtable));
1757
1758 /* No children to enumerate. */
1759 return VINF_SUCCESS;
1760}
1761
1762
1763RTDECL(int) RTAsn1String_Compare(PCRTASN1STRING pLeft, PCRTASN1STRING pRight)
1764{
1765 /* Compare tag and binary value. */
1766 return RTAsn1String_CompareEx(pLeft, pRight, true /*fTypeToo*/);
1767}
1768
1769
1770RTDECL(int) RTAsn1String_CheckSanity(PCRTASN1STRING pThis, uint32_t fFlags, PRTERRINFO pErrInfo, const char *pszErrorTag)
1771{
1772 RT_NOREF_PV(fFlags);
1773 if (RT_UNLIKELY(!RTAsn1String_IsPresent(pThis)))
1774 return RTErrInfoSetF(pErrInfo, VERR_ASN1_NOT_PRESENT, "%s: Missing (STRING).", pszErrorTag);
1775 return rtAsn1String_CheckSanity(pThis, pErrInfo, pszErrorTag, NULL /*pcchUtf8*/);
1776}
1777
1778
1779/*
1780 * Generate code for the tag specific methods.
1781 * Note! This is very similar to what we're doing in asn1-ut-time.cpp.
1782 */
1783#define RTASN1STRING_IMPL(a_uTag, a_szTag, a_Api) \
1784 \
1785 RTDECL(int) RT_CONCAT(a_Api,_Init)(PRTASN1STRING pThis, PCRTASN1ALLOCATORVTABLE pAllocator) \
1786 { \
1787 return RTAsn1String_InitEx(pThis, a_uTag, NULL /*pvValue*/, 0 /*cbValue*/, pAllocator); \
1788 } \
1789 \
1790 RTDECL(int) RT_CONCAT(a_Api,_Clone)(PRTASN1STRING pThis, PCRTASN1STRING pSrc, PCRTASN1ALLOCATORVTABLE pAllocator) \
1791 { \
1792 AssertReturn(RTASN1CORE_GET_TAG(&pSrc->Asn1Core) == a_uTag || !RTAsn1String_IsPresent(pSrc), \
1793 VERR_ASN1_STRING_TAG_MISMATCH); \
1794 return RTAsn1String_Clone(pThis, pSrc, pAllocator); \
1795 } \
1796 \
1797 RTDECL(void) RT_CONCAT(a_Api,_Delete)(PRTASN1STRING pThis) \
1798 { \
1799 Assert( !pThis \
1800 || !RTAsn1String_IsPresent(pThis) \
1801 || ( pThis->Asn1Core.pOps == &g_RTAsn1String_Vtable \
1802 && RTASN1CORE_GET_TAG(&pThis->Asn1Core) == a_uTag) ); \
1803 RTAsn1String_Delete(pThis); \
1804 } \
1805 \
1806 RTDECL(int) RT_CONCAT(a_Api,_Enum)(PRTASN1STRING pThis, PFNRTASN1ENUMCALLBACK pfnCallback, uint32_t uDepth, void *pvUser) \
1807 { \
1808 RT_NOREF_PV(pThis); RT_NOREF_PV(pfnCallback); RT_NOREF_PV(uDepth); RT_NOREF_PV(pvUser); \
1809 Assert( pThis \
1810 && ( !RTAsn1String_IsPresent(pThis) \
1811 || ( pThis->Asn1Core.pOps == &g_RTAsn1String_Vtable \
1812 && RTASN1CORE_GET_TAG(&pThis->Asn1Core) == a_uTag) ) ); \
1813 /* No children to enumerate. */ \
1814 return VINF_SUCCESS; \
1815 } \
1816 \
1817 RTDECL(int) RT_CONCAT(a_Api,_Compare)(PCRTASN1STRING pLeft, PCRTASN1STRING pRight) \
1818 { \
1819 int iDiff = RTAsn1String_CompareEx(pLeft, pRight, true /*fTypeToo*/); \
1820 if (!iDiff && RTASN1CORE_GET_TAG(&pLeft->Asn1Core) != a_uTag && RTAsn1String_IsPresent(pLeft)) \
1821 iDiff = RTASN1CORE_GET_TAG(&pLeft->Asn1Core) < a_uTag ? -1 : 1; \
1822 return iDiff; \
1823 } \
1824 \
1825 RTDECL(int) RT_CONCAT(a_Api,_CheckSanity)(PCRTASN1STRING pThis, uint32_t fFlags, \
1826 PRTERRINFO pErrInfo, const char *pszErrorTag) \
1827 { \
1828 if (RTASN1CORE_GET_TAG(&pThis->Asn1Core) != a_uTag && RTAsn1String_IsPresent(pThis)) \
1829 return RTErrInfoSetF(pErrInfo, VERR_ASN1_STRING_TAG_MISMATCH, "%s: uTag=%#x, expected %#x (%s)", \
1830 pszErrorTag, RTASN1CORE_GET_TAG(&pThis->Asn1Core), a_uTag, a_szTag); \
1831 return RTAsn1String_CheckSanity(pThis, fFlags, pErrInfo, pszErrorTag); \
1832 }
1833
1834#include "asn1-ut-string-template2.h"
1835
1836
1837/*
1838 * Generate code for the associated collection types.
1839 */
1840#define RTASN1TMPL_TEMPLATE_FILE "../common/asn1/asn1-ut-string-template.h"
1841#include <iprt/asn1-generator-internal-header.h>
1842#include <iprt/asn1-generator-core.h>
1843#include <iprt/asn1-generator-init.h>
1844#include <iprt/asn1-generator-sanity.h>
1845
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette