Subversion Repositories Programming Utils

Rev

Rev 114 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
113 rm5248 1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
114 rm5248 17
#include <cstring>
113 rm5248 18
#include <log4cxx/logstring.h>
19
#include <log4cxx/helpers/charsetdecoder.h>
20
#include <log4cxx/helpers/bytebuffer.h>
21
#include <log4cxx/helpers/exception.h>
22
#include <log4cxx/helpers/mutex.h>
23
#include <log4cxx/helpers/synchronized.h>
24
#include <log4cxx/helpers/pool.h>
25
#if !defined(LOG4CXX)
26
#define LOG4CXX 1
27
#endif
28
#include <log4cxx/private/log4cxx_private.h>
29
#include <locale.h>
30
#include <log4cxx/helpers/stringhelper.h>
31
#include <log4cxx/helpers/transcoder.h>
32
 
114 rm5248 33
#ifndef LOG4CXX_QT
34
#include <apr_xlate.h>
35
#include <apr_portable.h>
36
#endif
37
 
113 rm5248 38
using namespace log4cxx;
39
using namespace log4cxx::helpers;
40
 
41
IMPLEMENT_LOG4CXX_OBJECT(CharsetDecoder)
42
 
43
 
44
namespace log4cxx
45
{
114 rm5248 46
    namespace helpers {
113 rm5248 47
 
48
#if APR_HAS_XLATE
114 rm5248 49
    /**
113 rm5248 50
           *  Converts from an arbitrary encoding to LogString
51
           *    using apr_xlate.  Requires real iconv implementation,
52
         *    apr-iconv will crash in use.
53
           */
114 rm5248 54
    class APRCharsetDecoder : public CharsetDecoder
55
    {
56
    public:
57
        /**
113 rm5248 58
            *  Creates a new instance.
59
            *  @param frompage name of source encoding.
60
            */
114 rm5248 61
        APRCharsetDecoder(const LogString& frompage) : pool(), mutex(pool) {
113 rm5248 62
#if LOG4CXX_LOGCHAR_IS_WCHAR
114 rm5248 63
            const char* topage = "WCHAR_T";
113 rm5248 64
#endif
65
#if LOG4CXX_LOGCHAR_IS_UTF8
114 rm5248 66
            const char* topage = "UTF-8";
113 rm5248 67
#endif
68
#if LOG4CXX_LOGCHAR_IS_UNICHAR
114 rm5248 69
            const char* topage = "UTF-16";
113 rm5248 70
#endif
114 rm5248 71
            std::string fpage(Transcoder::encodeCharsetName(frompage));
72
            apr_status_t stat = apr_xlate_open(&convset,
73
                                               topage,
74
                                               fpage.c_str(),
75
                                               pool.getAPRPool());
76
            if (stat != APR_SUCCESS) {
77
                throw IllegalArgumentException(frompage);
78
            }
79
        }
113 rm5248 80
 
114 rm5248 81
        /**
113 rm5248 82
            *  Destructor.
83
            */
114 rm5248 84
        virtual ~APRCharsetDecoder() {
85
        }
113 rm5248 86
 
114 rm5248 87
        virtual log4cxx_status_t decode(ByteBuffer& in,
88
                                        LogString& out) {
89
            enum { BUFSIZE = 256 };
90
            logchar buf[BUFSIZE];
91
            const apr_size_t initial_outbytes_left = BUFSIZE * sizeof(logchar);
92
            apr_status_t stat = APR_SUCCESS;
93
            if (in.remaining() == 0) {
94
                size_t outbytes_left = initial_outbytes_left;
95
                {
96
                    synchronized sync(mutex);
97
                    stat = apr_xlate_conv_buffer((apr_xlate_t*) convset,
98
                                                 NULL, NULL, (char*) buf, &outbytes_left);
99
                }
100
                out.append(buf, (initial_outbytes_left - outbytes_left)/sizeof(logchar));
101
            } else {
102
                while(in.remaining() > 0 && stat == APR_SUCCESS) {
103
                    size_t inbytes_left = in.remaining();
104
                    size_t initial_inbytes_left = inbytes_left;
105
                    size_t pos = in.position();
106
                    apr_size_t outbytes_left = initial_outbytes_left;
113 rm5248 107
                    {
108
                        synchronized sync(mutex);
109
                        stat = apr_xlate_conv_buffer((apr_xlate_t*) convset,
114 rm5248 110
                                                     in.data() + pos,
111
                                                     &inbytes_left,
112
                                                     (char*) buf,
113
                                                     &outbytes_left);
113 rm5248 114
                    }
114 rm5248 115
                    out.append(buf, (initial_outbytes_left - outbytes_left)/sizeof(logchar));
116
                    in.position(pos + (initial_inbytes_left - inbytes_left));
117
                }
118
            }
119
            return stat;
120
        }
113 rm5248 121
 
114 rm5248 122
    private:
123
        APRCharsetDecoder(const APRCharsetDecoder&);
124
        APRCharsetDecoder& operator=(const APRCharsetDecoder&);
125
        log4cxx::helpers::Pool pool;
126
        Mutex mutex;
127
        apr_xlate_t *convset;
128
    };
129
 
113 rm5248 130
#endif
131
 
132
#if LOG4CXX_LOGCHAR_IS_WCHAR && LOG4CXX_HAS_MBSRTOWCS
114 rm5248 133
    /**
113 rm5248 134
          *    Converts from the default multi-byte string to
135
          *        LogString using mbstowcs.
136
          *
137
          */
114 rm5248 138
    class MbstowcsCharsetDecoder : public CharsetDecoder
139
    {
140
    public:
141
        MbstowcsCharsetDecoder() {
142
        }
113 rm5248 143
 
114 rm5248 144
        virtual ~MbstowcsCharsetDecoder() {
145
        }
113 rm5248 146
 
114 rm5248 147
    private:
148
        inline log4cxx_status_t append(LogString& out, const wchar_t* buf) {
149
            out.append(buf);
150
            return LOG4CXX_SUCCESS;
151
        }
113 rm5248 152
 
114 rm5248 153
        virtual log4cxx_status_t decode(ByteBuffer& in,
154
                                        LogString& out) {
155
            log4cxx_status_t stat = LOG4CXX_SUCCESS;
156
            enum { BUFSIZE = 256 };
157
            wchar_t buf[BUFSIZE];
113 rm5248 158
 
114 rm5248 159
            mbstate_t mbstate;
160
            memset(&mbstate, 0, sizeof(mbstate));
113 rm5248 161
 
114 rm5248 162
            while(in.remaining() > 0) {
163
                size_t requested = in.remaining();
164
                if (requested > BUFSIZE - 1) {
165
                    requested = BUFSIZE - 1;
166
                }
113 rm5248 167
 
114 rm5248 168
                memset(buf, 0, BUFSIZE*sizeof(wchar_t));
169
                const char* src = in.current();
170
                if(*src == 0) {
171
                    out.append(1, (logchar) 0);
172
                    in.position(in.position() + 1);
173
                } else {
174
                    size_t converted = mbsrtowcs(buf,
175
                                                 &src,
176
                                                 requested,
177
                                                 &mbstate);
178
                    if (converted == (size_t) -1) {
179
                        stat = LOG4CXX_BADARG;
180
                        in.position(src - in.data());
181
                        break;
182
                    } else {
183
                        stat = append(out, buf);
184
                        in.position(in.position() + converted);
185
                    }
186
                }
187
            }
188
            return stat;
189
        }
113 rm5248 190
 
191
 
192
 
114 rm5248 193
    private:
194
        MbstowcsCharsetDecoder(const MbstowcsCharsetDecoder&);
195
        MbstowcsCharsetDecoder& operator=(const MbstowcsCharsetDecoder&);
196
    };
113 rm5248 197
#endif
198
 
199
 
114 rm5248 200
    /**
113 rm5248 201
          *    Decoder used when the external and internal charsets
202
          *    are the same.
203
          *
204
          */
114 rm5248 205
    class TrivialCharsetDecoder : public CharsetDecoder
206
    {
207
    public:
208
        TrivialCharsetDecoder() {
209
        }
113 rm5248 210
 
114 rm5248 211
        virtual ~TrivialCharsetDecoder() {
212
        }
113 rm5248 213
 
114 rm5248 214
        virtual log4cxx_status_t decode(ByteBuffer& in,
215
                                        LogString& out) {
216
            size_t remaining = in.remaining();
217
            if( remaining > 0) {
218
                const logchar* src = (const logchar*) (in.data() + in.position());
219
                size_t count = remaining / sizeof(logchar);
220
                out.append(src, count);
221
                in.position(in.position() + remaining);
222
            }
223
            return LOG4CXX_SUCCESS;
224
        }
113 rm5248 225
 
226
 
227
 
114 rm5248 228
    private:
229
        TrivialCharsetDecoder(const TrivialCharsetDecoder&);
230
        TrivialCharsetDecoder& operator=(const TrivialCharsetDecoder&);
231
    };
113 rm5248 232
 
233
 
234
#if LOG4CXX_LOGCHAR_IS_UTF8
114 rm5248 235
    typedef TrivialCharsetDecoder UTF8CharsetDecoder;
113 rm5248 236
#else
114 rm5248 237
    /**
113 rm5248 238
*    Converts from UTF-8 to std::wstring
239
*
240
*/
114 rm5248 241
    class UTF8CharsetDecoder : public CharsetDecoder
242
    {
243
    public:
244
        UTF8CharsetDecoder() {
245
        }
113 rm5248 246
 
114 rm5248 247
        virtual ~UTF8CharsetDecoder() {
248
        }
113 rm5248 249
 
114 rm5248 250
    private:
251
        virtual log4cxx_status_t decode(ByteBuffer& in,
252
                                        LogString& out) {
253
            if (in.remaining() > 0) {
254
                std::string tmp(in.current(), in.remaining());
255
                std::string::const_iterator iter = tmp.begin();
256
                while(iter != tmp.end()) {
257
                    unsigned int sv = Transcoder::decode(tmp, iter);
258
                    if (sv == 0xFFFF) {
259
                        size_t offset = iter - tmp.begin();
260
                        in.position(in.position() + offset);
261
                        return LOG4CXX_BADARG;
262
                    } else {
263
                        Transcoder::encode(sv, out);
264
                    }
265
                }
266
                in.position(in.limit());
267
            }
268
            return LOG4CXX_SUCCESS;
113 rm5248 269
        }
270
 
114 rm5248 271
    private:
113 rm5248 272
        UTF8CharsetDecoder(const UTF8CharsetDecoder&);
273
        UTF8CharsetDecoder& operator=(const UTF8CharsetDecoder&);
114 rm5248 274
    };
113 rm5248 275
#endif
276
 
114 rm5248 277
    /**
113 rm5248 278
*    Converts from ISO-8859-1 to LogString.
279
*
280
*/
114 rm5248 281
    class ISOLatinCharsetDecoder : public CharsetDecoder
282
    {
283
    public:
284
        ISOLatinCharsetDecoder() {
285
        }
113 rm5248 286
 
114 rm5248 287
        virtual ~ISOLatinCharsetDecoder() {
288
        }
113 rm5248 289
 
114 rm5248 290
    private:
291
        virtual log4cxx_status_t decode(ByteBuffer& in,
292
                                        LogString& out) {
293
            if (in.remaining() > 0) {
113 rm5248 294
 
114 rm5248 295
                const unsigned char* src = (unsigned char*) in.current();
296
                const unsigned char* srcEnd = src + in.remaining();
297
                while(src < srcEnd) {
298
                    unsigned int sv = *(src++);
299
                    Transcoder::encode(sv, out);
300
                }
301
                in.position(in.limit());
302
            }
303
            return LOG4CXX_SUCCESS;
113 rm5248 304
        }
305
 
306
 
307
 
114 rm5248 308
    private:
113 rm5248 309
        ISOLatinCharsetDecoder(const ISOLatinCharsetDecoder&);
310
        ISOLatinCharsetDecoder& operator=(const ISOLatinCharsetDecoder&);
114 rm5248 311
    };
113 rm5248 312
 
313
 
114 rm5248 314
    /**
113 rm5248 315
*    Converts from US-ASCII to LogString.
316
*
317
*/
114 rm5248 318
    class USASCIICharsetDecoder : public CharsetDecoder
319
    {
320
    public:
321
        USASCIICharsetDecoder() {
322
        }
113 rm5248 323
 
114 rm5248 324
        virtual ~USASCIICharsetDecoder() {
325
        }
113 rm5248 326
 
114 rm5248 327
    private:
113 rm5248 328
 
114 rm5248 329
        virtual log4cxx_status_t decode(ByteBuffer& in,
330
                                        LogString& out) {
331
            log4cxx_status_t stat = LOG4CXX_SUCCESS;
332
            if (in.remaining() > 0) {
113 rm5248 333
 
114 rm5248 334
                const unsigned char* src = (unsigned char*) in.current();
335
                const unsigned char* srcEnd = src + in.remaining();
336
                while(src < srcEnd) {
337
                    unsigned char sv = *src;
338
                    if (sv < 0x80) {
339
                        src++;
340
                        Transcoder::encode(sv, out);
341
                    } else {
342
                        stat = LOG4CXX_BADARG;
343
                        break;
344
                    }
345
                }
346
                in.position(src - (const unsigned char*) in.data());
347
            }
348
            return stat;
113 rm5248 349
        }
350
 
351
 
352
 
114 rm5248 353
    private:
113 rm5248 354
        USASCIICharsetDecoder(const USASCIICharsetDecoder&);
355
        USASCIICharsetDecoder& operator=(const USASCIICharsetDecoder&);
114 rm5248 356
    };
113 rm5248 357
 
114 rm5248 358
    /**
113 rm5248 359
           *    Charset decoder that uses an embedded CharsetDecoder consistent
360
           *     with current locale settings.
361
           */
114 rm5248 362
    class LocaleCharsetDecoder : public CharsetDecoder {
363
    public:
364
        LocaleCharsetDecoder() : pool(), mutex(pool), decoder(), encoding() {
365
        }
366
        virtual ~LocaleCharsetDecoder() {
367
        }
368
        virtual log4cxx_status_t decode(ByteBuffer& in,
369
                                        LogString& out) {
370
            const char* p = in.current();
371
            size_t i = in.position();
113 rm5248 372
#if !LOG4CXX_CHARSET_EBCDIC                  
114 rm5248 373
            for (; i < in.limit() && ((unsigned int) *p) < 0x80; i++, p++) {
374
                out.append(1, *p);
375
            }
376
            in.position(i);
113 rm5248 377
#endif                  
114 rm5248 378
            if (i < in.limit()) {
379
                Pool subpool;
380
                //const char* enc = apr_os_locale_encoding(subpool.getAPRPool());
381
                //RM5248 no idea what this should be
382
                const char* enc = "UTF-8";
383
                {
384
                    synchronized sync(mutex);
385
                    if (enc == 0) {
386
                        if (decoder == 0) {
387
                            encoding = "C";
388
                            decoder = new USASCIICharsetDecoder();
389
                        }
390
                    } else if (encoding != enc) {
391
                        encoding = enc;
392
                        try {
393
                            LogString e;
394
                            Transcoder::decode(encoding, e);
395
                            decoder = getDecoder(e);
396
                        } catch (IllegalArgumentException& ex) {
397
                            decoder = new USASCIICharsetDecoder();
398
                        }
399
                    }
400
                }
401
                return decoder->decode(in, out);
402
            }
403
            return LOG4CXX_SUCCESS;
404
        }
405
    private:
406
        Pool pool;
407
        Mutex mutex;
408
        CharsetDecoderPtr decoder;
409
        std::string encoding;
410
    };
113 rm5248 411
 
412
 
413
 
114 rm5248 414
    } // namespace helpers
113 rm5248 415
 
416
}  //namespace log4cxx
417
 
