• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 **********************************************************************
3 *   Copyright (C) 2000-2015, International Business Machines
4 *   Corporation and others.  All Rights Reserved.
5 **********************************************************************
6 *   file name:  ucnv_lmb.cpp
7 *   encoding:   US-ASCII
8 *   tab size:   4 (not used)
9 *   indentation:4
10 *
11 *   created on: 2000feb09
12 *   created by: Brendan Murray
13 *   extensively hacked up by: Jim Snyder-Grant
14 *
15 * Modification History:
16 *
17 *   Date        Name             Description
18 *
19 *   06/20/2000  helena           OS/400 port changes; mostly typecast.
20 *   06/27/2000  Jim Snyder-Grant Deal with partial characters and small buffers.
21 *                                Add comments to document LMBCS format and implementation
22 *                                restructured order & breakdown of functions
23 *   06/28/2000  helena           Major rewrite for the callback API changes.
24 */
25 
26 #include "unicode/utypes.h"
27 
28 #if !UCONFIG_NO_CONVERSION && !UCONFIG_NO_LEGACY_CONVERSION && !UCONFIG_ONLY_HTML_CONVERSION
29 
30 #include "unicode/ucnv_err.h"
31 #include "unicode/ucnv.h"
32 #include "unicode/uset.h"
33 #include "cmemory.h"
34 #include "cstring.h"
35 #include "uassert.h"
36 #include "ucnv_imp.h"
37 #include "ucnv_bld.h"
38 #include "ucnv_cnv.h"
39 
40 #ifdef EBCDIC_RTL
41     #include "ascii_a.h"
42 #endif
43 
44 /*
45   LMBCS
46 
47   (Lotus Multi-Byte Character Set)
48 
49   LMBCS was invented in the late 1980's and is primarily used in Lotus Notes
50   databases and in Lotus 1-2-3 files. Programmers who work with the APIs
51   into these products will sometimes need to deal with strings in this format.
52 
53   The code in this file provides an implementation for an ICU converter of
54   LMBCS to and from Unicode.
55 
56   Since the LMBCS character set is only sparsely documented in existing
57   printed or online material, we have added  extensive annotation to this
58   file to serve as a guide to understanding LMBCS.
59 
60   LMBCS was originally designed with these four sometimes-competing design goals:
61 
62   -Provide encodings for the characters in 12 existing national standards
63    (plus a few other characters)
64   -Minimal memory footprint
65   -Maximal speed of conversion into the existing national character sets
66   -No need to track a changing state as you interpret a string.
67 
68 
69   All of the national character sets LMBCS was trying to encode are 'ANSI'
70   based, in that the bytes from 0x20 - 0x7F are almost exactly the
71   same common Latin unaccented characters and symbols in all character sets.
72 
73   So, in order to help meet the speed & memory design goals, the common ANSI
74   bytes from 0x20-0x7F are represented by the same single-byte values in LMBCS.
75 
76   The general LMBCS code unit is from 1-3 bytes. We can describe the 3 bytes as
77   follows:
78 
79   [G] D1 [D2]
80 
81   That is, a sometimes-optional 'group' byte, followed by 1 and sometimes 2
82   data bytes. The maximum size of a LMBCS chjaracter is 3 bytes:
83 */
84 #define ULMBCS_CHARSIZE_MAX      3
85 /*
86   The single-byte values from 0x20 to 0x7F are examples of single D1 bytes.
87   We often have to figure out if byte values are below or above this, so we
88   use the ANSI nomenclature 'C0' and 'C1' to refer to the range of control
89   characters just above & below the common lower-ANSI  range */
90 #define ULMBCS_C0END           0x1F
91 #define ULMBCS_C1START         0x80
92 /*
93   Since LMBCS is always dealing in byte units. we create a local type here for
94   dealing with these units of LMBCS code units:
95 
96 */
97 typedef uint8_t ulmbcs_byte_t;
98 
99 /*
100    Most of the values less than 0x20 are reserved in LMBCS to announce
101    which national  character standard is being used for the 'D' bytes.
102    In the comments we show the common name and the IBM character-set ID
103    for these character-set announcers:
104 */
105 
106 #define ULMBCS_GRP_L1         0x01   /* Latin-1    :ibm-850  */
107 #define ULMBCS_GRP_GR         0x02   /* Greek      :ibm-851  */
108 #define ULMBCS_GRP_HE         0x03   /* Hebrew     :ibm-1255 */
109 #define ULMBCS_GRP_AR         0x04   /* Arabic     :ibm-1256 */
110 #define ULMBCS_GRP_RU         0x05   /* Cyrillic   :ibm-1251 */
111 #define ULMBCS_GRP_L2         0x06   /* Latin-2    :ibm-852  */
112 #define ULMBCS_GRP_TR         0x08   /* Turkish    :ibm-1254 */
113 #define ULMBCS_GRP_TH         0x0B   /* Thai       :ibm-874  */
114 #define ULMBCS_GRP_JA         0x10   /* Japanese   :ibm-943  */
115 #define ULMBCS_GRP_KO         0x11   /* Korean     :ibm-1261 */
116 #define ULMBCS_GRP_TW         0x12   /* Chinese SC :ibm-950  */
117 #define ULMBCS_GRP_CN         0x13   /* Chinese TC :ibm-1386 */
118 
119 /*
120    So, the beginning of understanding LMBCS is that IF the first byte of a LMBCS
121    character is one of those 12 values, you can interpret the remaining bytes of
122    that character as coming from one of those character sets. Since the lower
123    ANSI bytes already are represented in single bytes, using one of the character
124    set announcers is used to announce a character that starts with a byte of
125    0x80 or greater.
126 
127    The character sets are  arranged so that the single byte sets all appear
128    before the multi-byte character sets. When we need to tell whether a
129    group byte is for a single byte char set or not we use this define: */
130 
131 #define ULMBCS_DOUBLEOPTGROUP_START  0x10
132 
133 /*
134 However, to fully understand LMBCS, you must also understand a series of
135 exceptions & optimizations made in service of the design goals.
136 
137 First, those of you who are character set mavens may have noticed that
138 the 'double-byte' character sets are actually multi-byte character sets
139 that can have 1 or two bytes, even in the upper-ascii range. To force
140 each group byte to introduce a fixed-width encoding (to make it faster to
141 count characters), we use a convention of doubling up on the group byte
142 to introduce any single-byte character > 0x80 in an otherwise double-byte
143 character set. So, for example, the LMBCS sequence x10 x10 xAE is the
144 same as '0xAE' in the Japanese code page 943.
145 
146 Next, you will notice that the list of group bytes has some gaps.
147 These are used in various ways.
148 
149 We reserve a few special single byte values for common control
150 characters. These are in the same place as their ANSI eqivalents for speed.
151 */
152 
153 #define ULMBCS_HT    0x09   /* Fixed control char - Horizontal Tab */
154 #define ULMBCS_LF    0x0A   /* Fixed control char - Line Feed */
155 #define ULMBCS_CR    0x0D   /* Fixed control char - Carriage Return */
156 
157 /* Then, 1-2-3 reserved a special single-byte character to put at the
158 beginning of internal 'system' range names: */
159 
160 #define ULMBCS_123SYSTEMRANGE  0x19
161 
162 /* Then we needed a place to put all the other ansi control characters
163 that must be moved to different values because LMBCS reserves those
164 values for other purposes. To represent the control characters, we start
165 with a first byte of 0xF & add the control chaarcter value as the
166 second byte */
167 #define ULMBCS_GRP_CTRL       0x0F
168 
169 /* For the C0 controls (less than 0x20), we add 0x20 to preserve the
170 useful doctrine that any byte less than 0x20 in a LMBCS char must be
171 the first byte of a character:*/
172 #define ULMBCS_CTRLOFFSET      0x20
173 
174 /*
175 Where to put the characters that aren't part of any of the 12 national
176 character sets? The first thing that was done, in the earlier years of
177 LMBCS, was to use up the spaces of the form
178 
179   [G] D1,
180 
181  where  'G' was one of the single-byte character groups, and
182  D1 was less than 0x80. These sequences are gathered together
183  into a Lotus-invented doublebyte character set to represent a
184  lot of stray values. Internally, in this implementation, we track this
185  as group '0', as a place to tuck this exceptions list.*/
186 
187 #define ULMBCS_GRP_EXCEPT     0x00
188 /*
189  Finally, as the durability and usefulness of UNICODE became clear,
190  LOTUS added a new group 0x14 to hold Unicode values not otherwise
191  represented in LMBCS: */
192 #define ULMBCS_GRP_UNICODE    0x14
193 /* The two bytes appearing after a 0x14 are intrepreted as UFT-16 BE
194 (Big-Endian) characters. The exception comes when the UTF16
195 representation would have a zero as the second byte. In that case,
196 'F6' is used in its place, and the bytes are swapped. (This prevents
197 LMBCS from encoding any Unicode values of the form U+F6xx, but that's OK:
198 0xF6xx is in the middle of the Private Use Area.)*/
199 #define ULMBCS_UNICOMPATZERO   0xF6
200 
201 /* It is also useful in our code to have a constant for the size of
202 a LMBCS char that holds a literal Unicode value */
203 #define ULMBCS_UNICODE_SIZE      3
204 
205 /*
206 To squish the LMBCS representations down even further, and to make
207 translations even faster,sometimes the optimization group byte can be dropped
208 from a LMBCS character. This is decided on a process-by-process basis. The
209 group byte that is dropped is called the 'optimization group'.
210 
211 For Notes, the optimzation group is always 0x1.*/
212 #define ULMBCS_DEFAULTOPTGROUP 0x1
213 /* For 1-2-3 files, the optimzation group is stored in the header of the 1-2-3
214 file.
215 
216  In any case, when using ICU, you either pass in the
217 optimization group as part of the name of the converter (LMBCS-1, LMBCS-2,
218 etc.). Using plain 'LMBCS' as the name of the converter will give you
219 LMBCS-1.
220 
221 
222 *** Implementation strategy ***
223 
224 
225 Because of the extensive use of other character sets, the LMBCS converter
226 keeps a mapping between optimization groups and IBM character sets, so that
227 ICU converters can be created and used as needed. */
228 
229 /* As you can see, even though any byte below 0x20 could be an optimization
230 byte, only those at 0x13 or below can map to an actual converter. To limit
231 some loops and searches, we define a value for that last group converter:*/
232 
233 #define ULMBCS_GRP_LAST       0x13   /* last LMBCS group that has a converter */
234 
235 static const char * const OptGroupByteToCPName[ULMBCS_GRP_LAST + 1] = {
236    /* 0x0000 */ "lmb-excp", /* internal home for the LOTUS exceptions list */
237    /* 0x0001 */ "ibm-850",
238    /* 0x0002 */ "ibm-851",
239    /* 0x0003 */ "windows-1255",
240    /* 0x0004 */ "windows-1256",
241    /* 0x0005 */ "windows-1251",
242    /* 0x0006 */ "ibm-852",
243    /* 0x0007 */ NULL,      /* Unused */
244    /* 0x0008 */ "windows-1254",
245    /* 0x0009 */ NULL,      /* Control char HT */
246    /* 0x000A */ NULL,      /* Control char LF */
247    /* 0x000B */ "windows-874",
248    /* 0x000C */ NULL,      /* Unused */
249    /* 0x000D */ NULL,      /* Control char CR */
250    /* 0x000E */ NULL,      /* Unused */
251    /* 0x000F */ NULL,      /* Control chars: 0x0F20 + C0/C1 character: algorithmic */
252    /* 0x0010 */ "windows-932",
253    /* 0x0011 */ "windows-949",
254    /* 0x0012 */ "windows-950",
255    /* 0x0013 */ "windows-936"
256 
257    /* The rest are null, including the 0x0014 Unicode compatibility region
258    and 0x0019, the 1-2-3 system range control char */
259 };
260 
261 
262 /* That's approximately all the data that's needed for translating
263   LMBCS to Unicode.
264 
265 
266 However, to translate Unicode to LMBCS, we need some more support.
267 
268 That's because there are often more than one possible mappings from a Unicode
269 code point back into LMBCS. The first thing we do is look up into a table
270 to figure out if there are more than one possible mappings. This table,
271 arranged by Unicode values (including ranges) either lists which group
272 to use, or says that it could go into one or more of the SBCS sets, or
273 into one or more of the DBCS sets.  (If the character exists in both DBCS &
274 SBCS, the table will place it in the SBCS sets, to make the LMBCS code point
275 length as small as possible. Here's the two special markers we use to indicate
276 ambiguous mappings: */
277 
278 #define ULMBCS_AMBIGUOUS_SBCS   0x80   /* could fit in more than one
279                                           LMBCS sbcs native encoding
280                                           (example: most accented latin) */
281 #define ULMBCS_AMBIGUOUS_MBCS   0x81   /* could fit in more than one
282                                           LMBCS mbcs native encoding
283                                           (example: Unihan) */
284 #define ULMBCS_AMBIGUOUS_ALL   0x82
285 /* And here's a simple way to see if a group falls in an appropriate range */
286 #define ULMBCS_AMBIGUOUS_MATCH(agroup, xgroup) \
287                   ((((agroup) == ULMBCS_AMBIGUOUS_SBCS) && \
288                   (xgroup) < ULMBCS_DOUBLEOPTGROUP_START) || \
289                   (((agroup) == ULMBCS_AMBIGUOUS_MBCS) && \
290                   (xgroup) >= ULMBCS_DOUBLEOPTGROUP_START)) || \
291                   ((agroup) == ULMBCS_AMBIGUOUS_ALL)
292 
293 
294 /* The table & some code to use it: */
295 
296 
297 static const struct _UniLMBCSGrpMap
298 {
299    const UChar uniStartRange;
300    const UChar uniEndRange;
301    const ulmbcs_byte_t  GrpType;
302 } UniLMBCSGrpMap[]
303 =
304 {
305 
306     {0x0001, 0x001F,  ULMBCS_GRP_CTRL},
307     {0x0080, 0x009F,  ULMBCS_GRP_CTRL},
308     {0x00A0, 0x00A6,  ULMBCS_AMBIGUOUS_SBCS},
309     {0x00A7, 0x00A8,  ULMBCS_AMBIGUOUS_ALL},
310     {0x00A9, 0x00AF,  ULMBCS_AMBIGUOUS_SBCS},
311     {0x00B0, 0x00B1,  ULMBCS_AMBIGUOUS_ALL},
312     {0x00B2, 0x00B3,  ULMBCS_AMBIGUOUS_SBCS},
313     {0x00B4, 0x00B4,  ULMBCS_AMBIGUOUS_ALL},
314     {0x00B5, 0x00B5,  ULMBCS_AMBIGUOUS_SBCS},
315     {0x00B6, 0x00B6,  ULMBCS_AMBIGUOUS_ALL},
316     {0x00B7, 0x00D6,  ULMBCS_AMBIGUOUS_SBCS},
317     {0x00D7, 0x00D7,  ULMBCS_AMBIGUOUS_ALL},
318     {0x00D8, 0x00F6,  ULMBCS_AMBIGUOUS_SBCS},
319     {0x00F7, 0x00F7,  ULMBCS_AMBIGUOUS_ALL},
320     {0x00F8, 0x01CD,  ULMBCS_AMBIGUOUS_SBCS},
321     {0x01CE, 0x01CE,  ULMBCS_GRP_TW },
322     {0x01CF, 0x02B9,  ULMBCS_AMBIGUOUS_SBCS},
323     {0x02BA, 0x02BA,  ULMBCS_GRP_CN},
324     {0x02BC, 0x02C8,  ULMBCS_AMBIGUOUS_SBCS},
325     {0x02C9, 0x02D0,  ULMBCS_AMBIGUOUS_MBCS},
326     {0x02D8, 0x02DD,  ULMBCS_AMBIGUOUS_SBCS},
327     {0x0384, 0x0390,  ULMBCS_AMBIGUOUS_SBCS},
328     {0x0391, 0x03A9,  ULMBCS_AMBIGUOUS_ALL},
329     {0x03AA, 0x03B0,  ULMBCS_AMBIGUOUS_SBCS},
330     {0x03B1, 0x03C9,  ULMBCS_AMBIGUOUS_ALL},
331     {0x03CA, 0x03CE,  ULMBCS_AMBIGUOUS_SBCS},
332     {0x0400, 0x0400,  ULMBCS_GRP_RU},
333     {0x0401, 0x0401,  ULMBCS_AMBIGUOUS_ALL},
334     {0x0402, 0x040F,  ULMBCS_GRP_RU},
335     {0x0410, 0x0431,  ULMBCS_AMBIGUOUS_ALL},
336     {0x0432, 0x044E,  ULMBCS_GRP_RU},
337     {0x044F, 0x044F,  ULMBCS_AMBIGUOUS_ALL},
338     {0x0450, 0x0491,  ULMBCS_GRP_RU},
339     {0x05B0, 0x05F2,  ULMBCS_GRP_HE},
340     {0x060C, 0x06AF,  ULMBCS_GRP_AR},
341     {0x0E01, 0x0E5B,  ULMBCS_GRP_TH},
342     {0x200C, 0x200F,  ULMBCS_AMBIGUOUS_SBCS},
343     {0x2010, 0x2010,  ULMBCS_AMBIGUOUS_MBCS},
344     {0x2013, 0x2014,  ULMBCS_AMBIGUOUS_SBCS},
345     {0x2015, 0x2015,  ULMBCS_AMBIGUOUS_MBCS},
346     {0x2016, 0x2016,  ULMBCS_AMBIGUOUS_MBCS},
347     {0x2017, 0x2017,  ULMBCS_AMBIGUOUS_SBCS},
348     {0x2018, 0x2019,  ULMBCS_AMBIGUOUS_ALL},
349     {0x201A, 0x201B,  ULMBCS_AMBIGUOUS_SBCS},
350     {0x201C, 0x201D,  ULMBCS_AMBIGUOUS_ALL},
351     {0x201E, 0x201F,  ULMBCS_AMBIGUOUS_SBCS},
352     {0x2020, 0x2021,  ULMBCS_AMBIGUOUS_ALL},
353     {0x2022, 0x2024,  ULMBCS_AMBIGUOUS_SBCS},
354     {0x2025, 0x2025,  ULMBCS_AMBIGUOUS_MBCS},
355     {0x2026, 0x2026,  ULMBCS_AMBIGUOUS_ALL},
356     {0x2027, 0x2027,  ULMBCS_GRP_TW},
357     {0x2030, 0x2030,  ULMBCS_AMBIGUOUS_ALL},
358     {0x2031, 0x2031,  ULMBCS_AMBIGUOUS_SBCS},
359     {0x2032, 0x2033,  ULMBCS_AMBIGUOUS_MBCS},
360     {0x2035, 0x2035,  ULMBCS_AMBIGUOUS_MBCS},
361     {0x2039, 0x203A,  ULMBCS_AMBIGUOUS_SBCS},
362     {0x203B, 0x203B,  ULMBCS_AMBIGUOUS_MBCS},
363     {0x203C, 0x203C,  ULMBCS_GRP_EXCEPT},
364     {0x2074, 0x2074,  ULMBCS_GRP_KO},
365     {0x207F, 0x207F,  ULMBCS_GRP_EXCEPT},
366     {0x2081, 0x2084,  ULMBCS_GRP_KO},
367     {0x20A4, 0x20AC,  ULMBCS_AMBIGUOUS_SBCS},
368     {0x2103, 0x2109,  ULMBCS_AMBIGUOUS_MBCS},
369     {0x2111, 0x2120,  ULMBCS_AMBIGUOUS_SBCS},
370     /*zhujin: upgrade, for regressiont test, spr HKIA4YHTSU*/
371     {0x2121, 0x2121,  ULMBCS_AMBIGUOUS_MBCS},
372     {0x2122, 0x2126,  ULMBCS_AMBIGUOUS_SBCS},
373     {0x212B, 0x212B,  ULMBCS_AMBIGUOUS_MBCS},
374     {0x2135, 0x2135,  ULMBCS_AMBIGUOUS_SBCS},
375     {0x2153, 0x2154,  ULMBCS_GRP_KO},
376     {0x215B, 0x215E,  ULMBCS_GRP_EXCEPT},
377     {0x2160, 0x2179,  ULMBCS_AMBIGUOUS_MBCS},
378     {0x2190, 0x2193,  ULMBCS_AMBIGUOUS_ALL},
379     {0x2194, 0x2195,  ULMBCS_GRP_EXCEPT},
380     {0x2196, 0x2199,  ULMBCS_AMBIGUOUS_MBCS},
381     {0x21A8, 0x21A8,  ULMBCS_GRP_EXCEPT},
382     {0x21B8, 0x21B9,  ULMBCS_GRP_CN},
383     {0x21D0, 0x21D1,  ULMBCS_GRP_EXCEPT},
384     {0x21D2, 0x21D2,  ULMBCS_AMBIGUOUS_MBCS},
385     {0x21D3, 0x21D3,  ULMBCS_GRP_EXCEPT},
386     {0x21D4, 0x21D4,  ULMBCS_AMBIGUOUS_MBCS},
387     {0x21D5, 0x21D5,  ULMBCS_GRP_EXCEPT},
388     {0x21E7, 0x21E7,  ULMBCS_GRP_CN},
389     {0x2200, 0x2200,  ULMBCS_AMBIGUOUS_MBCS},
390     {0x2201, 0x2201,  ULMBCS_GRP_EXCEPT},
391     {0x2202, 0x2202,  ULMBCS_AMBIGUOUS_MBCS},
392     {0x2203, 0x2203,  ULMBCS_AMBIGUOUS_MBCS},
393     {0x2204, 0x2206,  ULMBCS_GRP_EXCEPT},
394     {0x2207, 0x2208,  ULMBCS_AMBIGUOUS_MBCS},
395     {0x2209, 0x220A,  ULMBCS_GRP_EXCEPT},
396     {0x220B, 0x220B,  ULMBCS_AMBIGUOUS_MBCS},
397     {0x220F, 0x2215,  ULMBCS_AMBIGUOUS_MBCS},
398     {0x2219, 0x2219,  ULMBCS_GRP_EXCEPT},
399     {0x221A, 0x221A,  ULMBCS_AMBIGUOUS_MBCS},
400     {0x221B, 0x221C,  ULMBCS_GRP_EXCEPT},
401     {0x221D, 0x221E,  ULMBCS_AMBIGUOUS_MBCS},
402     {0x221F, 0x221F,  ULMBCS_GRP_EXCEPT},
403     {0x2220, 0x2220,  ULMBCS_AMBIGUOUS_MBCS},
404     {0x2223, 0x222A,  ULMBCS_AMBIGUOUS_MBCS},
405     {0x222B, 0x223D,  ULMBCS_AMBIGUOUS_MBCS},
406     {0x2245, 0x2248,  ULMBCS_GRP_EXCEPT},
407     {0x224C, 0x224C,  ULMBCS_GRP_TW},
408     {0x2252, 0x2252,  ULMBCS_AMBIGUOUS_MBCS},
409     {0x2260, 0x2261,  ULMBCS_AMBIGUOUS_MBCS},
410     {0x2262, 0x2265,  ULMBCS_GRP_EXCEPT},
411     {0x2266, 0x226F,  ULMBCS_AMBIGUOUS_MBCS},
412     {0x2282, 0x2283,  ULMBCS_AMBIGUOUS_MBCS},
413     {0x2284, 0x2285,  ULMBCS_GRP_EXCEPT},
414     {0x2286, 0x2287,  ULMBCS_AMBIGUOUS_MBCS},
415     {0x2288, 0x2297,  ULMBCS_GRP_EXCEPT},
416     {0x2299, 0x22BF,  ULMBCS_AMBIGUOUS_MBCS},
417     {0x22C0, 0x22C0,  ULMBCS_GRP_EXCEPT},
418     {0x2310, 0x2310,  ULMBCS_GRP_EXCEPT},
419     {0x2312, 0x2312,  ULMBCS_AMBIGUOUS_MBCS},
420     {0x2318, 0x2321,  ULMBCS_GRP_EXCEPT},
421     {0x2318, 0x2321,  ULMBCS_GRP_CN},
422     {0x2460, 0x24E9,  ULMBCS_AMBIGUOUS_MBCS},
423     {0x2500, 0x2500,  ULMBCS_AMBIGUOUS_SBCS},
424     {0x2501, 0x2501,  ULMBCS_AMBIGUOUS_MBCS},
425     {0x2502, 0x2502,  ULMBCS_AMBIGUOUS_ALL},
426     {0x2503, 0x2503,  ULMBCS_AMBIGUOUS_MBCS},
427     {0x2504, 0x2505,  ULMBCS_GRP_TW},
428     {0x2506, 0x2665,  ULMBCS_AMBIGUOUS_ALL},
429     {0x2666, 0x2666,  ULMBCS_GRP_EXCEPT},
430     {0x2667, 0x2669,  ULMBCS_AMBIGUOUS_SBCS},
431     {0x266A, 0x266A,  ULMBCS_AMBIGUOUS_ALL},
432     {0x266B, 0x266C,  ULMBCS_AMBIGUOUS_SBCS},
433     {0x266D, 0x266D,  ULMBCS_AMBIGUOUS_MBCS},
434     {0x266E, 0x266E,  ULMBCS_AMBIGUOUS_SBCS},
435     {0x266F, 0x266F,  ULMBCS_GRP_JA},
436     {0x2670, 0x2E7F,  ULMBCS_AMBIGUOUS_SBCS},
437     {0x2E80, 0xF861,  ULMBCS_AMBIGUOUS_MBCS},
438     {0xF862, 0xF8FF,  ULMBCS_GRP_EXCEPT},
439     {0xF900, 0xFA2D,  ULMBCS_AMBIGUOUS_MBCS},
440     {0xFB00, 0xFEFF,  ULMBCS_AMBIGUOUS_SBCS},
441     {0xFF01, 0xFFEE,  ULMBCS_AMBIGUOUS_MBCS},
442     {0xFFFF, 0xFFFF,  ULMBCS_GRP_UNICODE}
443 };
444 
445 static ulmbcs_byte_t
FindLMBCSUniRange(UChar uniChar)446 FindLMBCSUniRange(UChar uniChar)
447 {
448    const struct _UniLMBCSGrpMap * pTable = UniLMBCSGrpMap;
449 
450    while (uniChar > pTable->uniEndRange)
451    {
452       pTable++;
453    }
454 
455    if (uniChar >= pTable->uniStartRange)
456    {
457       return pTable->GrpType;
458    }
459    return ULMBCS_GRP_UNICODE;
460 }
461 
462 /*
463 We also ask the creator of a converter to send in a preferred locale
464 that we can use in resolving ambiguous mappings. They send the locale
465 in as a string, and we map it, if possible, to one of the
466 LMBCS groups. We use this table, and the associated code, to
467 do the lookup: */
468 
469 /**************************************************
470   This table maps locale ID's to LMBCS opt groups.
471   The default return is group 0x01. Note that for
472   performance reasons, the table is sorted in
473   increasing alphabetic order, with the notable
474   exception of zhTW. This is to force the check
475   for Traditonal Chinese before dropping back to
476   Simplified.
477 
478   Note too that the Latin-1 groups have been
479   commented out because it's the default, and
480   this shortens the table, allowing a serial
481   search to go quickly.
482  *************************************************/
483 
484 static const struct _LocaleLMBCSGrpMap
485 {
486    const char    *LocaleID;
487    const ulmbcs_byte_t OptGroup;
488 } LocaleLMBCSGrpMap[] =
489 {
490     {"ar", ULMBCS_GRP_AR},
491     {"be", ULMBCS_GRP_RU},
492     {"bg", ULMBCS_GRP_L2},
493    /* {"ca", ULMBCS_GRP_L1}, */
494     {"cs", ULMBCS_GRP_L2},
495    /* {"da", ULMBCS_GRP_L1}, */
496    /* {"de", ULMBCS_GRP_L1}, */
497     {"el", ULMBCS_GRP_GR},
498    /* {"en", ULMBCS_GRP_L1}, */
499    /* {"es", ULMBCS_GRP_L1}, */
500    /* {"et", ULMBCS_GRP_L1}, */
501    /* {"fi", ULMBCS_GRP_L1}, */
502    /* {"fr", ULMBCS_GRP_L1}, */
503     {"he", ULMBCS_GRP_HE},
504     {"hu", ULMBCS_GRP_L2},
505    /* {"is", ULMBCS_GRP_L1}, */
506    /* {"it", ULMBCS_GRP_L1}, */
507     {"iw", ULMBCS_GRP_HE},
508     {"ja", ULMBCS_GRP_JA},
509     {"ko", ULMBCS_GRP_KO},
510    /* {"lt", ULMBCS_GRP_L1}, */
511    /* {"lv", ULMBCS_GRP_L1}, */
512     {"mk", ULMBCS_GRP_RU},
513    /* {"nl", ULMBCS_GRP_L1}, */
514    /* {"no", ULMBCS_GRP_L1}, */
515     {"pl", ULMBCS_GRP_L2},
516    /* {"pt", ULMBCS_GRP_L1}, */
517     {"ro", ULMBCS_GRP_L2},
518     {"ru", ULMBCS_GRP_RU},
519     {"sh", ULMBCS_GRP_L2},
520     {"sk", ULMBCS_GRP_L2},
521     {"sl", ULMBCS_GRP_L2},
522     {"sq", ULMBCS_GRP_L2},
523     {"sr", ULMBCS_GRP_RU},
524    /* {"sv", ULMBCS_GRP_L1}, */
525     {"th", ULMBCS_GRP_TH},
526     {"tr", ULMBCS_GRP_TR},
527     {"uk", ULMBCS_GRP_RU},
528    /* {"vi", ULMBCS_GRP_L1}, */
529     {"zhTW", ULMBCS_GRP_TW},
530     {"zh", ULMBCS_GRP_CN},
531     {NULL, ULMBCS_GRP_L1}
532 };
533 
534 
535 static ulmbcs_byte_t
FindLMBCSLocale(const char * LocaleID)536 FindLMBCSLocale(const char *LocaleID)
537 {
538    const struct _LocaleLMBCSGrpMap *pTable = LocaleLMBCSGrpMap;
539 
540    if ((!LocaleID) || (!*LocaleID))
541    {
542       return 0;
543    }
544 
545    while (pTable->LocaleID)
546    {
547       if (*pTable->LocaleID == *LocaleID) /* Check only first char for speed */
548       {
549          /* First char matches - check whole name, for entry-length */
550          if (uprv_strncmp(pTable->LocaleID, LocaleID, strlen(pTable->LocaleID)) == 0)
551             return pTable->OptGroup;
552       }
553       else
554       if (*pTable->LocaleID > *LocaleID) /* Sorted alphabetically - exit */
555          break;
556       pTable++;
557    }
558    return ULMBCS_GRP_L1;
559 }
560 
561 
562 /*
563   Before we get to the main body of code, here's how we hook up to the rest
564   of ICU. ICU converters are required to define a structure that includes
565   some function pointers, and some common data, in the style of a C++
566   vtable. There is also room in there for converter-specific data. LMBCS
567   uses that converter-specific data to keep track of the 12 subconverters
568   we use, the optimization group, and the group (if any) that matches the
569   locale. We have one structure instantiated for each of the 12 possible
570   optimization groups. To avoid typos & to avoid boring the reader, we
571   put the declarations of these structures and functions into macros. To see
572   the definitions of these structures, see unicode\ucnv_bld.h
573 */
574 
575 typedef struct
576   {
577     UConverterSharedData *OptGrpConverter[ULMBCS_GRP_LAST+1];    /* Converter per Opt. grp. */
578     uint8_t    OptGroup;                  /* default Opt. grp. for this LMBCS session */
579     uint8_t    localeConverterIndex;      /* reasonable locale match for index */
580   }
581 UConverterDataLMBCS;
582 
583 static void _LMBCSClose(UConverter * _this);
584 
585 #define DECLARE_LMBCS_DATA(n) \
586 static const UConverterImpl _LMBCSImpl##n={\
587     UCNV_LMBCS_##n,\
588     NULL,NULL,\
589     _LMBCSOpen##n,\
590     _LMBCSClose,\
591     NULL,\
592     _LMBCSToUnicodeWithOffsets,\
593     _LMBCSToUnicodeWithOffsets,\
594     _LMBCSFromUnicode,\
595     _LMBCSFromUnicode,\
596     NULL,\
597     NULL,\
598     NULL,\
599     NULL,\
600     _LMBCSSafeClone,\
601     ucnv_getCompleteUnicodeSet\
602 };\
603 static const UConverterStaticData _LMBCSStaticData##n={\
604   sizeof(UConverterStaticData),\
605  "LMBCS-"  #n,\
606     0, UCNV_IBM, UCNV_LMBCS_##n, 1, 3,\
607     { 0x3f, 0, 0, 0 },1,FALSE,FALSE,0,0,{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} \
608 };\
609 const UConverterSharedData _LMBCSData##n= \
610         UCNV_IMMUTABLE_SHARED_DATA_INITIALIZER(&_LMBCSStaticData##n, &_LMBCSImpl##n);
611 
612  /* The only function we needed to duplicate 12 times was the 'open'
613 function, which will do basically the same thing except set a  different
614 optimization group. So, we put the common stuff into a worker function,
615 and set up another macro to stamp out the 12 open functions:*/
616 #define DEFINE_LMBCS_OPEN(n) \
617 static void \
618    _LMBCSOpen##n(UConverter* _this, UConverterLoadArgs* pArgs, UErrorCode* err) \
619 { _LMBCSOpenWorker(_this, pArgs, err, n); }
620 
621 
622 
623 /* Here's the open worker & the common close function */
624 static void
_LMBCSOpenWorker(UConverter * _this,UConverterLoadArgs * pArgs,UErrorCode * err,ulmbcs_byte_t OptGroup)625 _LMBCSOpenWorker(UConverter*  _this,
626                  UConverterLoadArgs *pArgs,
627                  UErrorCode*  err,
628                  ulmbcs_byte_t OptGroup)
629 {
630     UConverterDataLMBCS * extraInfo = _this->extraInfo =
631         (UConverterDataLMBCS*)uprv_malloc (sizeof (UConverterDataLMBCS));
632     if(extraInfo != NULL)
633     {
634         UConverterNamePieces stackPieces;
635         UConverterLoadArgs stackArgs={ (int32_t)sizeof(UConverterLoadArgs) };
636         ulmbcs_byte_t i;
637 
638         uprv_memset(extraInfo, 0, sizeof(UConverterDataLMBCS));
639 
640         stackArgs.onlyTestIsLoadable = pArgs->onlyTestIsLoadable;
641 
642         for (i=0; i <= ULMBCS_GRP_LAST && U_SUCCESS(*err); i++)
643         {
644             if(OptGroupByteToCPName[i] != NULL) {
645                 extraInfo->OptGrpConverter[i] = ucnv_loadSharedData(OptGroupByteToCPName[i], &stackPieces, &stackArgs, err);
646             }
647         }
648 
649         if(U_FAILURE(*err) || pArgs->onlyTestIsLoadable) {
650             _LMBCSClose(_this);
651             return;
652         }
653         extraInfo->OptGroup = OptGroup;
654         extraInfo->localeConverterIndex = FindLMBCSLocale(pArgs->locale);
655     }
656     else
657     {
658         *err = U_MEMORY_ALLOCATION_ERROR;
659     }
660 }
661 
662 static void
_LMBCSClose(UConverter * _this)663 _LMBCSClose(UConverter *   _this)
664 {
665     if (_this->extraInfo != NULL)
666     {
667         ulmbcs_byte_t Ix;
668         UConverterDataLMBCS * extraInfo = (UConverterDataLMBCS *) _this->extraInfo;
669 
670         for (Ix=0; Ix <= ULMBCS_GRP_LAST; Ix++)
671         {
672            if (extraInfo->OptGrpConverter[Ix] != NULL)
673               ucnv_unloadSharedDataIfReady(extraInfo->OptGrpConverter[Ix]);
674         }
675         if (!_this->isExtraLocal) {
676             uprv_free (_this->extraInfo);
677             _this->extraInfo = NULL;
678         }
679     }
680 }
681 
682 typedef struct LMBCSClone {
683     UConverter cnv;
684     UConverterDataLMBCS lmbcs;
685 } LMBCSClone;
686 
687 static UConverter *
_LMBCSSafeClone(const UConverter * cnv,void * stackBuffer,int32_t * pBufferSize,UErrorCode * status)688 _LMBCSSafeClone(const UConverter *cnv,
689                 void *stackBuffer,
690                 int32_t *pBufferSize,
691                 UErrorCode *status) {
692     LMBCSClone *newLMBCS;
693     UConverterDataLMBCS *extraInfo;
694     int32_t i;
695 
696     if(*pBufferSize<=0) {
697         *pBufferSize=(int32_t)sizeof(LMBCSClone);
698         return NULL;
699     }
700 
701     extraInfo=(UConverterDataLMBCS *)cnv->extraInfo;
702     newLMBCS=(LMBCSClone *)stackBuffer;
703 
704     /* ucnv.c/ucnv_safeClone() copied the main UConverter already */
705 
706     uprv_memcpy(&newLMBCS->lmbcs, extraInfo, sizeof(UConverterDataLMBCS));
707 
708     /* share the subconverters */
709     for(i = 0; i <= ULMBCS_GRP_LAST; ++i) {
710         if(extraInfo->OptGrpConverter[i] != NULL) {
711             ucnv_incrementRefCount(extraInfo->OptGrpConverter[i]);
712         }
713     }
714 
715     newLMBCS->cnv.extraInfo = &newLMBCS->lmbcs;
716     newLMBCS->cnv.isExtraLocal = TRUE;
717     return &newLMBCS->cnv;
718 }
719 
720 /*
721  * There used to be a _LMBCSGetUnicodeSet() function here (up to svn revision 20117)
722  * which added all code points except for U+F6xx
723  * because those cannot be represented in the Unicode group.
724  * However, it turns out that windows-950 has roundtrips for all of U+F6xx
725  * which means that LMBCS can convert all Unicode code points after all.
726  * We now simply use ucnv_getCompleteUnicodeSet().
727  *
728  * This may need to be looked at again as Lotus uses _LMBCSGetUnicodeSet(). (091216)
729  */
730 
731 /*
732    Here's the basic helper function that we use when converting from
733    Unicode to LMBCS, and we suspect that a Unicode character will fit into
734    one of the 12 groups. The return value is the number of bytes written
735    starting at pStartLMBCS (if any).
736 */
737 
738 static size_t
LMBCSConversionWorker(UConverterDataLMBCS * extraInfo,ulmbcs_byte_t group,ulmbcs_byte_t * pStartLMBCS,UChar * pUniChar,ulmbcs_byte_t * lastConverterIndex,UBool * groups_tried)739 LMBCSConversionWorker (
740    UConverterDataLMBCS * extraInfo,    /* subconverters, opt & locale groups */
741    ulmbcs_byte_t group,                /* The group to try */
742    ulmbcs_byte_t  * pStartLMBCS,              /* where to put the results */
743    UChar * pUniChar,                   /* The input unicode character */
744    ulmbcs_byte_t * lastConverterIndex, /* output: track last successful group used */
745    UBool * groups_tried                /* output: track any unsuccessful groups */
746 )
747 {
748    ulmbcs_byte_t  * pLMBCS = pStartLMBCS;
749    UConverterSharedData * xcnv = extraInfo->OptGrpConverter[group];
750 
751    int bytesConverted;
752    uint32_t value;
753    ulmbcs_byte_t firstByte;
754 
755    U_ASSERT(xcnv);
756    U_ASSERT(group<ULMBCS_GRP_UNICODE);
757 
758    bytesConverted = ucnv_MBCSFromUChar32(xcnv, *pUniChar, &value, FALSE);
759 
760    /* get the first result byte */
761    if(bytesConverted > 0) {
762       firstByte = (ulmbcs_byte_t)(value >> ((bytesConverted - 1) * 8));
763    } else {
764       /* most common failure mode is an unassigned character */
765       groups_tried[group] = TRUE;
766       return 0;
767    }
768 
769    *lastConverterIndex = group;
770 
771    /* All initial byte values in lower ascii range should have been caught by now,
772       except with the exception group.
773     */
774    U_ASSERT((firstByte <= ULMBCS_C0END) || (firstByte >= ULMBCS_C1START) || (group == ULMBCS_GRP_EXCEPT));
775 
776    /* use converted data: first write 0, 1 or two group bytes */
777    if (group != ULMBCS_GRP_EXCEPT && extraInfo->OptGroup != group)
778    {
779       *pLMBCS++ = group;
780       if (bytesConverted == 1 && group >= ULMBCS_DOUBLEOPTGROUP_START)
781       {
782          *pLMBCS++ = group;
783       }
784    }
785 
786   /* don't emit control chars */
787    if ( bytesConverted == 1 && firstByte < 0x20 )
788       return 0;
789 
790 
791    /* then move over the converted data */
792    switch(bytesConverted)
793    {
794    case 4:
795       *pLMBCS++ = (ulmbcs_byte_t)(value >> 24);
796    case 3: /*fall through*/
797       *pLMBCS++ = (ulmbcs_byte_t)(value >> 16);
798    case 2: /*fall through*/
799       *pLMBCS++ = (ulmbcs_byte_t)(value >> 8);
800    case 1: /*fall through*/
801       *pLMBCS++ = (ulmbcs_byte_t)value;
802    default:
803       /* will never occur */
804       break;
805    }
806 
807    return (pLMBCS - pStartLMBCS);
808 }
809 
810 
811 /* This is a much simpler version of above, when we
812 know we are writing LMBCS using the Unicode group
813 */
814 static size_t
LMBCSConvertUni(ulmbcs_byte_t * pLMBCS,UChar uniChar)815 LMBCSConvertUni(ulmbcs_byte_t * pLMBCS, UChar uniChar)
816 {
817      /* encode into LMBCS Unicode range */
818    uint8_t LowCh =   (uint8_t)(uniChar & 0x00FF);
819    uint8_t HighCh  = (uint8_t)(uniChar >> 8);
820 
821    *pLMBCS++ = ULMBCS_GRP_UNICODE;
822 
823    if (LowCh == 0)
824    {
825       *pLMBCS++ = ULMBCS_UNICOMPATZERO;
826       *pLMBCS++ = HighCh;
827    }
828    else
829    {
830       *pLMBCS++ = HighCh;
831       *pLMBCS++ = LowCh;
832    }
833    return ULMBCS_UNICODE_SIZE;
834 }
835 
836 
837 
838 /* The main Unicode to LMBCS conversion function */
839 static void
_LMBCSFromUnicode(UConverterFromUnicodeArgs * args,UErrorCode * err)840 _LMBCSFromUnicode(UConverterFromUnicodeArgs*     args,
841                   UErrorCode*     err)
842 {
843    ulmbcs_byte_t lastConverterIndex = 0;
844    UChar uniChar;
845    ulmbcs_byte_t  LMBCS[ULMBCS_CHARSIZE_MAX];
846    ulmbcs_byte_t  * pLMBCS;
847    int32_t bytes_written;
848    UBool groups_tried[ULMBCS_GRP_LAST+1];
849    UConverterDataLMBCS * extraInfo = (UConverterDataLMBCS *) args->converter->extraInfo;
850    int sourceIndex = 0;
851 
852    /* Basic strategy: attempt to fill in local LMBCS 1-char buffer.(LMBCS)
853       If that succeeds, see if it will all fit into the target & copy it over
854       if it does.
855 
856       We try conversions in the following order:
857 
858       1. Single-byte ascii & special fixed control chars (&null)
859       2. Look up group in table & try that (could be
860             A) Unicode group
861             B) control group,
862             C) national encoding,
863                or ambiguous SBCS or MBCS group (on to step 4...)
864 
865       3. If its ambiguous, try this order:
866          A) The optimization group
867          B) The locale group
868          C) The last group that succeeded with this string.
869          D) every other group that's relevent (single or double)
870          E) If its single-byte ambiguous, try the exceptions group
871 
872       4. And as a grand fallback: Unicode
873    */
874 
875     /*Fix for SPR#DJOE66JFN3 (Lotus)*/
876     ulmbcs_byte_t OldConverterIndex = 0;
877 
878    while (args->source < args->sourceLimit && !U_FAILURE(*err))
879    {
880       /*Fix for SPR#DJOE66JFN3 (Lotus)*/
881       OldConverterIndex = extraInfo->localeConverterIndex;
882 
883       if (args->target >= args->targetLimit)
884       {
885          *err = U_BUFFER_OVERFLOW_ERROR;
886          break;
887       }
888       uniChar = *(args->source);
889       bytes_written = 0;
890       pLMBCS = LMBCS;
891 
892       /* check cases in rough order of how common they are, for speed */
893 
894       /* single byte matches: strategy 1 */
895       /*Fix for SPR#DJOE66JFN3 (Lotus)*/
896       if((uniChar>=0x80) && (uniChar<=0xff)
897       /*Fix for SPR#JUYA6XAERU and TSAO7GL5NK (Lotus)*/ &&(uniChar!=0xB1) &&(uniChar!=0xD7) &&(uniChar!=0xF7)
898         &&(uniChar!=0xB0) &&(uniChar!=0xB4) &&(uniChar!=0xB6) &&(uniChar!=0xA7) &&(uniChar!=0xA8))
899       {
900             extraInfo->localeConverterIndex = ULMBCS_GRP_L1;
901       }
902       if (((uniChar > ULMBCS_C0END) && (uniChar < ULMBCS_C1START)) ||
903           uniChar == 0 || uniChar == ULMBCS_HT || uniChar == ULMBCS_CR ||
904           uniChar == ULMBCS_LF || uniChar == ULMBCS_123SYSTEMRANGE
905           )
906       {
907          *pLMBCS++ = (ulmbcs_byte_t ) uniChar;
908          bytes_written = 1;
909       }
910 
911 
912       if (!bytes_written)
913       {
914          /* Check by UNICODE range (Strategy 2) */
915          ulmbcs_byte_t group = FindLMBCSUniRange(uniChar);
916 
917          if (group == ULMBCS_GRP_UNICODE)  /* (Strategy 2A) */
918          {
919             pLMBCS += LMBCSConvertUni(pLMBCS,uniChar);
920 
921             bytes_written = (int32_t)(pLMBCS - LMBCS);
922          }
923          else if (group == ULMBCS_GRP_CTRL)  /* (Strategy 2B) */
924          {
925             /* Handle control characters here */
926             if (uniChar <= ULMBCS_C0END)
927             {
928                *pLMBCS++ = ULMBCS_GRP_CTRL;
929                *pLMBCS++ = (ulmbcs_byte_t)(ULMBCS_CTRLOFFSET + uniChar);
930             }
931             else if (uniChar >= ULMBCS_C1START && uniChar <= ULMBCS_C1START + ULMBCS_CTRLOFFSET)
932             {
933                *pLMBCS++ = ULMBCS_GRP_CTRL;
934                *pLMBCS++ = (ulmbcs_byte_t ) (uniChar & 0x00FF);
935             }
936             bytes_written = (int32_t)(pLMBCS - LMBCS);
937          }
938          else if (group < ULMBCS_GRP_UNICODE)  /* (Strategy 2C) */
939          {
940             /* a specific converter has been identified - use it */
941             bytes_written = (int32_t)LMBCSConversionWorker (
942                               extraInfo, group, pLMBCS, &uniChar,
943                               &lastConverterIndex, groups_tried);
944          }
945          if (!bytes_written)    /* the ambiguous group cases  (Strategy 3) */
946          {
947             uprv_memset(groups_tried, 0, sizeof(groups_tried));
948 
949             /* check for non-default optimization group (Strategy 3A )*/
950             if ((extraInfo->OptGroup != 1) && (ULMBCS_AMBIGUOUS_MATCH(group, extraInfo->OptGroup)))
951             {
952                 /*zhujin: upgrade, merge #39299 here (Lotus) */
953                 /*To make R5 compatible translation, look for exceptional group first for non-DBCS*/
954 
955                 if(extraInfo->localeConverterIndex < ULMBCS_DOUBLEOPTGROUP_START)
956                 {
957                   bytes_written = LMBCSConversionWorker (extraInfo,
958                      ULMBCS_GRP_L1, pLMBCS, &uniChar,
959                      &lastConverterIndex, groups_tried);
960 
961                   if(!bytes_written)
962                   {
963                      bytes_written = LMBCSConversionWorker (extraInfo,
964                          ULMBCS_GRP_EXCEPT, pLMBCS, &uniChar,
965                          &lastConverterIndex, groups_tried);
966                   }
967                   if(!bytes_written)
968                   {
969                       bytes_written = LMBCSConversionWorker (extraInfo,
970                           extraInfo->localeConverterIndex, pLMBCS, &uniChar,
971                           &lastConverterIndex, groups_tried);
972                   }
973                 }
974                 else
975                 {
976                      bytes_written = LMBCSConversionWorker (extraInfo,
977                          extraInfo->localeConverterIndex, pLMBCS, &uniChar,
978                          &lastConverterIndex, groups_tried);
979                 }
980             }
981             /* check for locale optimization group (Strategy 3B) */
982             if (!bytes_written && (extraInfo->localeConverterIndex) && (ULMBCS_AMBIGUOUS_MATCH(group, extraInfo->localeConverterIndex)))
983             {
984                 bytes_written = (int32_t)LMBCSConversionWorker (extraInfo,
985                         extraInfo->localeConverterIndex, pLMBCS, &uniChar, &lastConverterIndex, groups_tried);
986             }
987             /* check for last optimization group used for this string (Strategy 3C) */
988             if (!bytes_written && (lastConverterIndex) && (ULMBCS_AMBIGUOUS_MATCH(group, lastConverterIndex)))
989             {
990                 bytes_written = (int32_t)LMBCSConversionWorker (extraInfo,
991                         lastConverterIndex, pLMBCS, &uniChar, &lastConverterIndex, groups_tried);
992             }
993             if (!bytes_written)
994             {
995                /* just check every possible matching converter (Strategy 3D) */
996                ulmbcs_byte_t grp_start;
997                ulmbcs_byte_t grp_end;
998                ulmbcs_byte_t grp_ix;
999                grp_start = (ulmbcs_byte_t)((group == ULMBCS_AMBIGUOUS_MBCS)
1000                         ? ULMBCS_DOUBLEOPTGROUP_START
1001                         :  ULMBCS_GRP_L1);
1002                grp_end = (ulmbcs_byte_t)((group == ULMBCS_AMBIGUOUS_MBCS)
1003                         ? ULMBCS_GRP_LAST
1004                         :  ULMBCS_GRP_TH);
1005                if(group == ULMBCS_AMBIGUOUS_ALL)
1006                {
1007                    grp_start = ULMBCS_GRP_L1;
1008                    grp_end = ULMBCS_GRP_LAST;
1009                }
1010                for (grp_ix = grp_start;
1011                    grp_ix <= grp_end && !bytes_written;
1012                     grp_ix++)
1013                {
1014                   if (extraInfo->OptGrpConverter [grp_ix] && !groups_tried [grp_ix])
1015                   {
1016                      bytes_written = (int32_t)LMBCSConversionWorker (extraInfo,
1017                        grp_ix, pLMBCS, &uniChar,
1018                        &lastConverterIndex, groups_tried);
1019                   }
1020                }
1021                 /* a final conversion fallback to the exceptions group if its likely
1022                      to be single byte  (Strategy 3E) */
1023                if (!bytes_written && grp_start == ULMBCS_GRP_L1)
1024                {
1025                   bytes_written = (int32_t)LMBCSConversionWorker (extraInfo,
1026                      ULMBCS_GRP_EXCEPT, pLMBCS, &uniChar,
1027                      &lastConverterIndex, groups_tried);
1028                }
1029             }
1030             /* all of our other strategies failed. Fallback to Unicode. (Strategy 4)*/
1031             if (!bytes_written)
1032             {
1033 
1034                pLMBCS += LMBCSConvertUni(pLMBCS, uniChar);
1035                bytes_written = (int32_t)(pLMBCS - LMBCS);
1036             }
1037          }
1038       }
1039 
1040       /* we have a translation. increment source and write as much as posible to target */
1041       args->source++;
1042       pLMBCS = LMBCS;
1043       while (args->target < args->targetLimit && bytes_written--)
1044       {
1045          *(args->target)++ = *pLMBCS++;
1046          if (args->offsets)
1047          {
1048             *(args->offsets)++ = sourceIndex;
1049          }
1050       }
1051       sourceIndex++;
1052       if (bytes_written > 0)
1053       {
1054          /* write any bytes that didn't fit in target to the error buffer,
1055             common code will move this to target if we get called back with
1056             enough target room
1057          */
1058          uint8_t * pErrorBuffer = args->converter->charErrorBuffer;
1059          *err = U_BUFFER_OVERFLOW_ERROR;
1060          args->converter->charErrorBufferLength = (int8_t)bytes_written;
1061          while (bytes_written--)
1062          {
1063             *pErrorBuffer++ = *pLMBCS++;
1064          }
1065       }
1066       /*Fix for SPR#DJOE66JFN3 (Lotus)*/
1067       extraInfo->localeConverterIndex = OldConverterIndex;
1068    }
1069 }
1070 
1071 
1072 /* Now, the Unicode from LMBCS section */
1073 
1074 
1075 /* A function to call when we are looking at the Unicode group byte in LMBCS */
1076 static UChar
GetUniFromLMBCSUni(char const ** ppLMBCSin)1077 GetUniFromLMBCSUni(char const ** ppLMBCSin)  /* Called with LMBCS-style Unicode byte stream */
1078 {
1079    uint8_t  HighCh = *(*ppLMBCSin)++;  /* Big-endian Unicode in LMBCS compatibility group*/
1080    uint8_t  LowCh  = *(*ppLMBCSin)++;
1081 
1082    if (HighCh == ULMBCS_UNICOMPATZERO )
1083    {
1084       HighCh = LowCh;
1085       LowCh = 0; /* zero-byte in LSB special character */
1086    }
1087    return (UChar)((HighCh << 8) | LowCh);
1088 }
1089 
1090 
1091 
1092 /* CHECK_SOURCE_LIMIT: Helper macro to verify that there are at least'index'
1093    bytes left in source up to  sourceLimit.Errors appropriately if not.
1094    If we reach the limit, then update the source pointer to there to consume
1095    all input as required by ICU converter semantics.
1096 */
1097 
1098 #define CHECK_SOURCE_LIMIT(index) \
1099      if (args->source+index > args->sourceLimit){\
1100          *err = U_TRUNCATED_CHAR_FOUND;\
1101          args->source = args->sourceLimit;\
1102          return 0xffff;}
1103 
1104 /* Return the Unicode representation for the current LMBCS character */
1105 
1106 static UChar32
_LMBCSGetNextUCharWorker(UConverterToUnicodeArgs * args,UErrorCode * err)1107 _LMBCSGetNextUCharWorker(UConverterToUnicodeArgs*   args,
1108                          UErrorCode*   err)
1109 {
1110     UChar32 uniChar = 0;    /* an output UNICODE char */
1111     ulmbcs_byte_t   CurByte; /* A byte from the input stream */
1112 
1113     /* error check */
1114     if (args->source >= args->sourceLimit)
1115     {
1116         *err = U_ILLEGAL_ARGUMENT_ERROR;
1117         return 0xffff;
1118     }
1119     /* Grab first byte & save address for error recovery */
1120     CurByte = *((ulmbcs_byte_t  *) (args->source++));
1121 
1122     /*
1123     * at entry of each if clause:
1124     * 1. 'CurByte' points at the first byte of a LMBCS character
1125     * 2. '*source'points to the next byte of the source stream after 'CurByte'
1126     *
1127     * the job of each if clause is:
1128     * 1. set '*source' to point at the beginning of next char (nop if LMBCS char is only 1 byte)
1129     * 2. set 'uniChar' up with the right Unicode value, or set 'err' appropriately
1130     */
1131 
1132     /* First lets check the simple fixed values. */
1133 
1134     if(((CurByte > ULMBCS_C0END) && (CurByte < ULMBCS_C1START)) /* ascii range */
1135     ||  (CurByte == 0)
1136     ||  CurByte == ULMBCS_HT || CurByte == ULMBCS_CR
1137     ||  CurByte == ULMBCS_LF || CurByte == ULMBCS_123SYSTEMRANGE)
1138     {
1139         uniChar = CurByte;
1140     }
1141     else
1142     {
1143         UConverterDataLMBCS * extraInfo;
1144         ulmbcs_byte_t group;
1145         UConverterSharedData *cnv;
1146 
1147         if (CurByte == ULMBCS_GRP_CTRL)  /* Control character group - no opt group update */
1148         {
1149             ulmbcs_byte_t  C0C1byte;
1150             CHECK_SOURCE_LIMIT(1);
1151             C0C1byte = *(args->source)++;
1152             uniChar = (C0C1byte < ULMBCS_C1START) ? C0C1byte - ULMBCS_CTRLOFFSET : C0C1byte;
1153         }
1154         else
1155         if (CurByte == ULMBCS_GRP_UNICODE) /* Unicode compatibility group: BigEndian UTF16 */
1156         {
1157             CHECK_SOURCE_LIMIT(2);
1158 
1159             /* don't check for error indicators fffe/ffff below */
1160             return GetUniFromLMBCSUni(&(args->source));
1161         }
1162         else if (CurByte <= ULMBCS_CTRLOFFSET)
1163         {
1164             group = CurByte;                   /* group byte is in the source */
1165             extraInfo = (UConverterDataLMBCS *) args->converter->extraInfo;
1166             if (group > ULMBCS_GRP_LAST || (cnv = extraInfo->OptGrpConverter[group]) == NULL)
1167             {
1168                 /* this is not a valid group byte - no converter*/
1169                 *err = U_INVALID_CHAR_FOUND;
1170             }
1171             else if (group >= ULMBCS_DOUBLEOPTGROUP_START)    /* double byte conversion */
1172             {
1173 
1174                 CHECK_SOURCE_LIMIT(2);
1175 
1176                 /* check for LMBCS doubled-group-byte case */
1177                 if (*args->source == group) {
1178                     /* single byte */
1179                     ++args->source;
1180                     uniChar = ucnv_MBCSSimpleGetNextUChar(cnv, args->source, 1, FALSE);
1181                     ++args->source;
1182                 } else {
1183                     /* double byte */
1184                     uniChar = ucnv_MBCSSimpleGetNextUChar(cnv, args->source, 2, FALSE);
1185                     args->source += 2;
1186                 }
1187             }
1188             else {                                  /* single byte conversion */
1189                 CHECK_SOURCE_LIMIT(1);
1190                 CurByte = *(args->source)++;
1191 
1192                 if (CurByte >= ULMBCS_C1START)
1193                 {
1194                     uniChar = _MBCS_SINGLE_SIMPLE_GET_NEXT_BMP(cnv, CurByte);
1195                 }
1196                 else
1197                 {
1198                     /* The non-optimizable oddballs where there is an explicit byte
1199                     * AND the second byte is not in the upper ascii range
1200                     */
1201                     char bytes[2];
1202 
1203                     extraInfo = (UConverterDataLMBCS *) args->converter->extraInfo;
1204                     cnv = extraInfo->OptGrpConverter [ULMBCS_GRP_EXCEPT];
1205 
1206                     /* Lookup value must include opt group */
1207                     bytes[0] = group;
1208                     bytes[1] = CurByte;
1209                     uniChar = ucnv_MBCSSimpleGetNextUChar(cnv, bytes, 2, FALSE);
1210                 }
1211             }
1212         }
1213         else if (CurByte >= ULMBCS_C1START) /* group byte is implicit */
1214         {
1215             extraInfo = (UConverterDataLMBCS *) args->converter->extraInfo;
1216             group = extraInfo->OptGroup;
1217             cnv = extraInfo->OptGrpConverter[group];
1218             if (group >= ULMBCS_DOUBLEOPTGROUP_START)    /* double byte conversion */
1219             {
1220                 if (!ucnv_MBCSIsLeadByte(cnv, CurByte))
1221                 {
1222                     CHECK_SOURCE_LIMIT(0);
1223 
1224                     /* let the MBCS conversion consume CurByte again */
1225                     uniChar = ucnv_MBCSSimpleGetNextUChar(cnv, args->source - 1, 1, FALSE);
1226                 }
1227                 else
1228                 {
1229                     CHECK_SOURCE_LIMIT(1);
1230                     /* let the MBCS conversion consume CurByte again */
1231                     uniChar = ucnv_MBCSSimpleGetNextUChar(cnv, args->source - 1, 2, FALSE);
1232                     ++args->source;
1233                 }
1234             }
1235             else                                   /* single byte conversion */
1236             {
1237                 uniChar = _MBCS_SINGLE_SIMPLE_GET_NEXT_BMP(cnv, CurByte);
1238             }
1239         }
1240     }
1241     return uniChar;
1242 }
1243 
1244 
1245 /* The exported function that converts lmbcs to one or more
1246    UChars - currently UTF-16
1247 */
1248 static void
_LMBCSToUnicodeWithOffsets(UConverterToUnicodeArgs * args,UErrorCode * err)1249 _LMBCSToUnicodeWithOffsets(UConverterToUnicodeArgs*    args,
1250                      UErrorCode*    err)
1251 {
1252    char LMBCS [ULMBCS_CHARSIZE_MAX];
1253    UChar uniChar;    /* one output UNICODE char */
1254    const char * saveSource; /* beginning of current code point */
1255    const char * pStartLMBCS = args->source;  /* beginning of whole string */
1256    const char * errSource = NULL; /* pointer to actual input in case an error occurs */
1257    int8_t savebytes = 0;
1258 
1259    /* Process from source to limit, or until error */
1260    while (U_SUCCESS(*err) && args->sourceLimit > args->source && args->targetLimit > args->target)
1261    {
1262       saveSource = args->source; /* beginning of current code point */
1263 
1264       if (args->converter->toULength) /* reassemble char from previous call */
1265       {
1266         const char *saveSourceLimit;
1267         size_t size_old = args->converter->toULength;
1268 
1269          /* limit from source is either remainder of temp buffer, or user limit on source */
1270         size_t size_new_maybe_1 = sizeof(LMBCS) - size_old;
1271         size_t size_new_maybe_2 = args->sourceLimit - args->source;
1272         size_t size_new = (size_new_maybe_1 < size_new_maybe_2) ? size_new_maybe_1 : size_new_maybe_2;
1273 
1274 
1275         uprv_memcpy(LMBCS, args->converter->toUBytes, size_old);
1276         uprv_memcpy(LMBCS + size_old, args->source, size_new);
1277         saveSourceLimit = args->sourceLimit;
1278         args->source = errSource = LMBCS;
1279         args->sourceLimit = LMBCS+size_old+size_new;
1280         savebytes = (int8_t)(size_old+size_new);
1281         uniChar = (UChar) _LMBCSGetNextUCharWorker(args, err);
1282         args->source = saveSource + ((args->source - LMBCS) - size_old);
1283         args->sourceLimit = saveSourceLimit;
1284 
1285         if (*err == U_TRUNCATED_CHAR_FOUND)
1286         {
1287             /* evil special case: source buffers so small a char spans more than 2 buffers */
1288             args->converter->toULength = savebytes;
1289             uprv_memcpy(args->converter->toUBytes, LMBCS, savebytes);
1290             args->source = args->sourceLimit;
1291             *err = U_ZERO_ERROR;
1292             return;
1293          }
1294          else
1295          {
1296             /* clear the partial-char marker */
1297             args->converter->toULength = 0;
1298          }
1299       }
1300       else
1301       {
1302          errSource = saveSource;
1303          uniChar = (UChar) _LMBCSGetNextUCharWorker(args, err);
1304          savebytes = (int8_t)(args->source - saveSource);
1305       }
1306       if (U_SUCCESS(*err))
1307       {
1308          if (uniChar < 0xfffe)
1309          {
1310             *(args->target)++ = uniChar;
1311             if(args->offsets)
1312             {
1313                *(args->offsets)++ = (int32_t)(saveSource - pStartLMBCS);
1314             }
1315          }
1316          else if (uniChar == 0xfffe)
1317          {
1318             *err = U_INVALID_CHAR_FOUND;
1319          }
1320          else /* if (uniChar == 0xffff) */
1321          {
1322             *err = U_ILLEGAL_CHAR_FOUND;
1323          }
1324       }
1325    }
1326    /* if target ran out before source, return U_BUFFER_OVERFLOW_ERROR */
1327    if (U_SUCCESS(*err) && args->sourceLimit > args->source && args->targetLimit <= args->target)
1328    {
1329       *err = U_BUFFER_OVERFLOW_ERROR;
1330    }
1331    else if (U_FAILURE(*err))
1332    {
1333       /* If character incomplete or unmappable/illegal, store it in toUBytes[] */
1334       args->converter->toULength = savebytes;
1335       if (savebytes > 0) {
1336          uprv_memcpy(args->converter->toUBytes, errSource, savebytes);
1337       }
1338       if (*err == U_TRUNCATED_CHAR_FOUND) {
1339          *err = U_ZERO_ERROR;
1340       }
1341    }
1342 }
1343 
1344 /* And now, the macroized declarations of data & functions: */
1345 DEFINE_LMBCS_OPEN(1)
1346 DEFINE_LMBCS_OPEN(2)
1347 DEFINE_LMBCS_OPEN(3)
1348 DEFINE_LMBCS_OPEN(4)
1349 DEFINE_LMBCS_OPEN(5)
1350 DEFINE_LMBCS_OPEN(6)
1351 DEFINE_LMBCS_OPEN(8)
1352 DEFINE_LMBCS_OPEN(11)
1353 DEFINE_LMBCS_OPEN(16)
1354 DEFINE_LMBCS_OPEN(17)
1355 DEFINE_LMBCS_OPEN(18)
1356 DEFINE_LMBCS_OPEN(19)
1357 
1358 
1359 DECLARE_LMBCS_DATA(1)
1360 DECLARE_LMBCS_DATA(2)
1361 DECLARE_LMBCS_DATA(3)
1362 DECLARE_LMBCS_DATA(4)
1363 DECLARE_LMBCS_DATA(5)
1364 DECLARE_LMBCS_DATA(6)
1365 DECLARE_LMBCS_DATA(8)
1366 DECLARE_LMBCS_DATA(11)
1367 DECLARE_LMBCS_DATA(16)
1368 DECLARE_LMBCS_DATA(17)
1369 DECLARE_LMBCS_DATA(18)
1370 DECLARE_LMBCS_DATA(19)
1371 
1372 #endif /* #if !UCONFIG_NO_LEGACY_CONVERSION */
1373