Annotation of parser3/src/main/pa_charset.C, revision 1.4
1.1 paf 1: /** @file
2: Parser: Charset connection implementation.
3:
1.4 ! paf 4: Copyright(c) 2001 ArtLebedev Group(http://www.artlebedev.com)
! 5: Author: Alexander Petrosyan<paf@design.ru>(http://paf.design.ru)
1.1 paf 6:
1.4 ! paf 7: $Id: pa_charset.C,v 1.3 2001/12/15 21:49:18 paf Exp $
1.1 paf 8: */
9:
10: #include "pa_charset.h"
11: //#include "pa_exception.h"
12: //#include "pa_common.h"
13: //#include "pa_threads.h"
14:
15: #ifdef XML
1.4 ! paf 16: # include<util/TransENameMap.hpp>
! 17: # include<util/XML256TableTranscoder.hpp>
! 18: # include<util/PlatformUtils.hpp>
! 19: # include<PlatformSupport/XalanTranscodingServices.hpp>
1.1 paf 20: #endif
21:
22: // globals
23:
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: #ifdef XML
81: template <class TType> class ENameMapFor2 : public ENameMap {
1.4 ! paf 82: public:
1.1 paf 83: // -----------------------------------------------------------------------
84: // Constructors and Destructor
85: // -----------------------------------------------------------------------
86: ENameMapFor2(
87: const XMLCh* const encodingName
88: , const XMLCh* const fromTable
89: , const XMLTransService::TransRec* const toTable
90: , const unsigned int toTableSize
1.4 ! paf 91: ): ENameMap(encodingName),
1.1 paf 92: ffromTable(fromTable),
93: ftoTable(toTable),
94: ftoTableSize(toTableSize) {}
95:
96: // -----------------------------------------------------------------------
97: // Implementation of virtual factory method
98: // -----------------------------------------------------------------------
99: virtual XMLTranscoder* makeNew(const unsigned int blockSize) const {
100: return new TType(
101: getKey(),
102: blockSize,
103: ffromTable,
104: ftoTable, ftoTableSize);
105: }
106: private:
107: const XMLCh* const ffromTable;
108: const XMLTransService::TransRec* const ftoTable;
109: const unsigned int ftoTableSize;
110:
1.4 ! paf 111: private:
1.1 paf 112: // -----------------------------------------------------------------------
113: // Unimplemented constructors and operators
114: // -----------------------------------------------------------------------
115: ENameMapFor2();
116: ENameMapFor2(const ENameMapFor2<TType>&);
117: void operator=(const ENameMapFor2<TType>&);
118: };
119:
120: class XML256TableTranscoder2 : public XML256TableTranscoder {
121: public :
122: XML256TableTranscoder2(
123: const XMLCh* const encodingName
124: , const unsigned int blockSize
125: , const XMLCh* const fromTable
126: , const XMLTransService::TransRec* const toTable
127: , const unsigned int toTableSize
128: ) : XML256TableTranscoder(encodingName, blockSize, fromTable, toTable, toTableSize) {}
129:
1.4 ! paf 130: private:
1.1 paf 131: XML256TableTranscoder2();
132: XML256TableTranscoder2(const XML256TableTranscoder2&);
133: void operator=(const XML256TableTranscoder2&);
134: };
135: #endif
136:
137: // methods
138:
139: extern "C" unsigned char pcre_default_tables[]; // pcre/chartables.c
1.4 ! paf 140: Charset::Charset(Pool& apool, const String& aname, const String *file_spec): Pooled(apool),
1.1 paf 141: fname(apool) {
142: // fname
1.2 paf 143: char *name_cstr=(char *)malloc(aname.size()+1);
144: memcpy(name_cstr, aname.cstr(String::UL_AS_IS), aname.size()+1);
1.1 paf 145: fname.APPEND_CLEAN(name_cstr, aname.size(), 0, 0);
146:
147: if(file_spec) {
148: fisUTF8=false;
149: loadDefinition(*file_spec);
150: #ifdef XML
151: addEncoding(name_cstr);
152: #endif
153: } else {
154: fisUTF8=true;
1.4 ! paf 155: // grab default onces [for UTF-8 so to be able to make a-z =>A-Z
1.1 paf 156: memcpy(pcre_tables, pcre_default_tables, sizeof(pcre_tables));
157: }
158:
159: #ifdef XML
160: initTranscoder(&aname, name_cstr);
161: #endif
162: }
163:
164: Charset::~Charset() {
165: #ifdef XML
166: delete transcoder;
167: #endif
168: }
169:
170: void Charset::loadDefinition(const String& file_spec) {
171: // pcre_tables
172: // lowcase, flipcase, bits digit+word+whitespace, masks
173:
174: // must not move this inside of prepare_case_tables
175: // don't know the size there
176: memset(pcre_tables, 0, sizeof(pcre_tables));
177: prepare_case_tables(pcre_tables);
1.4 ! paf 178: cstr2ctypes(pcre_tables,(const unsigned char *)"*+?{^.$|()[", ctype_meta);
1.1 paf 179:
180: // charset
181: memset(fromTable, 0, sizeof(fromTable));
182: toTable=(XMLTransService::TransRec *)calloc(
183: sizeof(XMLTransService::TransRec)*MAX_CHARSET_UNI_CODES);
184: toTableSize=0;
185: // strangly vital
186: toTable[toTableSize].intCh=0;
187: toTable[toTableSize].extCh=(XMLByte)0;
188: toTableSize++;
189:
190: // loading text
191: char *data=file_read_text(pool(), file_spec);
192:
193: // ignore header
194: getrow(&data);
195:
196: // parse cells
197: char *row;
198: while(row=getrow(&data)) {
199: // remove empty&comment lines
200: if(!*row || *row=='#')
201: continue;
202:
203: // char white-space digit hex-digit letter word lowercase unicode1 unicode2
204: unsigned int c=0;
205: char *cell;
206: for(int column=0; cell=lsplit(&row, '\t'); column++) {
207: switch(column) {
208: case 0: c=to_wchar_code(cell); break;
209: // pcre_tables
210: case 1: element2ctypes(c, to_bool(cell), pcre_tables, ctype_space, cbit_space); break;
211: case 2: element2ctypes(c, to_bool(cell), pcre_tables, ctype_digit, cbit_digit); break;
212: case 3: element2ctypes(c, to_bool(cell), pcre_tables, ctype_xdigit); break;
213: case 4: element2ctypes(c, to_bool(cell), pcre_tables, ctype_letter); break;
214: case 5: element2ctypes(c, to_bool(cell), pcre_tables, ctype_word, cbit_word); break;
215: case 6: element2case(c, to_wchar_code(cell), pcre_tables); break;
216: case 7:
217: case 8:
218: // charset
219: if(toTableSize>MAX_CHARSET_UNI_CODES)
220: throw Exception(0, 0,
221: &file_spec,
222: "charset must contain not more then %d unicode values", MAX_CHARSET_UNI_CODES);
223:
224: XMLCh unicode=(XMLCh)to_wchar_code(cell);
225: if(!unicode && column==7/*unicode1 column*/)
226: unicode=(XMLCh)c;
227: if(unicode) {
228: if(!fromTable[c])
229: fromTable[c]=unicode;
230: toTable[toTableSize].intCh=unicode;
231: toTable[toTableSize].extCh=(XMLByte)c;
232: toTableSize++;
233: }
234: break;
235: }
236: }
237: };
238:
239: // sort by the Unicode code point
240: sort_ToTable();
241: }
242:
243: #ifdef XML
244: void Charset::addEncoding(const char *name_cstr) {
245: // addEncoding
246: XalanDOMString sencoding(name_cstr);
247: const XMLCh* const auto_encoding_cstr=sencoding.c_str();
248: int size=sizeof(XMLCh)*(sencoding.size()+1);
249: XMLCh* pool_encoding_cstr=(XMLCh*)malloc(size);
250: memcpy(pool_encoding_cstr, auto_encoding_cstr, size);
251: XMLString::upperCase(pool_encoding_cstr);
252:
253: XMLPlatformUtils::fgTransService->addEncoding(
254: pool_encoding_cstr,
255: new ENameMapFor2<XML256TableTranscoder2>(
256: pool_encoding_cstr
257: , fromTable
258: , toTable
259: , toTableSize
260: ));
261: }
262:
263: void Charset::initTranscoder(const String *source, const char *name_cstr) {
264: XMLTransService::Codes resValue;
265: transcoder=XMLPlatformUtils::fgTransService->makeNewTranscoderFor(name_cstr, resValue, 60);
266: if(!transcoder)
267: throw Exception(0, 0,
268: source,
269: "unsupported encoding");
270: }
271: #endif
272:
273: static int sort_cmp_Trans_rec_intCh(const void *a, const void *b) {
274: return
275: static_cast<const Charset_TransRec *>(a)->intCh-
276: static_cast<const Charset_TransRec *>(b)->intCh;
277: }
278:
279: void Charset::sort_ToTable() {
280: _qsort(toTable, toTableSize, sizeof(*toTable),
281: sort_cmp_Trans_rec_intCh);
282: //FILE *f=fopen("c:\\temp\\a", "wb");
283: //fwrite(toTable, toTableSize, sizeof(*toTable), f);
284: //fclose(f);
285: }
286:
287: XMLByte Charset::xlatOneTo(const XMLCh toXlat) const {
288: unsigned int lowOfs = 0;
289: unsigned int hiOfs = toTableSize - 1;
290: XMLByte curByte = 0;
291: do {
292: // Calc the mid point of the low and high offset.
1.4 ! paf 293: const unsigned int midOfs =((hiOfs - lowOfs) / 2)+lowOfs;
1.1 paf 294:
295: // If our test char is greater than the mid point char, then
296: // we move up to the upper half. Else we move to the lower
297: // half. If its equal, then its our guy.
1.4 ! paf 298: if(toXlat>toTable[midOfs].intCh)
1.1 paf 299: lowOfs = midOfs;
1.4 ! paf 300: else if(toXlat<toTable[midOfs].intCh)
1.1 paf 301: hiOfs = midOfs;
302: else
303: return toTable[midOfs].extCh;
1.4 ! paf 304: } while(lowOfs+1<hiOfs);
1.1 paf 305:
306: return '?';
307: }
308:
309: void Charset::transcode(Pool& pool,
310: const Charset& source_charset, const void *source_body, size_t source_content_length,
311: const Charset& dest_charset, const void *& dest_body, size_t& dest_content_length
312: ) {
1.4 ! paf 313: if(!source_content_length) {
! 314: dest_body=0;
! 315: dest_content_length=0;
! 316: return;
! 317: }
! 318:
1.1 paf 319: switch((source_charset.isUTF8()?0x10:0x00)|(dest_charset.isUTF8()?0x01:0x00)) {
320: default: // 0x00
321: source_charset.transcodeToCharset(pool, dest_charset,
322: source_body, source_content_length,
323: dest_body, dest_content_length);
324: break;
325: case 0x01:
326: source_charset.transcodeToUTF8(pool,
327: source_body, source_content_length,
328: dest_body, dest_content_length);
329: break;
330: case 0x10:
331: dest_charset.transcodeFromUTF8(pool,
332: source_body, source_content_length,
333: dest_body, dest_content_length);
334: break;
335: case 0x11:
336: dest_body=source_body;
337: dest_content_length=source_content_length;
338: break;
339: }
340: }
341:
342: // ---------------------------------------------------------------------------
343: // Local static data
344: //
345: // gUTFBytes
346: // A list of counts of trailing bytes for each initial byte in the input.
347: //
348: // gUTFOffsets
349: // A list of values to offset each result char type, according to how
350: // many source bytes when into making it.
351: //
352: // gFirstByteMark
353: // A list of values to mask onto the first byte of an encoded sequence,
354: // indexed by the number of bytes used to create the sequence.
355: // ---------------------------------------------------------------------------
356: static const XMLByte gUTFBytes[0x100] = {
357: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
358: , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
359: , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
360: , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
361: , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
362: , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
363: , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
364: , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
365: , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
366: , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
367: , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
368: , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
369: , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
370: , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
371: , 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
372: , 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
373: };
374:
375: static const uint gUTFOffsets[6] = {
376: 0, 0x3080, 0xE2080, 0x3C82080, 0xFA082080, 0x82082080
377: };
378:
379: static const XMLByte gFirstByteMark[7] = {
380: 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
381: };
382:
383: /// @todo not so memory-hungry with prescan
384: void Charset::transcodeToUTF8(Pool& pool,
385: const void *source_body, size_t source_content_length,
386: const void *& adest_body, size_t& adest_content_length) const {
387:
388: size_t dest_content_length=0;
389: XMLByte *dest_body=(XMLByte*)pool.malloc(source_content_length*6/*so that surly enough*/);
390:
391: const XMLByte* srcPtr=(const XMLByte*)source_body;
392: const XMLByte* srcEnd=(const XMLByte*)source_body+source_content_length;
393: XMLByte* outPtr=dest_body;
394:
1.4 ! paf 395: while(srcPtr<srcEnd) {
1.1 paf 396: uint curVal = fromTable[*srcPtr];
397: if(!curVal) {
398: // use the replacement character
1.4 ! paf 399: *outPtr++= '?';
! 400: srcPtr++;
1.1 paf 401: continue;
402: }
403:
404: // Figure out how many bytes we need
405: unsigned int encodedBytes;
1.4 ! paf 406: if(curVal<0x80)
1.1 paf 407: encodedBytes = 1;
1.4 ! paf 408: else if(curVal<0x800)
1.1 paf 409: encodedBytes = 2;
1.4 ! paf 410: else if(curVal<0x10000)
1.1 paf 411: encodedBytes = 3;
1.4 ! paf 412: else if(curVal<0x200000)
1.1 paf 413: encodedBytes = 4;
1.4 ! paf 414: else if(curVal<0x4000000)
1.1 paf 415: encodedBytes = 5;
1.4 ! paf 416: else if(curVal<= 0x7FFFFFFF)
1.1 paf 417: encodedBytes = 6;
418: else {
419: // use the replacement character
1.4 ! paf 420: *outPtr++= '?';
! 421: srcPtr++;
1.1 paf 422: continue;
423: }
424:
425: // If we cannot fully get this char into the output buffer,
426: // never
427:
428: // We can do it, so update the source index
429: srcPtr++;
430:
431: // And spit out the bytes. We spit them out in reverse order
432: // here, so bump up the output pointer and work down as we go.
1.4 ! paf 433: outPtr+= encodedBytes;
1.1 paf 434: switch(encodedBytes) {
1.4 ! paf 435: case 6: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
! 436: curVal>>= 6;
! 437: case 5: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
! 438: curVal>>= 6;
! 439: case 4: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
! 440: curVal>>= 6;
! 441: case 3: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
! 442: curVal>>= 6;
! 443: case 2: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
! 444: curVal>>= 6;
! 445: case 1: *--outPtr = XMLByte(curVal | gFirstByteMark[encodedBytes]);
1.1 paf 446: }
447:
448: // Add the encoded bytes back in again to indicate we've eaten them
1.4 ! paf 449: outPtr+= encodedBytes;
1.1 paf 450: }
451:
452: // return
453: adest_body=dest_body;
454: adest_content_length=outPtr-dest_body;
455: }
456: void Charset::transcodeFromUTF8(Pool& pool,
457: const void *source_body, size_t source_content_length,
458: const void *& adest_body, size_t& adest_content_length) const {
459: size_t dest_content_length=0;
460: XMLByte *dest_body=(XMLByte*)pool.malloc(source_content_length/*surly enough*/);
461:
462: const XMLByte* srcPtr=(const XMLByte*)source_body;
463: const XMLByte* srcEnd=(const XMLByte*)source_body+source_content_length;
464: XMLByte* outPtr=dest_body;
465:
466: // We now loop until we either run out of input data
1.4 ! paf 467: while(srcPtr<srcEnd) {
1.1 paf 468: // Get the next leading byte out
469: const XMLByte firstByte = *srcPtr;
470:
1.4 ! paf 471: // Special-case ASCII, which is a leading byte value of<= 127
! 472: if(firstByte<= 127) {
! 473: *outPtr++= firstByte;
1.1 paf 474: srcPtr++;
475: continue;
476: }
477:
478: // See how many trailing src bytes this sequence is going to require
479: const unsigned int trailingBytes = gUTFBytes[firstByte];
480:
481: // If there are not enough source bytes to do this one, then we
1.4 ! paf 482: // are done. Note that we done>= here because we are implicitly
1.1 paf 483: // counting the 1 byte we get no matter what.
1.4 ! paf 484: if(srcPtr+trailingBytes>= srcEnd)
1.1 paf 485: break;
486:
487: // Looks ok, so lets build up the value
488: uint tmpVal=0;
489: switch(trailingBytes) {
490: case 5: tmpVal+=*srcPtr++; tmpVal<<=6;
491: case 4: tmpVal+=*srcPtr++; tmpVal<<=6;
492: case 3: tmpVal+=*srcPtr++; tmpVal<<=6;
493: case 2: tmpVal+=*srcPtr++; tmpVal<<=6;
494: case 1: tmpVal+=*srcPtr++; tmpVal<<=6;
495: case 0: tmpVal+=*srcPtr++;
496: break;
497:
498: default:
499: throw Exception(0, 0,
500: 0,
1.4 ! paf 501: "transcodeFromUTF8 error: wrong trailingBytes value(%d)", trailingBytes);
1.1 paf 502: }
503: tmpVal-=gUTFOffsets[trailingBytes];
504:
505: // If it will fit into a single char, then put it in. Otherwise
506: // fail [*encode it as a surrogate pair. If its not valid, use the
507: // replacement char.*]
1.4 ! paf 508: if(!(tmpVal & 0xFFFF0000))
! 509: *outPtr++= xlatOneTo(tmpVal);
1.1 paf 510: else
511: throw Exception(0, 0,
512: 0,
1.4 ! paf 513: "transcodeFromUTF8 error: too big tmpVal(0x%08X)", tmpVal);
1.1 paf 514: }
515:
516: // return
517: adest_body=dest_body;
518: adest_content_length=outPtr-dest_body;
519: }
520:
521: /// transcode using both charsets
522: void Charset::transcodeToCharset(Pool& pool,
523: const Charset& dest_charset,
524: const void *source_body, size_t source_content_length,
1.3 paf 525: const void *& dest_body, size_t& dest_content_length) const {
526: if(&dest_charset==this) {
527: dest_body=source_body;
528: dest_content_length=source_content_length;
529: } else
530: throw Exception(0, 0,
531: 0,
532: "transcodeToCharset not supported(yet)");
1.1 paf 533: /*
534: void *dest_body;
535:
536: dest_body=pool.malloc(dest_content_length=source_content_length);
537: // dummy
538: memset(dest_body, '?', dest_content_length);
539:
540: adest_body=dest_body;*/
541: }
542:
543: #ifdef XML
544: const char *Charset::transcode_cstr(const XalanDOMString& s) {
545: const unsigned int len=s.size()*2;
546: XMLByte* dest=(XMLByte *)malloc((len+1)*sizeof(XMLByte));
547: bool error=true;
548: try {
549: if(transcoder) {
550: unsigned int charsEaten;
551: unsigned int size=transcoder->transcodeTo(
552: s.c_str(), s.length(),
553: dest, len,
554: charsEaten,
555: XMLTranscoder::UnRep_RepChar //UnRep_Throw
556: );
557: dest[size]=0;
558: error=false;
559: }
560: } catch(XMLException& e) {
561: Exception::provide_source(pool(), 0, e);
562: }
1.4 ! paf 563: return(const char *)dest;
1.1 paf 564: }
565: String& Charset::transcode(const XalanDOMString& s) {
566: return *NEW String(pool(), transcode_cstr(s));
567: }
568:
1.4 ! paf 569: std::auto_ptr<XalanDOMString>Charset::transcode_buf(const char *buf, size_t buf_size) {
1.1 paf 570: unsigned int dest_size=0;
571: XMLCh* dest=(XMLCh *)malloc((buf_size+1)*sizeof(XMLCh));
572: unsigned char *charSizes=(unsigned char *)malloc(buf_size*sizeof(unsigned char));
573: XalanDOMString *result;
574: try {
575: if(transcoder) {
576: unsigned int bytesEaten;
577: unsigned int dest_size=transcoder->transcodeFrom(
578: (unsigned char *)buf,
579: (const unsigned int)buf_size,
1.4 ! paf 580: dest,(const unsigned int)buf_size,
1.1 paf 581: bytesEaten,
582: charSizes
583: );
584: result=new XalanDOMString(dest, dest_size);
585: }
586: } catch(XMLException& e) {
587: Exception::provide_source(pool(), 0, e);
588: result=0; //calm, compiler
589: }
590:
591: return std::auto_ptr<XalanDOMString>(result);
592: }
1.4 ! paf 593: std::auto_ptr<XalanDOMString>Charset::transcode(const String& s) {
1.1 paf 594: const char *cstr=s.cstr(String::UL_UNSPECIFIED);
595:
596: return transcode_buf(cstr, strlen(cstr));
597: }
598: #endif
E-mail: