~ubuntu-branches/ubuntu/gutsy/icu/gutsy-updates

« back to all changes in this revision

Viewing changes to source/common/ucnv_lmb.c

  • Committer: Package Import Robot
  • Author(s): Jay Berkenbilt
  • Date: 2005-11-19 11:29:31 UTC
  • mfrom: (1.1.2)
  • Revision ID: package-import@ubuntu.com-20051119112931-vcizkrp10tli4enw
Tags: 3.4-3
Explicitly build with g++ 3.4.  The current ICU fails its test suite
with 4.0 but not with 3.4.  Future versions should work properly with
4.0.

Show diffs side-by-side

added added

removed removed

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