VirtualBox

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

Last change on this file since 62448 was 62448, checked in by vboxsync, 8 years ago

IPRT: More MSC level 4 warning fixes.

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