418
 
419
CharsetDecoder::CharsetDecoder() {
420
}
421
 
422
 
423
CharsetDecoder::~CharsetDecoder() {
424
}
425
 
426
CharsetDecoder* CharsetDecoder::createDefaultDecoder() {
427
#if LOG4CXX_CHARSET_UTF8
114 rm5248 428
    return new UTF8CharsetDecoder();
113 rm5248 429
#elif LOG4CXX_CHARSET_ISO88591 || defined(_WIN32_WCE)
114 rm5248 430
    return new ISOLatinCharsetDecoder();
113 rm5248 431
#elif LOG4CXX_CHARSET_USASCII
114 rm5248 432
    return new USASCIICharsetDecoder();
113 rm5248 433
#elif LOG4CXX_LOGCHAR_IS_WCHAR && LOG4CXX_HAS_MBSRTOWCS
434
    return new MbstowcsCharsetDecoder();
435
#else
436
    return new LocaleCharsetDecoder();
437
#endif
438
}
439
 
440
CharsetDecoderPtr CharsetDecoder::getDefaultDecoder() {
441
    static CharsetDecoderPtr decoder(createDefaultDecoder());
442
    //
443
    //  if invoked after static variable destruction
444
    //     (if logging is called in the destructor of a static object)
445
    //     then create a new decoder.
446
    //
447
    if (decoder == 0) {
114 rm5248 448
        return createDefaultDecoder();
113 rm5248 449
    }
450
    return decoder;
451
}
452
 
