source: trunk/Lucide/SOURCE/plugins/ludoc/cpconv.cpp @ 113

Last change on this file since 113 was 113, checked in by Eugene Romanenko, 15 years ago

replace ligatures when converting text from unicode to system codepage (closes #45)

File size: 12.2 KB
Line 
1/* ***** BEGIN LICENSE BLOCK *****
2 * Version: CDDL 1.0/LGPL 2.1
3 *
4 * The contents of this file are subject to the COMMON DEVELOPMENT AND
5 * DISTRIBUTION LICENSE (CDDL) Version 1.0 (the "License"); you may not use
6 * this file except in compliance with the License. You may obtain a copy of
7 * the License at http://www.sun.com/cddl/
8 *
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
13 *
14 * The Initial Developer of the Original Code is
15 * Eugene Romanenko, netlabs.org.
16 * Portions created by the Initial Developer are Copyright (C) 2006
17 * the Initial Developer. All Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * Alternatively, the contents of this file may be used under the terms of
22 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
23 * in which case the provisions of the LGPL are applicable instead of those
24 * above. If you wish to allow use of your version of this file only under the
25 * terms of the LGPL, and not to allow others to use your version of this file
26 * under the terms of the CDDL, indicate your decision by deleting the
27 * provisions above and replace them with the notice and other provisions
28 * required by the LGPL. If you do not delete the provisions above, a recipient
29 * may use your version of this file under the terms of any one of the CDDL
30 * or the LGPL.
31 *
32 * ***** END LICENSE BLOCK ***** */
33
34
35#define INCL_DOS
36#include <os2.h>
37
38#include <string.h>
39#include <malloc.h>
40#include <stdio.h>
41
42#include <uconv.h>
43
44
45class cpconv
46{
47    protected:
48        int  err;
49        void *objtoucs;
50        void *objfromucs;
51    public:
52        cpconv( int cpfrom, int cpto = 0 );
53        cpconv( UniChar *cpfrom, UniChar *cpto );
54        ~cpconv();
55        int conv( int chfrom );
56        int conv( const char **in, size_t *in_left, char **out, size_t *out_left );
57};
58
59cpconv::cpconv( UniChar *cpfrom, UniChar *cpto )
60{
61    err = 0;
62    int         rc = ULS_SUCCESS;
63
64    rc = UniCreateUconvObject( cpfrom, &objtoucs );
65    if (rc != ULS_SUCCESS)
66    {
67        err = 1;
68        return;
69    }
70
71    uconv_attribute_t attr;
72    UniQueryUconvObject(objtoucs, &attr, sizeof(attr), NULL, NULL, NULL);
73    attr.converttype &= ~(CVTTYPE_CTRL7F | CVTTYPE_PATH);
74    UniSetUconvObject(objtoucs, &attr);
75
76    rc = UniCreateUconvObject( cpto, &objfromucs );
77    if (rc != ULS_SUCCESS)
78    {
79        UniFreeUconvObject( objtoucs );
80        err = 1;
81        return;
82    }
83    UniQueryUconvObject(objfromucs, &attr, sizeof(uconv_attribute_t), NULL, NULL, NULL);
84    attr.options = UCONV_OPTION_SUBSTITUTE_BOTH;
85    UniSetUconvObject(objfromucs, &attr);
86}
87
88cpconv::cpconv( int cpfrom, int cpto )
89{
90    err = 0;
91
92    UniChar     ucs_code_page[12];
93    size_t      num_elems = 12;
94    int         rc = ULS_SUCCESS;
95
96    rc = UniMapCpToUcsCp(cpfrom, ucs_code_page, num_elems);
97    if (rc != ULS_SUCCESS)
98    {
99        err = 1;
100        return;
101    }
102
103    rc = UniCreateUconvObject(ucs_code_page, &objtoucs);
104    if (rc != ULS_SUCCESS)
105    {
106        err = 1;
107        return;
108    }
109
110    uconv_attribute_t attr;
111    UniQueryUconvObject(objtoucs, &attr, sizeof(attr), NULL, NULL, NULL);
112    attr.converttype &= ~(CVTTYPE_CTRL7F | CVTTYPE_PATH);
113    UniSetUconvObject(objtoucs, &attr);
114
115    rc = UniMapCpToUcsCp(cpto, ucs_code_page, num_elems);
116    if (rc != ULS_SUCCESS)
117    {
118        UniFreeUconvObject( objtoucs );
119        err = 1;
120        return;
121    }
122
123    rc = UniCreateUconvObject(ucs_code_page, &objfromucs);
124    if (rc != ULS_SUCCESS)
125    {
126        UniFreeUconvObject( objtoucs );
127        err = 1;
128        return;
129    }
130    UniQueryUconvObject(objfromucs, &attr, sizeof(uconv_attribute_t), NULL, NULL, NULL);
131    attr.options = UCONV_OPTION_SUBSTITUTE_BOTH;
132    UniSetUconvObject(objfromucs, &attr);
133}
134
135cpconv::~cpconv()
136{
137    if ( !err )
138    {
139        UniFreeUconvObject( objtoucs );
140        UniFreeUconvObject( objfromucs );
141    }
142}
143
144// convert one char
145int cpconv::conv( int chfrom )
146{
147    int rc = ULS_SUCCESS;
148    size_t ns = 0;
149    int chto = 0;
150
151    if ( err )  return chfrom;
152
153    size_t len = 1;
154    UniChar unichar;
155    UniChar *punichar = &unichar;
156    void *pchfrom = &chfrom;
157    void *pchto = &chto;
158
159    rc = UniUconvToUcs( objtoucs, &pchfrom, &len, &punichar, &len, &ns);
160    if ( rc != ULS_SUCCESS )  return chfrom;
161
162    len = 1;
163    punichar = &unichar;
164    ns = 0;
165    rc = UniUconvFromUcs( objfromucs, &punichar, &len, &pchto, &len, &ns);
166    if ( rc != ULS_SUCCESS )  return chfrom;
167
168    return chto;
169}
170
171int cpconv::conv( const char **in, size_t *in_left, char **out, size_t *out_left )
172{
173    int       rc;
174    size_t    sl;
175    size_t    nonid;
176    UniChar  *ucs;
177    UniChar  *orig_ucs;
178    size_t    retval = 0;
179
180    if (!in || !*in) {
181        return 0;
182    }
183
184    sl =  *in_left;
185    //ucs = new UniChar[ sl ];
186    // have crashes in libc memmanager due to frequent alloc/free
187    // use system malloc routines as workaround
188    DosAllocMem( (PPVOID)&ucs, sl * sizeof( UniChar ), fALLOC );
189    orig_ucs = ucs;
190
191    rc = UniUconvToUcs( objtoucs, (void **)in, in_left, &ucs, &sl, &retval );
192    if ( rc != 0 ) {
193        //delete ucs;
194        DosFreeMem( ucs );
195        err = 1;
196        return -1;
197    }
198
199    sl = ucs - orig_ucs;
200    ucs = orig_ucs;
201    rc = UniUconvFromUcs( objfromucs, &ucs, &sl, (void **)out, out_left, &nonid );
202    //delete ucs;
203    DosFreeMem( ucs );
204
205    if ( rc != 0 ) {
206        err = 1;
207        return -1;
208    }
209
210    retval += nonid;
211    return 0;
212}
213
214extern "C" LONG APIENTRY cnvUniToUTF8( const char **in, unsigned *in_left,
215                                       char **out, unsigned *out_left )
216{
217    cpconv c( 1200, 1208 );
218    return c.conv( in, in_left, out, out_left );
219}
220
221extern "C" LONG APIENTRY cnvUniBEToUTF8( const char **in, unsigned *in_left,
222                                         char **out, unsigned *out_left )
223{
224    cpconv c( (UniChar *)(L"UCS-2@endian=big"), (UniChar *)(L"UTF-8") );
225    return c.conv( in, in_left, out, out_left );
226}
227
228extern "C" LONG APIENTRY cnvUTF8ToUni( const char **in, unsigned *in_left,
229                                       char **out, unsigned *out_left )
230{
231    cpconv c( 1208, 1200 );
232    return c.conv( in, in_left, out, out_left );
233}
234
235
236// Converts special non-ascii chars to suitable ascii chars
237static void convSpchars( UniChar *uni )
238{
239    while ( *uni )
240    {
241        switch ( *uni )
242        {
243            case 0x2018:
244            case 0x2019:
245            case 0x2032:
246                *uni = 0x0027; // '
247                break;
248            case 0x201C:
249            case 0x201D:
250            case 0x00AB:
251            case 0x00BB:
252                *uni = 0x0022; // "
253                break;
254            case 0x2014:
255                *uni = 0x002D; // -
256                break;
257        }
258        *uni++;
259    }
260}
261
262
263// Ligatures table
264struct Ligature { UniChar unicode;  wchar_t *equivalent;  int equivalentLength; };
265
266// Table from [http://en.wikipedia.org/wiki/Ligature_(typography)#Unicode]
267#define NUM_LIGATURES   38
268static Ligature ligatures[ NUM_LIGATURES ] = {
269    { 0x00DF, L"fs",  2 }, { 0x00E6, L"AE",  2 }, { 0x00C6, L"ae",  2 },
270    { 0x0152, L"OE",  2 }, { 0x0153, L"oe",  2 }, { 0x0276, L"oe",  2 },
271    { 0x0132, L"IJ",  2 }, { 0x0133, L"ij",  2 }, { 0x014A, L"Ng",  2 },
272    { 0x014B, L"ng",  2 }, { 0x01F6, L"Hv",  2 }, { 0x0195, L"hv",  2 },
273    { 0x01C4, L"DZ",  2 }, { 0x01C5, L"Dz",  2 }, { 0x01C6, L"dz",  2 },
274    { 0x01C7, L"LJ",  2 }, { 0x01C8, L"Lj",  2 }, { 0x01C9, L"lj",  2 },
275    { 0x01CA, L"NJ",  2 }, { 0x01CB, L"Nj",  2 }, { 0x01CC, L"nj",  2 },
276    { 0x01F1, L"DZ",  2 }, { 0x01F2, L"Dz",  2 }, { 0x01F3, L"dz",  2 },
277    { 0x02A3, L"dz",  2 }, { 0x02A6, L"ts",  2 }, { 0x02A9, L"fng", 3 },
278    { 0x02AA, L"ls",  2 }, { 0x02AB, L"lz",  2 }, { 0x02AC, L"ww",  2 },
279    { 0x1D6B, L"ue",  2 }, { 0xFB00, L"ff",  2 }, { 0xFB01, L"fi",  2 },
280    { 0xFB02, L"fl",  2 }, { 0xFB03, L"ffi", 3 }, { 0xFB04, L"ffl", 3 },
281    { 0xFB05, L"ft",  2 }, { 0xFB06, L"st",  2 }
282};
283
284// If unichar is ligature - returns number of additional chars
285// which replaces the ligature, zero otherwise.
286inline int isLigature( UniChar ch )
287{
288    for ( int i = 0; i < NUM_LIGATURES; i++ ) {
289        if ( ch == ligatures[ i ].unicode ) {
290            return ligatures[ i ].equivalentLength - 1;
291        }
292    }
293    return 0;
294}
295
296// If unichar is ligature - returns pointer to struct Ligature
297// which contains replacement for ligature, NULL otherwise.
298inline Ligature *getReplLigature( UniChar ch )
299{
300    for ( int i = 0; i < NUM_LIGATURES; i++ ) {
301        if ( ch == ligatures[ i ].unicode ) {
302            return &( ligatures[ i ] );
303        }
304    }
305    return NULL;
306}
307
308// Return number of chars which should be added to string
309// length to fit the string with converted ligatures.
310// If no ligatures in string - returns zero.
311static int ligaturesLength( UniChar *str )
312{
313    int llen = 0;
314    while ( *str != 0 ) {
315        llen += isLigature( *str++ );
316    }
317    return llen;
318}
319
320// replaces ligatures in src into dst
321// src remains unchanged
322static void replLigatures( UniChar *src, UniChar *dst )
323{
324    while ( *src != 0 )
325    {
326        Ligature *lig = getReplLigature( *src );
327        if ( lig == NULL ) {
328            *dst++ = *src++;
329        }
330        else {
331            for ( int i = 0; i < lig->equivalentLength; i++ ) {
332                *dst++ = lig->equivalent[ i ];
333            }
334            *src++;
335        }
336    }
337}
338
339extern "C" LONG APIENTRY cnvUTF8ToSys( const char **in, unsigned *in_left,
340                                       char **out, unsigned *out_left )
341{
342    unsigned ulen = ( (*in_left) * 2 ) + 2;
343    char *uni = new char[ ulen ];
344    memset( uni, 0, ulen );
345    char *savuni = uni;
346    unsigned savulen = ulen;
347    cnvUTF8ToUni( in, in_left, &uni, &ulen );
348    uni = savuni;
349    ulen = savulen;
350    int liglen = ligaturesLength( (UniChar *)uni );
351    if ( liglen > 0 )  // string contain ligature(s)
352    {
353        unsigned ulen_tmp = ulen + ( liglen * 2 );
354        char *uni_tmp = new char[ ulen_tmp ];
355        replLigatures( (UniChar *)uni, (UniChar *)uni_tmp );
356        delete uni;
357        uni = uni_tmp;
358        ulen = ulen_tmp;
359    }
360    convSpchars( (UniChar *)uni );
361    cpconv c( 1200 );
362    LONG rc = c.conv( (const char **)&uni, &ulen, out, out_left );
363    uni = savuni;
364    delete uni;
365    return rc;
366}
367
368extern "C" LONG APIENTRY cnvUniBEToSys( const char **in, unsigned *in_left,
369                                         char **out, unsigned *out_left )
370{
371    unsigned ulen = ( (*in_left) * 2 ) + 2;
372    char *uni = new char[ ulen ];
373    memset( uni, 0, ulen );
374    char *savuni = uni;
375    unsigned savulen = ulen;
376    cpconv c1( (UniChar *)(L"UCS-2@endian=big"), (UniChar *)(L"UCS-2") );
377    c1.conv( in, in_left, &uni, &ulen );
378    uni = savuni;
379    ulen = savulen;
380    convSpchars( (UniChar *)uni );
381    cpconv c2( 1200 );
382    LONG rc = c2.conv( (const char **)&uni, &ulen, out, out_left );
383    uni = savuni;
384    delete uni;
385    return rc;
386}
387
388extern "C" LONG APIENTRY cnvUniToSys( const char **in, unsigned *in_left,
389                                      char **out, unsigned *out_left )
390{
391    convSpchars( (UniChar *)in );
392    cpconv c( 1200 );
393    return c.conv( (const char **)&in, in_left, out, out_left );
394}
395
396extern "C" LONG APIENTRY cnvSysToUCS2( const char **in, unsigned *in_left,
397                                       char **out, unsigned *out_left )
398{
399    cpconv c( (UniChar *)(L""), (UniChar *)(L"UCS-2") );
400    return c.conv( in, in_left, out, out_left );
401}
402
403
404// test
405/*void main()
406{
407    const char *testutf8 = "test UTF-8  ’¥áâ! à®¢¥àª !";
408    char buf[ 100 ];
409    memset( buf, 0, sizeof( buf ) );
410    char *bufsav = buf;
411    char *buf1 = buf;
412    unsigned in_len = strlen( testutf8 );
413    unsigned out_len = sizeof( buf );
414
415    cnvUTF8ToUCS4( &testutf8, &in_len, &buf1, &out_len );
416
417    for ( int i = 0; i<100; i++ )
418    {
419        printf( ":%d:", (int)bufsav[i] );
420    }
421    printf( "\n" );
422}
423*/
Note: See TracBrowser for help on using the repository browser.