VirtualBox

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

Last change on this file since 74762 was 69111, checked in by vboxsync, 7 years ago

(C) year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 67.3 KB
Line 
1/* $Id: asn1-ut-string.cpp 69111 2017-10-17 14:26:02Z vboxsync $ */
2/** @file
3 * IPRT - ASN.1, XXX STRING Types.
4 */
5
6/*
7 * Copyright (C) 2006-2017 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/asn1@asn1.org/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,
1243 "%s: Bad UTF-8 encoding (%Rrc)", pszErrorTag, rc);
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 numberic string: ch=%#x", pszErrorTag, ch);
1253 }
1254 break;
1255
1256 case ASN1_TAG_PRINTABLE_STRING:
1257 while (cch-- > 0)
1258 {
1259 char ch = *pch++;
1260 if ( !RT_C_IS_ALNUM(ch)
1261 && ch != ' '
1262 && ch != '\''
1263 && ch != '('
1264 && ch != ')'
1265 && ch != '+'
1266 && ch != ','
1267 && ch != '-'
1268 && ch != '.'
1269 && ch != '/'
1270 && ch != ':'
1271 && ch != '='
1272 && ch != '?'
1273 )
1274 return RTErrInfoSetF(pErrInfo, VERR_ASN1_INVALID_PRINTABLE_STRING_ENCODING,
1275 "%s: Bad printable string: ch=%#x", pszErrorTag, ch);
1276 }
1277 break;
1278
1279 case ASN1_TAG_IA5_STRING: /* ASCII */
1280 while (cch-- > 0)
1281 {
1282 unsigned char ch = *pch++;
1283 if (ch == 0 || ch >= 0x80)
1284 return RTErrInfoSetF(pErrInfo, VERR_ASN1_INVALID_IA5_STRING_ENCODING,
1285 "%s: Bad IA5 string: ch=%#x", pszErrorTag, ch);
1286 }
1287 break;
1288
1289 case ASN1_TAG_T61_STRING:
1290 switch (rtAsn1String_IsTeletexLatin1(pch, cch))
1291 {
1292 default:
1293 rc = rtIso2022ValidateString(ASN1_TAG_T61_STRING, pch, cch, &cchUtf8, pErrInfo);
1294 if (RT_FAILURE(rc))
1295 return rc;
1296 break;
1297 case RTASN1TELETEXVARIANT_UNDECIDED:
1298 case RTASN1TELETEXVARIANT_LATIN1:
1299 case RTASN1TELETEXVARIANT_WIN_1252:
1300 cchUtf8 = rtWin1252CalcUtf8Length(pch, cch);
1301 break;
1302 }
1303 break;
1304
1305 case ASN1_TAG_VIDEOTEX_STRING:
1306 case ASN1_TAG_GRAPHIC_STRING:
1307 return VERR_ASN1_STRING_TYPE_NOT_IMPLEMENTED;
1308
1309 case ASN1_TAG_VISIBLE_STRING:
1310 while (cch-- > 0)
1311 {
1312 unsigned char ch = *pch++;
1313 if (ch < 0x20 || ch >= 0x7f)
1314 return RTErrInfoSetF(pErrInfo, VERR_ASN1_INVALID_VISIBLE_STRING_ENCODING,
1315 "%s: Bad visible string: ch=%#x", pszErrorTag, ch);
1316 }
1317 break;
1318
1319 case ASN1_TAG_GENERAL_STRING:
1320 return VERR_ASN1_STRING_TYPE_NOT_IMPLEMENTED;
1321
1322 case ASN1_TAG_UNIVERSAL_STRING:
1323 if (!(cch & 3))
1324 {
1325 uint8_t const *pb = (uint8_t const *)pch;
1326 cchUtf8 = 0;
1327 while (cch > 0)
1328 {
1329 RTUNICP uc = RT_MAKE_U32_FROM_U8(pb[3], pb[2], pb[1], pb[0]); /* big endian */
1330 if (!RTUniCpIsValid(uc))
1331 return RTErrInfoSetF(pErrInfo, VERR_ASN1_INVALID_UNIVERSAL_STRING_ENCODING,
1332 "%s: Bad universal string: uc=%#x", pszErrorTag, uc);
1333 cchUtf8 += RTUniCpCalcUtf8Len(uc);
1334
1335 /* next */
1336 pb += 4;
1337 cch -= 4;
1338 }
1339 break;
1340 }
1341 return RTErrInfoSetF(pErrInfo, VERR_ASN1_INVALID_UNIVERSAL_STRING_ENCODING,
1342 "%s: Bad universal string: size not a multiple of 4: cch=%#x", pszErrorTag, cch);
1343
1344 case ASN1_TAG_BMP_STRING:
1345 if (!(cch & 1))
1346 {
1347 uint8_t const *pb = (uint8_t const *)pch;
1348 cchUtf8 = 0;
1349 while (cch > 0)
1350 {
1351 RTUNICP uc = RT_MAKE_U32_FROM_U8(pb[1], pb[0], 0, 0); /* big endian */
1352 if (!RTUniCpIsValid(uc))
1353 return RTErrInfoSetF(pErrInfo, VERR_ASN1_INVALID_BMP_STRING_ENCODING,
1354 "%s: Bad BMP string: uc=%#x", pszErrorTag, uc);
1355 cchUtf8 += RTUniCpCalcUtf8Len(uc);
1356
1357 /* next */
1358 pb += 2;
1359 cch -= 2;
1360 }
1361 break;
1362 }
1363 return RTErrInfoSetF(pErrInfo, VERR_ASN1_INVALID_BMP_STRING_ENCODING,
1364 "%s: Bad BMP string: odd number of bytes cch=%#x", pszErrorTag, cch);
1365
1366 default:
1367 AssertMsgFailedReturn(("uTag=%#x\n", uTag), VERR_INTERNAL_ERROR_3);
1368 }
1369
1370 if (pcchUtf8)
1371 *pcchUtf8 = cchUtf8;
1372 return VINF_SUCCESS;
1373}
1374
1375
1376RTDECL(int) RTAsn1String_CompareValues(PCRTASN1STRING pLeft, PCRTASN1STRING pRight)
1377{
1378 return RTAsn1String_CompareEx(pLeft, pRight, false /*fTypeToo*/);
1379}
1380
1381
1382RTDECL(int) RTAsn1String_CompareEx(PCRTASN1STRING pLeft, PCRTASN1STRING pRight, bool fTypeToo)
1383{
1384 Assert(pLeft && (!RTAsn1String_IsPresent(pLeft) || pLeft->Asn1Core.pOps == &g_RTAsn1String_Vtable));
1385 Assert(pRight && (!RTAsn1String_IsPresent(pRight) || pRight->Asn1Core.pOps == &g_RTAsn1String_Vtable));
1386
1387 int iDiff;
1388 if (RTAsn1String_IsPresent(pLeft))
1389 {
1390 if (RTAsn1String_IsPresent(pRight))
1391 {
1392 if (!fTypeToo || RTASN1CORE_GET_TAG(&pLeft->Asn1Core) == RTASN1CORE_GET_TAG(&pRight->Asn1Core))
1393 iDiff = RTAsn1Core_CompareEx(&pLeft->Asn1Core, &pRight->Asn1Core, true /*fIgnoreTagAndClass*/);
1394 else
1395 iDiff = RTASN1CORE_GET_TAG(&pLeft->Asn1Core) < RTASN1CORE_GET_TAG(&pRight->Asn1Core) ? -1 : 1;
1396 }
1397 else
1398 iDiff = 1;
1399 }
1400 else
1401 iDiff = 0 - RTAsn1String_IsPresent(pRight);
1402 return iDiff;
1403}
1404
1405
1406RTDECL(int) RTAsn1String_CompareWithString(PCRTASN1STRING pThis, const char *pszString, size_t cchString)
1407{
1408 Assert(pThis && (!RTAsn1String_IsPresent(pThis) || pThis->Asn1Core.pOps == &g_RTAsn1String_Vtable));
1409 AssertPtr(pszString);
1410
1411 int iDiff;
1412 if (RTAsn1String_IsPresent(pThis))
1413 {
1414 if (cchString == RTSTR_MAX)
1415 cchString = strlen(pszString);
1416
1417 /*
1418 * If there is a UTF-8 conversion available already, use it.
1419 */
1420 if (pThis->pszUtf8)
1421 {
1422 iDiff = strncmp(pThis->pszUtf8, pszString, cchString);
1423 if (!iDiff && pThis->cchUtf8 != cchString)
1424 iDiff = pThis->cchUtf8 < cchString ? -1 : 1;
1425 }
1426 else
1427 {
1428 /*
1429 * Some types are UTF-8 compatible, so try do the compare without
1430 * RTAsn1String_QueryUtf8.
1431 */
1432 uint32_t cch = pThis->Asn1Core.cb;
1433 const char *pch = pThis->Asn1Core.uData.pch;
1434 switch (RTASN1CORE_GET_TAG(&pThis->Asn1Core))
1435 {
1436 case ASN1_TAG_UTF8_STRING:
1437 case ASN1_TAG_NUMERIC_STRING:
1438 case ASN1_TAG_IA5_STRING:
1439 case ASN1_TAG_PRINTABLE_STRING:
1440 iDiff = strncmp(pch, pszString, RT_MIN(cch, cchString));
1441 if (iDiff && cch != cchString)
1442 iDiff = cch < cchString ? - 1 : 1;
1443 break;
1444
1445 /** @todo Implement comparing ASN1_TAG_BMP_STRING, ASN1_TAG_UNIVERSAL_STRING and
1446 * ASN1_TAG_T61_STRING with UTF-8 strings without conversion. */
1447
1448 default:
1449 {
1450 int rc = RTAsn1String_QueryUtf8(pThis, NULL, NULL);
1451 if (RT_SUCCESS(rc))
1452 {
1453 iDiff = strncmp(pThis->pszUtf8, pszString, cchString);
1454 if (!iDiff && pThis->cchUtf8 != cchString)
1455 iDiff = pThis->cchUtf8 < cchString ? -1 : 1;
1456 }
1457 else
1458 iDiff = -1;
1459 break;
1460 }
1461 }
1462 }
1463
1464 /* Reduce the strcmp return value. */
1465 if (iDiff != 0)
1466 iDiff = iDiff < 0 ? -1 : 1;
1467 }
1468 else
1469 iDiff = -1;
1470 return iDiff;
1471}
1472
1473
1474RTDECL(int) RTAsn1String_QueryUtf8(PCRTASN1STRING pThis, const char **ppsz, size_t *pcch)
1475{
1476 Assert(pThis->Asn1Core.pOps == &g_RTAsn1String_Vtable);
1477
1478 char *psz = (char *)pThis->pszUtf8;
1479 size_t cch = pThis->cchUtf8;
1480 if (!psz)
1481 {
1482
1483 /*
1484 * Convert the first time around. Start by validating the encoding and
1485 * calculating the length.
1486 */
1487 int rc = rtAsn1String_CheckSanity(pThis, NULL, NULL, &cch);
1488 if (RT_SUCCESS(rc))
1489 {
1490 PRTASN1STRING pThisNC = (PRTASN1STRING)pThis;
1491 rc = RTAsn1MemAllocZ(&pThisNC->Allocation, (void **)&psz, cch + 1);
1492 if (RT_SUCCESS(rc))
1493 {
1494 /*
1495 * Got memory, now do the actual convertion to UTF-8 / copying.
1496 */
1497 switch (RTASN1CORE_GET_TAG(&pThis->Asn1Core))
1498 {
1499 case ASN1_TAG_UTF8_STRING:
1500 case ASN1_TAG_NUMERIC_STRING:
1501 case ASN1_TAG_PRINTABLE_STRING:
1502 case ASN1_TAG_IA5_STRING:
1503 case ASN1_TAG_VISIBLE_STRING:
1504 Assert(cch == pThis->Asn1Core.cb);
1505 memcpy(psz, pThis->Asn1Core.uData.pch, cch);
1506 psz[cch] = '\0';
1507 break;
1508
1509 case ASN1_TAG_T61_STRING:
1510 switch (rtAsn1String_IsTeletexLatin1(pThis->Asn1Core.uData.pch, pThis->Asn1Core.cb))
1511 {
1512 default:
1513 rc = rtIso2022RecodeAsUtf8(ASN1_TAG_T61_STRING, pThis->Asn1Core.uData.pch, pThis->Asn1Core.cb,
1514 psz, cch + 1);
1515 break;
1516 case RTASN1TELETEXVARIANT_UNDECIDED:
1517 case RTASN1TELETEXVARIANT_LATIN1:
1518 case RTASN1TELETEXVARIANT_WIN_1252:
1519 rc = rtWin1252RecodeAsUtf8(pThis->Asn1Core.uData.pch, pThis->Asn1Core.cb, psz, cch + 1);
1520 break;
1521 }
1522 AssertReturnStmt(RT_SUCCESS(rc), RTAsn1MemFree(&pThisNC->Allocation, psz), VERR_INTERNAL_ERROR_3);
1523 break;
1524
1525 /* case ASN1_TAG_VIDEOTEX_STRING: */
1526 /* case ASN1_TAG_GRAPHIC_STRING: */
1527 /* case ASN1_TAG_GENERAL_STRING: */
1528
1529 case ASN1_TAG_UNIVERSAL_STRING:
1530 {
1531 char *pszDst = psz;
1532 size_t cchSrc = pThis->Asn1Core.cb;
1533 uint8_t const *pbSrc = pThis->Asn1Core.uData.pu8;
1534 while (cchSrc > 0)
1535 {
1536 RTUNICP uc = RT_MAKE_U32_FROM_U8(pbSrc[3], pbSrc[2], pbSrc[1], pbSrc[0]); /* big endian */
1537 AssertReturnStmt(RTUniCpIsValid(uc), RTAsn1MemFree(&pThisNC->Allocation, psz), VERR_INTERNAL_ERROR_2);
1538 pszDst = RTStrPutCp(pszDst, uc);
1539
1540 /* next */
1541 pbSrc += 4;
1542 cchSrc -= 4;
1543 }
1544 Assert((size_t)(pszDst - psz) == cch);
1545 break;
1546 }
1547
1548 case ASN1_TAG_BMP_STRING:
1549 {
1550 char *pszDst = psz;
1551 size_t cchSrc = pThis->Asn1Core.cb;
1552 uint8_t const *pbSrc = pThis->Asn1Core.uData.pu8;
1553 while (cchSrc > 0)
1554 {
1555 RTUNICP uc = RT_MAKE_U32_FROM_U8(pbSrc[1], pbSrc[0], 0, 0); /* big endian */
1556 AssertReturnStmt(RTUniCpIsValid(uc), RTAsn1MemFree(&pThisNC->Allocation, psz), VERR_INTERNAL_ERROR_2);
1557 pszDst = RTStrPutCp(pszDst, uc);
1558
1559 /* next */
1560 pbSrc += 2;
1561 cchSrc -= 2;
1562 }
1563 Assert((size_t)(pszDst - psz) == cch);
1564 break;
1565 }
1566
1567 default:
1568 RTAsn1MemFree(&pThisNC->Allocation, psz);
1569 AssertMsgFailedReturn(("uTag=%#x\n", RTASN1CORE_GET_TAG(&pThis->Asn1Core)), VERR_INTERNAL_ERROR_3);
1570 }
1571
1572 /*
1573 * Successfully produced UTF-8. Save it in the object.
1574 */
1575 pThisNC->pszUtf8 = psz;
1576 pThisNC->cchUtf8 = (uint32_t)cch;
1577 }
1578 else
1579 return rc;
1580 }
1581 else
1582 return rc;
1583 }
1584
1585 /*
1586 * Success.
1587 */
1588 if (ppsz)
1589 *ppsz = psz;
1590 if (pcch)
1591 *pcch = cch;
1592 return VINF_SUCCESS;
1593}
1594
1595
1596
1597RTDECL(int) RTAsn1String_QueryUtf8Len(PCRTASN1STRING pThis, size_t *pcch)
1598{
1599 Assert(pThis->Asn1Core.pOps == &g_RTAsn1String_Vtable);
1600
1601 size_t cch = pThis->cchUtf8;
1602 if (!cch && !pThis->pszUtf8)
1603 {
1604 int rc = rtAsn1String_CheckSanity(pThis, NULL, NULL, &cch);
1605 if (RT_FAILURE(rc))
1606 return rc;
1607 }
1608
1609 *pcch = cch;
1610 return VINF_SUCCESS;
1611}
1612
1613
1614
1615
1616RTDECL(int) RTAsn1String_InitEx(PRTASN1STRING pThis, uint32_t uTag, void const *pvValue, size_t cbValue,
1617 PCRTASN1ALLOCATORVTABLE pAllocator)
1618{
1619 RT_ZERO(*pThis);
1620 AssertMsgReturn(uTag < RT_ELEMENTS(g_acbStringTags) && g_acbStringTags[uTag] > 0, ("uTag=%#x\n", uTag),
1621 VERR_INVALID_PARAMETER);
1622
1623 RTAsn1MemInitAllocation(&pThis->Allocation, pAllocator);
1624 RTAsn1Core_InitEx(&pThis->Asn1Core,
1625 uTag,
1626 ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_PRIMITIVE,
1627 &g_RTAsn1String_Vtable,
1628 RTASN1CORE_F_PRESENT | RTASN1CORE_F_PRIMITE_TAG_STRUCT);
1629
1630 if (cbValue > 0)
1631 {
1632 int rc = RTAsn1ContentDup(&pThis->Asn1Core, pvValue, cbValue, pAllocator);
1633 if (RT_FAILURE(rc))
1634 return rc;
1635 }
1636
1637 return VINF_SUCCESS;
1638}
1639
1640
1641RTDECL(int) RTAsn1String_InitWithValue(PRTASN1STRING pThis, const char *pszUtf8Value, PCRTASN1ALLOCATORVTABLE pAllocator)
1642{
1643 Assert(RTStrValidateEncoding(pszUtf8Value));
1644 return RTAsn1String_InitEx(pThis, ASN1_TAG_UTF8_STRING, pszUtf8Value, strlen(pszUtf8Value), pAllocator);
1645}
1646
1647
1648RTDECL(int) RTAsn1String_RecodeAsUtf8(PRTASN1STRING pThis, PCRTASN1ALLOCATORVTABLE pAllocator)
1649{
1650 /*
1651 * Query the UTF-8 string. Do this even if it's already an
1652 * ASN1_TAG_UTF8_STRING object as it makes sure we've got a valid UTF-8
1653 * string upon successful return.
1654 */
1655 int rc = RTAsn1String_QueryUtf8(pThis, NULL, NULL);
1656 if (RT_SUCCESS(rc))
1657 {
1658 if (RTASN1CORE_GET_TAG(&pThis->Asn1Core) != ASN1_TAG_UTF8_STRING)
1659 {
1660 /*
1661 * Resize the content, copy the UTF-8 bytes in there, and change
1662 * the tag.
1663 */
1664 rc = RTAsn1ContentReallocZ(&pThis->Asn1Core, pThis->cchUtf8, pAllocator);
1665 if (RT_SUCCESS(rc))
1666 {
1667 memcpy((void *)pThis->Asn1Core.uData.pv, pThis->pszUtf8, pThis->cchUtf8);
1668 rc = RTAsn1Core_ChangeTag(&pThis->Asn1Core, ASN1_TAG_UTF8_STRING);
1669 }
1670 }
1671 }
1672 return rc;
1673}
1674
1675
1676
1677/*
1678 * ASN.1 STRING - Standard Methods.
1679 */
1680
1681RT_DECL_DATA_CONST(RTASN1COREVTABLE const) g_RTAsn1String_Vtable =
1682{
1683 "RTAsn1String",
1684 sizeof(RTASN1STRING),
1685 UINT8_MAX,
1686 ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_PRIMITIVE,
1687 0,
1688 (PFNRTASN1COREVTDTOR)RTAsn1String_Delete,
1689 NULL,
1690 (PFNRTASN1COREVTCLONE)RTAsn1String_Clone,
1691 (PFNRTASN1COREVTCOMPARE)RTAsn1String_Compare,
1692 (PFNRTASN1COREVTCHECKSANITY)RTAsn1String_CheckSanity,
1693 NULL,
1694 NULL
1695};
1696
1697
1698RTDECL(int) RTAsn1String_Init(PRTASN1STRING pThis, PCRTASN1ALLOCATORVTABLE pAllocator)
1699{
1700 return RTAsn1String_InitEx(pThis, ASN1_TAG_UTF8_STRING, NULL /*pvValue*/, 0 /*cbValue*/, pAllocator);
1701}
1702
1703
1704RTDECL(int) RTAsn1String_Clone(PRTASN1STRING pThis, PCRTASN1STRING pSrc, PCRTASN1ALLOCATORVTABLE pAllocator)
1705{
1706 AssertPtr(pSrc); AssertPtr(pThis); AssertPtr(pAllocator);
1707 RT_ZERO(*pThis);
1708 if (RTAsn1String_IsPresent(pSrc))
1709 {
1710 AssertReturn(pSrc->Asn1Core.pOps == &g_RTAsn1String_Vtable, VERR_INTERNAL_ERROR_3);
1711 int rc = RTAsn1Core_CloneContent(&pThis->Asn1Core, &pSrc->Asn1Core, pAllocator);
1712 if (RT_SUCCESS(rc))
1713 {
1714 /* Don't copy the UTF-8 representation, decode it when queried. */
1715 RTAsn1MemInitAllocation(&pThis->Allocation, pAllocator);
1716 return VINF_SUCCESS;
1717 }
1718 }
1719 return VINF_SUCCESS;
1720}
1721
1722
1723RTDECL(void) RTAsn1String_Delete(PRTASN1STRING pThis)
1724{
1725 if ( pThis
1726 && RTAsn1String_IsPresent(pThis))
1727 {
1728 Assert(pThis->Asn1Core.pOps == &g_RTAsn1String_Vtable);
1729
1730 if (pThis->Allocation.cbAllocated)
1731 RTAsn1MemFree(&pThis->Allocation, (char *)pThis->pszUtf8);
1732 RTAsn1ContentFree(&pThis->Asn1Core);
1733 RT_ZERO(*pThis);
1734 }
1735}
1736
1737
1738RTDECL(int) RTAsn1String_Enum(PRTASN1STRING pThis, PFNRTASN1ENUMCALLBACK pfnCallback, uint32_t uDepth, void *pvUser)
1739{
1740 RT_NOREF_PV(pThis); RT_NOREF_PV(pfnCallback); RT_NOREF_PV(uDepth); RT_NOREF_PV(pvUser);
1741 Assert(pThis && (!RTAsn1String_IsPresent(pThis) || pThis->Asn1Core.pOps == &g_RTAsn1String_Vtable));
1742
1743 /* No children to enumerate. */
1744 return VINF_SUCCESS;
1745}
1746
1747
1748RTDECL(int) RTAsn1String_Compare(PCRTASN1STRING pLeft, PCRTASN1STRING pRight)
1749{
1750 /* Compare tag and binary value. */
1751 return RTAsn1String_CompareEx(pLeft, pRight, true /*fTypeToo*/);
1752}
1753
1754
1755RTDECL(int) RTAsn1String_CheckSanity(PCRTASN1STRING pThis, uint32_t fFlags, PRTERRINFO pErrInfo, const char *pszErrorTag)
1756{
1757 RT_NOREF_PV(fFlags);
1758 if (RT_UNLIKELY(!RTAsn1String_IsPresent(pThis)))
1759 return RTErrInfoSetF(pErrInfo, VERR_ASN1_NOT_PRESENT, "%s: Missing (STRING).", pszErrorTag);
1760 return rtAsn1String_CheckSanity(pThis, pErrInfo, pszErrorTag, NULL /*pcchUtf8*/);
1761}
1762
1763
1764/*
1765 * Generate code for the tag specific methods.
1766 * Note! This is very similar to what we're doing in asn1-ut-time.cpp.
1767 */
1768#define RTASN1STRING_IMPL(a_uTag, a_szTag, a_Api) \
1769 \
1770 RTDECL(int) RT_CONCAT(a_Api,_Init)(PRTASN1STRING pThis, PCRTASN1ALLOCATORVTABLE pAllocator) \
1771 { \
1772 return RTAsn1String_InitEx(pThis, a_uTag, NULL /*pvValue*/, 0 /*cbValue*/, pAllocator); \
1773 } \
1774 \
1775 RTDECL(int) RT_CONCAT(a_Api,_Clone)(PRTASN1STRING pThis, PCRTASN1STRING pSrc, PCRTASN1ALLOCATORVTABLE pAllocator) \
1776 { \
1777 AssertReturn(RTASN1CORE_GET_TAG(&pSrc->Asn1Core) == a_uTag || !RTAsn1String_IsPresent(pSrc), \
1778 VERR_ASN1_STRING_TAG_MISMATCH); \
1779 return RTAsn1String_Clone(pThis, pSrc, pAllocator); \
1780 } \
1781 \
1782 RTDECL(void) RT_CONCAT(a_Api,_Delete)(PRTASN1STRING pThis) \
1783 { \
1784 Assert( !pThis \
1785 || !RTAsn1String_IsPresent(pThis) \
1786 || ( pThis->Asn1Core.pOps == &g_RTAsn1String_Vtable \
1787 && RTASN1CORE_GET_TAG(&pThis->Asn1Core) == a_uTag) ); \
1788 RTAsn1String_Delete(pThis); \
1789 } \
1790 \
1791 RTDECL(int) RT_CONCAT(a_Api,_Enum)(PRTASN1STRING pThis, PFNRTASN1ENUMCALLBACK pfnCallback, uint32_t uDepth, void *pvUser) \
1792 { \
1793 RT_NOREF_PV(pThis); RT_NOREF_PV(pfnCallback); RT_NOREF_PV(uDepth); RT_NOREF_PV(pvUser); \
1794 Assert( pThis \
1795 && ( !RTAsn1String_IsPresent(pThis) \
1796 || ( pThis->Asn1Core.pOps == &g_RTAsn1String_Vtable \
1797 && RTASN1CORE_GET_TAG(&pThis->Asn1Core) == a_uTag) ) ); \
1798 /* No children to enumerate. */ \
1799 return VINF_SUCCESS; \
1800 } \
1801 \
1802 RTDECL(int) RT_CONCAT(a_Api,_Compare)(PCRTASN1STRING pLeft, PCRTASN1STRING pRight) \
1803 { \
1804 int iDiff = RTAsn1String_CompareEx(pLeft, pRight, true /*fTypeToo*/); \
1805 if (!iDiff && RTASN1CORE_GET_TAG(&pLeft->Asn1Core) != a_uTag && RTAsn1String_IsPresent(pLeft)) \
1806 iDiff = RTASN1CORE_GET_TAG(&pLeft->Asn1Core) < a_uTag ? -1 : 1; \
1807 return iDiff; \
1808 } \
1809 \
1810 RTDECL(int) RT_CONCAT(a_Api,_CheckSanity)(PCRTASN1STRING pThis, uint32_t fFlags, \
1811 PRTERRINFO pErrInfo, const char *pszErrorTag) \
1812 { \
1813 if (RTASN1CORE_GET_TAG(&pThis->Asn1Core) != a_uTag && RTAsn1String_IsPresent(pThis)) \
1814 return RTErrInfoSetF(pErrInfo, VERR_ASN1_STRING_TAG_MISMATCH, "%s: uTag=%#x, expected %#x (%s)", \
1815 pszErrorTag, RTASN1CORE_GET_TAG(&pThis->Asn1Core), a_uTag, a_szTag); \
1816 return RTAsn1String_CheckSanity(pThis, fFlags, pErrInfo, pszErrorTag); \
1817 }
1818
1819#include "asn1-ut-string-template2.h"
1820
1821
1822/*
1823 * Generate code for the associated collection types.
1824 */
1825#define RTASN1TMPL_TEMPLATE_FILE "../common/asn1/asn1-ut-string-template.h"
1826#include <iprt/asn1-generator-internal-header.h>
1827#include <iprt/asn1-generator-core.h>
1828#include <iprt/asn1-generator-init.h>
1829#include <iprt/asn1-generator-sanity.h>
1830
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