453
CharsetDecoderPtr CharsetDecoder::getUTF8Decoder() {
454
    static CharsetDecoderPtr decoder(new UTF8CharsetDecoder());
455
    //
456
    //  if invoked after static variable destruction
457
    //     (if logging is called in the destructor of a static object)
458
    //     then create a new decoder.
459
    //
460
    if (decoder == 0) {
114 rm5248 461
        return new UTF8CharsetDecoder();
113 rm5248 462
    }
463
    return decoder;
464
}
465
 
466
CharsetDecoderPtr CharsetDecoder::getISOLatinDecoder() {
467
    return new ISOLatinCharsetDecoder();
468
}
469
 
470
 
471
CharsetDecoderPtr CharsetDecoder::getDecoder(const LogString& charset) {
472
    if (StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("UTF-8"), LOG4CXX_STR("utf-8")) ||
114 rm5248 473
            StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("UTF8"), LOG4CXX_STR("utf8"))) {
113 rm5248 474
        return new UTF8CharsetDecoder();
475
    } else if (StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("C"), LOG4CXX_STR("c")) ||
114 rm5248 476
               charset == LOG4CXX_STR("646") ||
477
               StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("US-ASCII"), LOG4CXX_STR("us-ascii")) ||
478
               StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("ISO646-US"), LOG4CXX_STR("iso646-US")) ||
479
               StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("ANSI_X3.4-1968"), LOG4CXX_STR("ansi_x3.4-1968"))) {
113 rm5248 480
        return new USASCIICharsetDecoder();
481
    } else if (StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("ISO-8859-1"), LOG4CXX_STR("iso-8859-1")) ||
114 rm5248 482
               StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("ISO-LATIN-1"), LOG4CXX_STR("iso-latin-1"))) {
113 rm5248 483
        return new ISOLatinCharsetDecoder();
484
    }
115 rm5248 485
 
486
#ifdef LOG4CXX_QT
487
    //RM5248 not sure what this should be
488
    return new UTF8CharsetDecoder();
489
#elif APR_HAS_XLATE || !defined(_WIN32)
113 rm5248 490
    return new APRCharsetDecoder(charset);
491
#else    
492
    throw IllegalArgumentException(charset);
493
#endif
494
}
495
 
496
 
497
 
498
 
499
 
500