~ubuntu-branches/ubuntu/jaunty/texlive-bin/jaunty-security

« back to all changes in this revision

Viewing changes to build/source/libs/icu-xetex/common/ucnv_lmb.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Preining
  • Date: 2008-06-26 23:14:59 UTC
  • mfrom: (2.1.30 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080626231459-y02rjsrgtafu83yr
Tags: 2007.dfsg.2-3
add missing source roadmap.fig of roadmap.eps in fontinst documentation
(Closes: #482915) (urgency medium due to RC bug)
(new patch add-missing-fontinst-source)

Show diffs side-by-side

added added

removed removed

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