Annotation of parser3/src/main/pa_charset.C, revision 1.33.2.2
1.1 paf 1: /** @file
2: Parser: Charset connection implementation.
3:
1.33 paf 4: Copyright(c) 2001, 2003 ArtLebedev Group (http://www.artlebedev.com)
1.4 paf 5: Author: Alexander Petrosyan<paf@design.ru>(http://paf.design.ru)
1.27 paf 6: */
1.1 paf 7:
1.33.2.2! paf 8: static const char* IDENT_CHARSET_C="$Date: 2003/01/27 15:35:24 $";
1.1 paf 9:
10: #include "pa_charset.h"
1.33.2.2! paf 11: //#include "pa_globals.h"
1.1 paf 12:
13: #ifdef XML
1.8 paf 14: #include "libxml/encoding.h"
1.1 paf 15: #endif
16:
17: // globals
18:
1.33.2.2! paf 19: #define CHARSET_UTF8_NAME "UTF-8"
! 20:
! 21: CharsetPtr UTF8_charset(new Charset(ConstStringPtr(new String(CHARSET_UTF8_NAME)),
! 22: ConstStringPtrZero/*no file=system*/,
! 23: 0/* no file=no file read pool*/));
1.1 paf 24:
25: // consts
26:
27: #define MAX_CHARSET_UNI_CODES 500
28:
29: // helpers
30:
31: inline void prepare_case_tables(unsigned char *tables) {
32: unsigned char *lcc_table=tables+lcc_offset;
33: unsigned char *fcc_table=tables+fcc_offset;
34: for(int i=0; i<0x100; i++)
35: lcc_table[i]=fcc_table[i]=i;
36: }
37: inline void cstr2ctypes(unsigned char *tables, const unsigned char *cstr,
38: unsigned char bit) {
39: unsigned char *ctypes_table=tables+ctypes_offset;
40: ctypes_table[0]=bit;
41: for(; *cstr; cstr++) {
42: unsigned char c=*cstr;
43: ctypes_table[c]|=bit;
44: }
45: }
46: inline unsigned int to_wchar_code(const char *cstr) {
47: if(!cstr || !*cstr)
48: return 0;
49: if(cstr[1]==0)
1.4 paf 50: return(unsigned int)(unsigned char)cstr[0];
1.1 paf 51:
52: char *error_pos;
1.4 paf 53: return(unsigned int)strtol(cstr, &error_pos, 0);
1.1 paf 54: }
55: inline bool to_bool(const char *cstr) {
56: return cstr && *cstr!=0;
57: }
58: static void element2ctypes(unsigned char c, bool belongs,
59: unsigned char *tables, unsigned char bit, int group_offset=-1) {
60: if(!belongs)
61: return;
62:
63: unsigned char *ctypes_table=tables+ctypes_offset;
64:
65: ctypes_table[c]|=bit;
66: if(group_offset>=0)
1.4 paf 67: tables[cbits_offset+group_offset+c/8] |= 1<<(c%8);
1.1 paf 68: }
69: static void element2case(unsigned char from, unsigned char to,
70: unsigned char *tables) {
71: if(!to)
72: return;
73:
74: unsigned char *lcc_table=tables+lcc_offset;
75: unsigned char *fcc_table=tables+fcc_offset;
76: lcc_table[from]=to;
77: fcc_table[from]=to; fcc_table[to]=from;
78: }
79:
80: // methods
81:
82: extern "C" unsigned char pcre_default_tables[]; // pcre/chartables.c
1.33.2.2! paf 83: Charset::Charset(ConstStringPtr aname, ConstStringPtr afile_spec, Pool* apool_for_load):
1.33.2.1 paf 84: fname(aname),
85: fname_cstr(aname->cstr()) {
1.1 paf 86:
1.33.2.1 paf 87: for(char *c=fname_cstr; *c; c++)
1.10 paf 88: *c = toupper(*c);
1.7 paf 89:
1.33.2.2! paf 90: if(afile_spec && apool_for_load) {
1.1 paf 91: fisUTF8=false;
1.33.2.2! paf 92: loadDefinition(*apool_for_load, fname);
1.1 paf 93: #ifdef XML
1.33.2.1 paf 94: addEncoding(fname_cstr);
1.1 paf 95: #endif
96: } else {
97: fisUTF8=true;
1.4 paf 98: // grab default onces [for UTF-8 so to be able to make a-z =>A-Z
1.1 paf 99: memcpy(pcre_tables, pcre_default_tables, sizeof(pcre_tables));
100: }
101:
102: #ifdef XML
1.33.2.1 paf 103: initTranscoder(fname, fname_cstr);
1.1 paf 104: #endif
105: }
106:
107: Charset::~Charset() {
1.33.2.1 paf 108: // @todonow unregister encodings
1.1 paf 109: #ifdef XML
1.9 paf 110: // not deleting transcoder, that's not our business
1.1 paf 111: #endif
112: }
113:
1.33.2.2! paf 114: void Charset::loadDefinition(Pool& apool_for_load, ConstStringPtr afile_spec) {
1.1 paf 115: // pcre_tables
116: // lowcase, flipcase, bits digit+word+whitespace, masks
117:
118: // must not move this inside of prepare_case_tables
119: // don't know the size there
120: memset(pcre_tables, 0, sizeof(pcre_tables));
121: prepare_case_tables(pcre_tables);
1.4 paf 122: cstr2ctypes(pcre_tables,(const unsigned char *)"*+?{^.$|()[", ctype_meta);
1.1 paf 123:
124: // charset
1.10 paf 125: memset(tables.fromTable, 0, sizeof(tables.fromTable));
1.33.2.2! paf 126: tables.toTable=(Charset_TransRec *)apool_for_load.calloc(sizeof(Charset_TransRec)*MAX_CHARSET_UNI_CODES);
1.10 paf 127: tables.toTableSize=0;
1.1 paf 128: // strangly vital
1.10 paf 129: tables.toTable[tables.toTableSize].intCh=0;
130: tables.toTable[tables.toTableSize].extCh=(XMLByte)0;
131: tables.toTableSize++;
1.1 paf 132:
133: // loading text
1.33.2.2! paf 134: char *data=file_read_text(apool_for_load, *UTF8_charset, afile_spec);
1.1 paf 135:
136: // ignore header
137: getrow(&data);
138:
139: // parse cells
140: char *row;
141: while(row=getrow(&data)) {
142: // remove empty&comment lines
143: if(!*row || *row=='#')
144: continue;
145:
146: // char white-space digit hex-digit letter word lowercase unicode1 unicode2
147: unsigned int c=0;
148: char *cell;
149: for(int column=0; cell=lsplit(&row, '\t'); column++) {
150: switch(column) {
151: case 0: c=to_wchar_code(cell); break;
152: // pcre_tables
153: case 1: element2ctypes(c, to_bool(cell), pcre_tables, ctype_space, cbit_space); break;
154: case 2: element2ctypes(c, to_bool(cell), pcre_tables, ctype_digit, cbit_digit); break;
155: case 3: element2ctypes(c, to_bool(cell), pcre_tables, ctype_xdigit); break;
156: case 4: element2ctypes(c, to_bool(cell), pcre_tables, ctype_letter); break;
157: case 5: element2ctypes(c, to_bool(cell), pcre_tables, ctype_word, cbit_word); break;
158: case 6: element2case(c, to_wchar_code(cell), pcre_tables); break;
159: case 7:
160: case 8:
161: // charset
1.10 paf 162: if(tables.toTableSize>MAX_CHARSET_UNI_CODES)
1.23 paf 163: throw Exception("parser.runtime",
1.33.2.1 paf 164: afile_spec,
1.1 paf 165: "charset must contain not more then %d unicode values", MAX_CHARSET_UNI_CODES);
166:
167: XMLCh unicode=(XMLCh)to_wchar_code(cell);
168: if(!unicode && column==7/*unicode1 column*/)
169: unicode=(XMLCh)c;
170: if(unicode) {
1.10 paf 171: if(!tables.fromTable[c])
172: tables.fromTable[c]=unicode;
173: tables.toTable[tables.toTableSize].intCh=unicode;
174: tables.toTable[tables.toTableSize].extCh=(XMLByte)c;
175: tables.toTableSize++;
1.1 paf 176: }
177: break;
178: }
179: }
180: };
181:
182: // sort by the Unicode code point
183: sort_ToTable();
184: }
185:
186: static int sort_cmp_Trans_rec_intCh(const void *a, const void *b) {
187: return
188: static_cast<const Charset_TransRec *>(a)->intCh-
189: static_cast<const Charset_TransRec *>(b)->intCh;
190: }
191:
192: void Charset::sort_ToTable() {
1.10 paf 193: _qsort(tables.toTable, tables.toTableSize, sizeof(*tables.toTable),
1.1 paf 194: sort_cmp_Trans_rec_intCh);
195: //FILE *f=fopen("c:\\temp\\a", "wb");
1.10 paf 196: //fwrite(tables.toTable, tables.toTableSize, sizeof(*tables.toTable), f);
1.1 paf 197: //fclose(f);
198: }
199:
1.10 paf 200: static XMLByte xlatOneTo(const XMLCh toXlat,
1.25 paf 201: const Charset::Tables& tables,
202: XMLByte not_found) {
1.1 paf 203: unsigned int lowOfs = 0;
1.10 paf 204: unsigned int hiOfs = tables.toTableSize - 1;
1.1 paf 205: XMLByte curByte = 0;
206: do {
207: // Calc the mid point of the low and high offset.
1.4 paf 208: const unsigned int midOfs =((hiOfs - lowOfs) / 2)+lowOfs;
1.1 paf 209:
210: // If our test char is greater than the mid point char, then
211: // we move up to the upper half. Else we move to the lower
212: // half. If its equal, then its our guy.
1.10 paf 213: if(toXlat>tables.toTable[midOfs].intCh)
1.1 paf 214: lowOfs = midOfs;
1.10 paf 215: else if(toXlat<tables.toTable[midOfs].intCh)
1.1 paf 216: hiOfs = midOfs;
217: else
1.10 paf 218: return tables.toTable[midOfs].extCh;
1.4 paf 219: } while(lowOfs+1<hiOfs);
1.1 paf 220:
1.25 paf 221: return not_found;
1.1 paf 222: }
223:
224: void Charset::transcode(Pool& pool,
225: const Charset& source_charset, const void *source_body, size_t source_content_length,
226: const Charset& dest_charset, const void *& dest_body, size_t& dest_content_length
227: ) {
1.4 paf 228: if(!source_content_length) {
229: dest_body=0;
230: dest_content_length=0;
231: return;
232: }
233:
1.1 paf 234: switch((source_charset.isUTF8()?0x10:0x00)|(dest_charset.isUTF8()?0x01:0x00)) {
235: default: // 0x00
236: source_charset.transcodeToCharset(pool, dest_charset,
237: source_body, source_content_length,
238: dest_body, dest_content_length);
239: break;
240: case 0x01:
241: source_charset.transcodeToUTF8(pool,
242: source_body, source_content_length,
243: dest_body, dest_content_length);
244: break;
245: case 0x10:
246: dest_charset.transcodeFromUTF8(pool,
247: source_body, source_content_length,
248: dest_body, dest_content_length);
249: break;
250: case 0x11:
251: dest_body=source_body;
252: dest_content_length=source_content_length;
253: break;
254: }
255: }
256:
257: // ---------------------------------------------------------------------------
258: // Local static data
259: //
260: // gUTFBytes
261: // A list of counts of trailing bytes for each initial byte in the input.
262: //
263: // gUTFOffsets
264: // A list of values to offset each result char type, according to how
265: // many source bytes when into making it.
266: //
267: // gFirstByteMark
268: // A list of values to mask onto the first byte of an encoded sequence,
269: // indexed by the number of bytes used to create the sequence.
270: // ---------------------------------------------------------------------------
271: static const XMLByte gUTFBytes[0x100] = {
272: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
273: , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
274: , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
275: , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
276: , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
277: , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
278: , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
279: , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
280: , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
281: , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
282: , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
283: , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
284: , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
285: , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
286: , 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
287: , 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
288: };
289:
290: static const uint gUTFOffsets[6] = {
291: 0, 0x3080, 0xE2080, 0x3C82080, 0xFA082080, 0x82082080
292: };
293:
294: static const XMLByte gFirstByteMark[7] = {
295: 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
296: };
297:
1.11 paf 298: static int transcodeToUTF8(
299: const XMLByte* srcData, size_t& srcLen,
300: XMLByte *toFill, size_t& toFillLen,
1.10 paf 301: const Charset::Tables& tables) {
1.11 paf 302: const XMLByte* srcPtr=srcData;
303: const XMLByte* srcEnd=srcData+srcLen;
304: XMLByte* outPtr=toFill;
305: XMLByte* outEnd=toFill+toFillLen;
1.1 paf 306:
1.4 paf 307: while(srcPtr<srcEnd) {
1.10 paf 308: uint curVal = tables.fromTable[*srcPtr];
1.1 paf 309: if(!curVal) {
310: // use the replacement character
1.4 paf 311: *outPtr++= '?';
312: srcPtr++;
1.1 paf 313: continue;
314: }
315:
316: // Figure out how many bytes we need
317: unsigned int encodedBytes;
1.4 paf 318: if(curVal<0x80)
1.1 paf 319: encodedBytes = 1;
1.4 paf 320: else if(curVal<0x800)
1.1 paf 321: encodedBytes = 2;
1.4 paf 322: else if(curVal<0x10000)
1.1 paf 323: encodedBytes = 3;
1.4 paf 324: else if(curVal<0x200000)
1.1 paf 325: encodedBytes = 4;
1.4 paf 326: else if(curVal<0x4000000)
1.1 paf 327: encodedBytes = 5;
1.4 paf 328: else if(curVal<= 0x7FFFFFFF)
1.1 paf 329: encodedBytes = 6;
330: else {
331: // use the replacement character
1.4 paf 332: *outPtr++= '?';
333: srcPtr++;
1.1 paf 334: continue;
335: }
336:
1.10 paf 337: // If we cannot fully get this char into the output buffer
338: if (outPtr + encodedBytes > outEnd)
339: break;
1.1 paf 340:
341: // We can do it, so update the source index
342: srcPtr++;
343:
344: // And spit out the bytes. We spit them out in reverse order
345: // here, so bump up the output pointer and work down as we go.
1.4 paf 346: outPtr+= encodedBytes;
1.1 paf 347: switch(encodedBytes) {
1.18 paf 348: case 6: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
1.4 paf 349: curVal>>= 6;
1.18 paf 350: case 5: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
1.4 paf 351: curVal>>= 6;
1.18 paf 352: case 4: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
1.4 paf 353: curVal>>= 6;
1.18 paf 354: case 3: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
1.4 paf 355: curVal>>= 6;
1.18 paf 356: case 2: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
1.4 paf 357: curVal>>= 6;
1.18 paf 358: case 1: *--outPtr = XMLByte(curVal | gFirstByteMark[encodedBytes]);
1.1 paf 359: }
360:
361: // Add the encoded bytes back in again to indicate we've eaten them
1.4 paf 362: outPtr+= encodedBytes;
1.1 paf 363: }
364:
1.11 paf 365: // Update the bytes eaten
366: srcLen = srcPtr - srcData;
367:
368: // Return the characters read
369: toFillLen = outPtr - toFill;
370:
1.29 paf 371: //return srcPtr==srcEnd?(int)toFillLen:-1;
372: /*
373: xmlCharEncodingInputFunc
374: Returns :
375: the number of byte written, or -1 by lack of space, or -2 if the transcoding failed. The value of inlen after return is the
376: number of octets consumed as the return value is positive, else unpredictiable. The value of outlen after return is the number
377: of ocetes consumed.
378: */
379: return 0;
1.1 paf 380: }
1.26 paf 381: /// @todo digital entites only when xml/html output [at output in html/xml mode, in html part of a letter]
1.30 paf 382: static int transcodeFromUTF8(
1.11 paf 383: const XMLByte *srcData, size_t& srcLen,
384: XMLByte* toFill, size_t& toFillLen,
385: const Charset::Tables& tables) {
386: const XMLByte* srcPtr=srcData;
387: const XMLByte* srcEnd=srcData+srcLen;
388: XMLByte* outPtr=toFill;
389: XMLByte* outEnd=toFill+toFillLen;
1.1 paf 390:
1.10 paf 391: // We now loop until we either run out of input data, or room to store
392: while ((srcPtr < srcEnd) && (outPtr < outEnd)) {
1.1 paf 393: // Get the next leading byte out
394: const XMLByte firstByte = *srcPtr;
395:
1.4 paf 396: // Special-case ASCII, which is a leading byte value of<= 127
397: if(firstByte<= 127) {
398: *outPtr++= firstByte;
1.1 paf 399: srcPtr++;
400: continue;
401: }
402:
403: // See how many trailing src bytes this sequence is going to require
404: const unsigned int trailingBytes = gUTFBytes[firstByte];
405:
406: // If there are not enough source bytes to do this one, then we
1.4 paf 407: // are done. Note that we done>= here because we are implicitly
1.1 paf 408: // counting the 1 byte we get no matter what.
1.4 paf 409: if(srcPtr+trailingBytes>= srcEnd)
1.1 paf 410: break;
411:
412: // Looks ok, so lets build up the value
413: uint tmpVal=0;
414: switch(trailingBytes) {
415: case 5: tmpVal+=*srcPtr++; tmpVal<<=6;
416: case 4: tmpVal+=*srcPtr++; tmpVal<<=6;
417: case 3: tmpVal+=*srcPtr++; tmpVal<<=6;
418: case 2: tmpVal+=*srcPtr++; tmpVal<<=6;
419: case 1: tmpVal+=*srcPtr++; tmpVal<<=6;
420: case 0: tmpVal+=*srcPtr++;
421: break;
422:
423: default:
1.23 paf 424: throw Exception(0,
1.33.2.1 paf 425: Exception::undefined_source,
1.4 paf 426: "transcodeFromUTF8 error: wrong trailingBytes value(%d)", trailingBytes);
1.1 paf 427: }
428: tmpVal-=gUTFOffsets[trailingBytes];
429:
430: // If it will fit into a single char, then put it in. Otherwise
431: // fail [*encode it as a surrogate pair. If its not valid, use the
432: // replacement char.*]
1.25 paf 433: if(!(tmpVal & 0xFFFF0000)) {
434: if(XMLByte xlat=xlatOneTo(tmpVal, tables, 0))
435: *outPtr++=xlat;
436: else
437: outPtr+=sprintf((char *)outPtr, "&#%d;", tmpVal); // &#decimal;
438: } else
1.23 paf 439: throw Exception(0,
1.33.2.1 paf 440: Exception::undefined_source,
1.4 paf 441: "transcodeFromUTF8 error: too big tmpVal(0x%08X)", tmpVal);
1.1 paf 442: }
443:
1.11 paf 444: // Update the bytes eaten
445: srcLen = srcPtr - srcData;
446:
447: // Return the characters read
448: toFillLen = outPtr - toFill;
449:
1.29 paf 450: //return srcPtr==srcEnd?(int)toFillLen:-1;
451: /*
452: xmlCharEncodingOutputFunc
453: Returns :
454: the number of byte written, or -1 by lack of space, or -2 if the transcoding failed. The value of inlen after return is the
455: number of octets consumed as the return value is positive, else unpredictiable. The value of outlen after return is the number
456: of ocetes consumed.
457: */
458: return 0;
1.10 paf 459: }
460:
461: /// @todo not so memory-hungry with prescan
462: void Charset::transcodeToUTF8(Pool& pool,
463: const void *source_body, size_t source_content_length,
1.11 paf 464: const void *& adest_body, size_t& dest_content_length) const {
1.25 paf 465: dest_content_length=source_content_length*6/*so that surly enough, max utf8 seq len=6*/;
1.11 paf 466: XMLByte *dest_body=(XMLByte*)pool.malloc(dest_content_length);
467:
468: if(::transcodeToUTF8(
469: (XMLByte *)source_body, source_content_length,
470: dest_body, dest_content_length,
471: tables)<0)
1.10 paf 472: throw(0, 0,
473: 0,
1.11 paf 474: "Charset::transcodeToUTF8 buffer overflow");
1.10 paf 475:
1.1 paf 476: // return
477: adest_body=dest_body;
1.10 paf 478: }
479: void Charset::transcodeFromUTF8(Pool& pool,
480: const void *source_body, size_t source_content_length,
1.11 paf 481: const void *& adest_body, size_t& dest_content_length) const {
1.25 paf 482: dest_content_length=source_content_length*6/*so that surly enough, "ÿ" has max ratio */;
1.11 paf 483: XMLByte *dest_body=(XMLByte*)pool.malloc(dest_content_length);
484:
485: if(::transcodeFromUTF8(
486: (XMLByte *)source_body, source_content_length,
487: dest_body, dest_content_length,
488: tables)<0)
1.10 paf 489: throw(0, 0,
490: 0,
1.11 paf 491: "Charset::transcodeToUTF8 buffer overflow");
1.10 paf 492:
493: // return
494: adest_body=dest_body;
1.1 paf 495: }
496:
497: /// transcode using both charsets
498: void Charset::transcodeToCharset(Pool& pool,
499: const Charset& dest_charset,
500: const void *source_body, size_t source_content_length,
1.6 paf 501: const void *& adest_body, size_t& adest_content_length) const {
1.3 paf 502: if(&dest_charset==this) {
1.6 paf 503: adest_body=source_body;
504: adest_content_length=source_content_length;
505: } else {
506: size_t dest_content_length=source_content_length;
507: unsigned char *dest_body=(unsigned char *)pool.malloc(dest_content_length);
508:
1.11 paf 509: const XMLByte* srcPtr=(XMLByte *)source_body;
510: const XMLByte* srcEnd=(XMLByte *)source_body+source_content_length;
1.6 paf 511:
512: for(XMLByte* outPtr=dest_body; srcPtr<srcEnd; srcPtr++) {
1.10 paf 513: XMLCh curVal = tables.fromTable[*srcPtr];
1.6 paf 514: if(curVal)
1.25 paf 515: *outPtr++=xlatOneTo(curVal, dest_charset.tables, '?');
1.6 paf 516: else {
517: // use the replacement character
518: *outPtr++= '?';
519: }
520: }
1.1 paf 521:
1.6 paf 522: adest_body=dest_body;
523: adest_content_length=dest_content_length;
524: }
1.1 paf 525: }
526:
527: #ifdef XML
1.10 paf 528: static int xml256CharEncodingInputFunc (
529: unsigned char *out,
530: int *outlen,
531: const unsigned char *in,
532: int *inlen,
533: void *info) {
534: return transcodeToUTF8(
1.21 paf 535: in, *(size_t*)inlen,
536: out, *(size_t*)outlen,
1.10 paf 537: *(const Charset::Tables *)info);
538: }
539:
540: static int xml256CharEncodingOutputFunc (
541: unsigned char *out,
542: int *outlen,
543: const unsigned char *in,
544: int *inlen,
545: void *info) {
546: return transcodeFromUTF8(
1.21 paf 547: in, *(size_t*)inlen,
548: out, *(size_t*)outlen,
1.10 paf 549: *(const Charset::Tables *)info);
550: }
551:
552:
553: void Charset::addEncoding(char *name_cstr) {
554: xmlCharEncodingHandler *handler=
555: (xmlCharEncodingHandler *)malloc(sizeof(xmlCharEncodingHandler));
556: handler->name=name_cstr;
557: handler->input=xml256CharEncodingInputFunc; handler->inputInfo=&tables;
558: handler->output=xml256CharEncodingOutputFunc; handler->outputInfo=&tables;
559:
560: xmlRegisterCharEncodingHandler(handler);
561: }
562:
563: void Charset::initTranscoder(const String *source, const char *name_cstr) {
1.15 paf 564: ftranscoder=xmlFindCharEncodingHandler(name_cstr);
565: transcoder(source); // check right way
566: }
567:
568: xmlCharEncodingHandler *Charset::transcoder(const String *source) {
569: if(!ftranscoder)
1.23 paf 570: throw Exception("parser.runtime",
1.10 paf 571: source,
572: "unsupported encoding");
1.15 paf 573: return ftranscoder;
1.10 paf 574: }
575:
1.14 paf 576: const char *Charset::transcode_cstr(xmlChar *s) {
1.13 paf 577: if(!s)
1.14 paf 578: return "";
1.8 paf 579:
1.14 paf 580: int inlen=strlen((const char *)s);
1.8 paf 581: int outlen=inlen+1; // max
582: char *out=(char *)malloc(outlen*sizeof(char));
583:
1.30 paf 584: int error;
1.17 paf 585: if(xmlCharEncodingOutputFunc output=transcoder(0)->output) {
1.30 paf 586: error=output(
1.17 paf 587: (unsigned char*)out, &outlen,
588: (const unsigned char*)s, &inlen,
589: transcoder(0)->outputInfo);
1.30 paf 590: } else {
591: memcpy(out, s, outlen=inlen);
592: error=0;
593: }
594: if(error<0)
1.23 paf 595: throw Exception(0,
1.8 paf 596: 0,
1.30 paf 597: "transcode_cstr failed (%d)", error);
1.8 paf 598:
1.30 paf 599: out[outlen/*surely would be less then on input*/]=0;
1.8 paf 600: return out;
1.14 paf 601: }
1.31 paf 602: String& Charset::transcode(xmlChar *s
603: #ifndef NO_STRING_ORIGIN
604: , const String *origin
605: #endif
606: ) {
607: String& result=*NEW String(pool());
608: result.APPEND_CLEAN(transcode_cstr(s), 0/*auto-size*/, origin->origin().file, origin->origin().line);
609: return result;
1.14 paf 610: }
611: const char *Charset::transcode_cstr(GdomeDOMString *s) {
612: return s?transcode_cstr(BAD_CAST s->str):"";
1.1 paf 613: }
1.31 paf 614: String& Charset::transcode(GdomeDOMString *s
615: #ifndef NO_STRING_ORIGIN
616: , const String *origin
617: #endif
618: ) {
619: String& result=*NEW String(pool());
620: result.APPEND_CLEAN(transcode_cstr(s), 0/*auto-size*/, origin->origin().file, origin->origin().line);
621: return result;
1.1 paf 622: }
623:
1.8 paf 624: /// @test less memory using -maybe- xmlParserInputBufferCreateMem
1.24 paf 625: xmlChar *Charset::transcode_buf2xchar(const char *buf, size_t buf_size) {
1.30 paf 626: unsigned char *out;
627: int outlen;
628: int error;
1.17 paf 629: if(xmlCharEncodingInputFunc input=transcoder(0)->input) {
1.32 paf 630: outlen=buf_size*6/*max*/;
631: out=(unsigned char*)malloc((outlen+1)*sizeof(unsigned char));
1.30 paf 632: error=input(
1.17 paf 633: out, &outlen,
634: (const unsigned char *)buf, (int *)&buf_size,
635: transcoder(0)->inputInfo);
1.30 paf 636: } else {
637: outlen=buf_size;
1.32 paf 638: out=(unsigned char*)malloc((outlen+1)*sizeof(unsigned char));
1.30 paf 639: memcpy(out, buf, outlen);
640: error=0;
641: }
1.17 paf 642:
1.30 paf 643: if(error<0)
1.23 paf 644: throw Exception(0,
1.8 paf 645: 0,
1.30 paf 646: "transcode_buf failed (%d)", error);
1.8 paf 647:
1.30 paf 648: out[outlen/*surely would be less then on input*/]=0;
1.24 paf 649: return (xmlChar *)out;
650: }
651: GdomeDOMString_auto_ptr Charset::transcode_buf2dom(const char *buf, size_t buf_size) {
652: return GdomeDOMString_auto_ptr((gchar*)transcode_buf2xchar(buf, buf_size));
1.1 paf 653: }
1.12 paf 654: GdomeDOMString_auto_ptr Charset::transcode(const String& s) {
1.1 paf 655: const char *cstr=s.cstr(String::UL_UNSPECIFIED);
656:
1.24 paf 657: return transcode_buf2dom(cstr, strlen(cstr));
1.1 paf 658: }
659: #endif
E-mail: