VirtualBox

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

Last change on this file since 51770 was 51770, checked in by vboxsync, 10 years ago

Merged in iprt++ dev branch.

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