1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Netscape Public License
6
* Version 1.1 (the "License"); you may not use this file except in
7
* compliance with the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/NPL/
10
* Software distributed under the License is distributed on an "AS IS" basis,
11
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
* for the specific language governing rights and limitations under the
15
* The Original Code is Mozilla Communicator client code.
17
* The Initial Developer of the Original Code is
18
* Netscape Communications Corporation.
19
* Portions created by the Initial Developer are Copyright (C) 1998
20
* the Initial Developer. All Rights Reserved.
23
* Pierre Phaneuf <pp@ludusdesign.com>
26
* Alternatively, the contents of this file may be used under the terms of
27
* either the GNU General Public License Version 2 or later (the "GPL"), or
28
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29
* in which case the provisions of the GPL or the LGPL are applicable instead
30
* of those above. If you wish to allow use of your version of this file only
31
* under the terms of either the GPL or the LGPL, and not to allow others to
32
* use your version of this file under the terms of the NPL, indicate your
33
* decision by deleting the provisions above and replace them with the notice
34
* and other provisions required by the GPL or the LGPL. If you do not delete
35
* the provisions above, a recipient may use your version of this file under
36
* the terms of any one of the NPL, the GPL or the LGPL.
38
* ***** END LICENSE BLOCK ***** */
41
#include "nsIComponentManager.h"
42
#include "nsICharRepresentable.h"
43
#include "nsUCSupport.h"
45
static NS_DEFINE_CID(kUnicodeEncodeHelperCID, NS_UNICODEENCODEHELPER_CID);
46
static NS_DEFINE_CID(kUnicodeDecodeHelperCID, NS_UNICODEDECODEHELPER_CID);
48
#define DEFAULT_BUFFER_CAPACITY 16
50
// XXX review the buffer growth limitation code
52
//----------------------------------------------------------------------
53
// Class nsBasicDecoderSupport [implementation]
55
nsBasicDecoderSupport::nsBasicDecoderSupport()
59
nsBasicDecoderSupport::~nsBasicDecoderSupport()
63
//----------------------------------------------------------------------
64
// Interface nsISupports [implementation]
66
NS_IMPL_ADDREF(nsBasicDecoderSupport)
67
NS_IMPL_RELEASE(nsBasicDecoderSupport)
69
NS_IMPL_QUERY_INTERFACE2(nsBasicDecoderSupport, nsIUnicodeDecoder, nsIBasicDecoder)
71
NS_IMPL_QUERY_INTERFACE1(nsBasicDecoderSupport, nsIUnicodeDecoder)
74
//----------------------------------------------------------------------
75
// Interface nsIUnicodeDecoder [implementation]
77
//----------------------------------------------------------------------
78
// Class nsBufferDecoderSupport [implementation]
80
nsBufferDecoderSupport::nsBufferDecoderSupport(PRUint32 aMaxLengthFactor)
81
: nsBasicDecoderSupport(),
82
mMaxLengthFactor(aMaxLengthFactor)
84
mBufferCapacity = DEFAULT_BUFFER_CAPACITY;
85
mBuffer = new char[mBufferCapacity];
90
nsBufferDecoderSupport::~nsBufferDecoderSupport()
95
void nsBufferDecoderSupport::FillBuffer(const char ** aSrc, PRInt32 aSrcLength)
97
PRInt32 bcr = PR_MIN(mBufferCapacity - mBufferLength, aSrcLength);
98
memcpy(mBuffer + mBufferLength, *aSrc, bcr);
103
void nsBufferDecoderSupport::DoubleBuffer()
105
mBufferCapacity *= 2;
106
char * newBuffer = new char [mBufferCapacity];
107
if (mBufferLength > 0) memcpy(newBuffer, mBuffer, mBufferLength);
112
//----------------------------------------------------------------------
113
// Subclassing of nsBasicDecoderSupport class [implementation]
115
NS_IMETHODIMP nsBufferDecoderSupport::Convert(const char * aSrc,
116
PRInt32 * aSrcLength,
118
PRInt32 * aDestLength)
120
// we do all operations using pointers internally
121
const char * src = aSrc;
122
const char * srcEnd = aSrc + *aSrcLength;
123
PRUnichar * dest = aDest;
124
PRUnichar * destEnd = aDest + *aDestLength;
126
PRInt32 bcr, bcw; // byte counts for read & write;
127
nsresult res = NS_OK;
129
// do we have some residual data from the last conversion?
130
if (mBufferLength > 0) if (dest == destEnd) {
131
res = NS_OK_UDEC_MOREOUTPUT;
133
// we need new data to add to the buffer
135
res = NS_OK_UDEC_MOREINPUT;
140
PRInt32 buffLen = mBufferLength; // initial buffer length
141
FillBuffer(&src, srcEnd - src);
143
// convert that buffer
145
bcw = destEnd - dest;
146
res = ConvertNoBuff(mBuffer, &bcr, dest, &bcw);
149
if ((res == NS_OK_UDEC_MOREINPUT) && (bcw == 0)) {
150
res = NS_ERROR_UNEXPECTED;
151
#if defined(DEBUG_yokoyama) || defined(DEBUG_ftang)
152
NS_ASSERTION(0, "This should not happen. Internal buffer may be corrupted.");
157
// we didn't convert that residual data - unfill the buffer
158
src -= mBufferLength - buffLen;
159
mBufferLength = buffLen;
160
#if defined(DEBUG_yokoyama) || defined(DEBUG_ftang)
161
NS_ASSERTION(0, "This should not happen. Internal buffer may be corrupted.");
164
// the buffer and some extra data was converted - unget the rest
165
src -= mBufferLength - bcr;
175
bcw = destEnd - dest;
176
res = ConvertNoBuff(src, &bcr, dest, &bcw);
180
// if we have partial input, store it in our internal buffer.
181
if (res == NS_OK_UDEC_MOREINPUT) {
183
// make sure buffer is large enough
184
if (bcr > mBufferCapacity) {
185
// somehow we got into an error state and the buffer is growing out of control
186
res = NS_ERROR_UNEXPECTED;
188
FillBuffer(&src, bcr);
193
*aSrcLength -= srcEnd - src;
194
*aDestLength -= destEnd - dest;
198
NS_IMETHODIMP nsBufferDecoderSupport::Reset()
204
NS_IMETHODIMP nsBufferDecoderSupport::GetMaxLength(const char* aSrc,
206
PRInt32* aDestLength)
208
NS_ASSERTION(mMaxLengthFactor != 0, "Must override GetMaxLength!");
209
*aDestLength = aSrcLength * mMaxLengthFactor;
213
//----------------------------------------------------------------------
214
// Class nsTableDecoderSupport [implementation]
216
nsTableDecoderSupport::nsTableDecoderSupport(uShiftTable * aShiftTable,
217
uMappingTable * aMappingTable,
218
PRUint32 aMaxLengthFactor)
219
: nsBufferDecoderSupport(aMaxLengthFactor)
222
mShiftTable = aShiftTable;
223
mMappingTable = aMappingTable;
226
nsTableDecoderSupport::~nsTableDecoderSupport()
228
NS_IF_RELEASE(mHelper);
231
//----------------------------------------------------------------------
232
// Subclassing of nsBufferDecoderSupport class [implementation]
234
NS_IMETHODIMP nsTableDecoderSupport::ConvertNoBuff(const char * aSrc,
235
PRInt32 * aSrcLength,
237
PRInt32 * aDestLength)
241
if (mHelper == nsnull) {
242
res = nsComponentManager::CreateInstance(kUnicodeDecodeHelperCID, NULL,
243
NS_GET_IID(nsIUnicodeDecodeHelper), (void**) & mHelper);
245
if (NS_FAILED(res)) return NS_ERROR_UDEC_NOHELPER;
248
res = mHelper->ConvertByTable(aSrc, aSrcLength, aDest, aDestLength,
249
mShiftTable, mMappingTable);
253
//----------------------------------------------------------------------
254
// Class nsMultiTableDecoderSupport [implementation]
256
nsMultiTableDecoderSupport::nsMultiTableDecoderSupport(
258
const uRange * aRangeArray,
259
uShiftTable ** aShiftTable,
260
uMappingTable ** aMappingTable,
261
PRUint32 aMaxLengthFactor)
262
: nsBufferDecoderSupport(aMaxLengthFactor)
265
mTableCount = aTableCount;
266
mRangeArray = aRangeArray;
267
mShiftTable = aShiftTable;
268
mMappingTable = aMappingTable;
271
nsMultiTableDecoderSupport::~nsMultiTableDecoderSupport()
273
NS_IF_RELEASE(mHelper);
276
//----------------------------------------------------------------------
277
// Subclassing of nsBufferDecoderSupport class [implementation]
279
NS_IMETHODIMP nsMultiTableDecoderSupport::ConvertNoBuff(const char * aSrc,
280
PRInt32 * aSrcLength,
282
PRInt32 * aDestLength)
286
if (mHelper == nsnull) {
287
res = nsComponentManager::CreateInstance(kUnicodeDecodeHelperCID, NULL,
288
NS_GET_IID(nsIUnicodeDecodeHelper), (void**) &mHelper);
290
if (NS_FAILED(res)) return NS_ERROR_UDEC_NOHELPER;
293
res = mHelper->ConvertByMultiTable(aSrc, aSrcLength, aDest, aDestLength,
294
mTableCount, mRangeArray, mShiftTable, mMappingTable);
298
//----------------------------------------------------------------------
299
// Class nsOneByteDecoderSupport [implementation]
301
nsOneByteDecoderSupport::nsOneByteDecoderSupport(
302
uShiftTable * aShiftTable,
303
uMappingTable * aMappingTable)
304
: nsBasicDecoderSupport()
307
mShiftTable = aShiftTable;
308
mMappingTable = aMappingTable;
311
nsOneByteDecoderSupport::~nsOneByteDecoderSupport()
313
NS_IF_RELEASE(mHelper);
316
//----------------------------------------------------------------------
317
// Subclassing of nsBasicDecoderSupport class [implementation]
319
NS_IMETHODIMP nsOneByteDecoderSupport::Convert(const char * aSrc,
320
PRInt32 * aSrcLength,
322
PRInt32 * aDestLength)
326
if (mHelper == nsnull) {
327
res = nsComponentManager::CreateInstance(kUnicodeDecodeHelperCID, NULL,
328
NS_GET_IID(nsIUnicodeDecodeHelper), (void**) &mHelper);
329
if (NS_FAILED(res)) return NS_ERROR_UDEC_NOHELPER;
331
res = mHelper -> CreateFastTable(mShiftTable, mMappingTable, mFastTable,
332
ONE_BYTE_TABLE_SIZE);
333
if (NS_FAILED(res)) return res;
336
res = mHelper->ConvertByFastTable(aSrc, aSrcLength, aDest, aDestLength,
337
mFastTable, ONE_BYTE_TABLE_SIZE);
341
NS_IMETHODIMP nsOneByteDecoderSupport::GetMaxLength(const char * aSrc,
343
PRInt32 * aDestLength)
345
// single byte to Unicode converter
346
*aDestLength = aSrcLength;
347
return NS_OK_UDEC_EXACTLENGTH;
350
NS_IMETHODIMP nsOneByteDecoderSupport::Reset()
352
// nothing to reset, no internal state in this case
356
//----------------------------------------------------------------------
357
// Class nsBasicEncoder [implementation]
358
nsBasicEncoder::nsBasicEncoder()
362
nsBasicEncoder::~nsBasicEncoder()
366
//----------------------------------------------------------------------
367
// Interface nsISupports [implementation]
369
NS_IMPL_ADDREF(nsBasicEncoder)
370
NS_IMPL_RELEASE(nsBasicEncoder)
372
NS_IMPL_QUERY_INTERFACE3(nsBasicEncoder,
374
nsICharRepresentable, nsIBasicEncoder)
376
NS_IMPL_QUERY_INTERFACE2(nsBasicEncoder,
378
nsICharRepresentable)
380
//----------------------------------------------------------------------
381
// Class nsEncoderSupport [implementation]
383
nsEncoderSupport::nsEncoderSupport(PRUint32 aMaxLengthFactor) :
384
mMaxLengthFactor(aMaxLengthFactor)
386
mBufferCapacity = DEFAULT_BUFFER_CAPACITY;
387
mBuffer = new char[mBufferCapacity];
389
mErrBehavior = kOnError_Signal;
396
nsEncoderSupport::~nsEncoderSupport()
399
NS_IF_RELEASE(mErrEncoder);
402
NS_IMETHODIMP nsEncoderSupport::ConvertNoBuff(const PRUnichar * aSrc,
403
PRInt32 * aSrcLength,
405
PRInt32 * aDestLength)
407
// we do all operations using pointers internally
408
const PRUnichar * src = aSrc;
409
const PRUnichar * srcEnd = aSrc + *aSrcLength;
411
char * destEnd = aDest + *aDestLength;
413
PRInt32 bcr, bcw; // byte counts for read & write;
418
bcw = destEnd - dest;
419
res = ConvertNoBuffNoErr(src, &bcr, dest, &bcw);
423
if (res == NS_ERROR_UENC_NOMAPPING) {
424
if (mErrBehavior == kOnError_Replace) {
425
const PRUnichar buff[] = {mErrChar};
427
bcw = destEnd - dest;
428
src--; // back the input: maybe the guy won't consume consume anything.
429
res = ConvertNoBuffNoErr(buff, &bcr, dest, &bcw);
432
if (res != NS_OK) break;
433
} else if (mErrBehavior == kOnError_CallBack) {
434
bcw = destEnd - dest;
436
res = mErrEncoder->Convert(*src, dest, &bcw);
438
// if enought output space then the last char was used
439
if (res != NS_OK_UENC_MOREOUTPUT) src++;
440
if (res != NS_OK) break;
446
*aSrcLength -= srcEnd - src;
447
*aDestLength -= destEnd - dest;
451
NS_IMETHODIMP nsEncoderSupport::FinishNoBuff(char * aDest,
452
PRInt32 * aDestLength)
458
nsresult nsEncoderSupport::FlushBuffer(char ** aDest, const char * aDestEnd)
460
PRInt32 bcr, bcw; // byte counts for read & write;
461
nsresult res = NS_OK;
462
char * dest = *aDest;
464
if (mBufferStart < mBufferEnd) {
465
bcr = mBufferEnd - mBufferStart;
466
bcw = aDestEnd - dest;
467
if (bcw < bcr) bcr = bcw;
468
memcpy(dest, mBufferStart, bcr);
472
if (mBufferStart < mBufferEnd) res = NS_OK_UENC_MOREOUTPUT;
480
//----------------------------------------------------------------------
481
// Interface nsIUnicodeEncoder [implementation]
483
NS_IMETHODIMP nsEncoderSupport::Convert(const PRUnichar * aSrc,
484
PRInt32 * aSrcLength,
486
PRInt32 * aDestLength)
488
// we do all operations using pointers internally
489
const PRUnichar * src = aSrc;
490
const PRUnichar * srcEnd = aSrc + *aSrcLength;
492
char * destEnd = aDest + *aDestLength;
494
PRInt32 bcr, bcw; // byte counts for read & write;
497
res = FlushBuffer(&dest, destEnd);
498
if (res == NS_OK_UENC_MOREOUTPUT) goto final;
501
bcw = destEnd - dest;
502
res = ConvertNoBuff(src, &bcr, dest, &bcw);
505
if ((res == NS_OK_UENC_MOREOUTPUT) && (dest < destEnd)) {
506
// convert exactly one character into the internal buffer
507
// at this point, there should be at least a char in the input
510
bcw = mBufferCapacity;
511
res = ConvertNoBuff(src, &bcr, mBuffer, &bcw);
513
if (res == NS_OK_UENC_MOREOUTPUT) {
515
mBufferCapacity *= 2;
516
mBuffer = new char [mBufferCapacity];
519
mBufferStart = mBufferEnd = mBuffer;
525
res = FlushBuffer(&dest, destEnd);
529
*aSrcLength -= srcEnd - src;
530
*aDestLength -= destEnd - dest;
534
NS_IMETHODIMP nsEncoderSupport::Finish(char * aDest, PRInt32 * aDestLength)
536
// we do all operations using pointers internally
538
char * destEnd = aDest + *aDestLength;
540
PRInt32 bcw; // byte count for write;
543
res = FlushBuffer(&dest, destEnd);
544
if (res == NS_OK_UENC_MOREOUTPUT) goto final;
546
// do the finish into the internal buffer.
548
bcw = mBufferCapacity;
549
res = FinishNoBuff(mBuffer, &bcw);
551
if (res == NS_OK_UENC_MOREOUTPUT) {
553
mBufferCapacity *= 2;
554
mBuffer = new char [mBufferCapacity];
556
mBufferStart = mBufferEnd = mBuffer;
562
res = FlushBuffer(&dest, destEnd);
565
*aDestLength -= destEnd - dest;
569
NS_IMETHODIMP nsEncoderSupport::Reset()
571
mBufferStart = mBufferEnd = mBuffer;
575
NS_IMETHODIMP nsEncoderSupport::SetOutputErrorBehavior(
577
nsIUnicharEncoder * aEncoder,
580
if ((aBehavior == kOnError_CallBack) && (aEncoder == NULL))
581
return NS_ERROR_NULL_POINTER;
583
NS_IF_RELEASE(aEncoder);
584
mErrEncoder = aEncoder;
585
NS_IF_ADDREF(aEncoder);
587
mErrBehavior = aBehavior;
593
nsEncoderSupport::GetMaxLength(const PRUnichar * aSrc,
595
PRInt32 * aDestLength)
597
*aDestLength = aSrcLength * mMaxLengthFactor;
602
//----------------------------------------------------------------------
603
// Class nsTableEncoderSupport [implementation]
605
nsTableEncoderSupport::nsTableEncoderSupport(uShiftTable * aShiftTable,
606
uMappingTable * aMappingTable,
607
PRUint32 aMaxLengthFactor)
608
: nsEncoderSupport(aMaxLengthFactor)
611
mShiftTable = aShiftTable;
612
mMappingTable = aMappingTable;
615
nsTableEncoderSupport::~nsTableEncoderSupport()
617
NS_IF_RELEASE(mHelper);
620
NS_IMETHODIMP nsTableEncoderSupport::FillInfo(PRUint32 *aInfo)
624
if (mHelper == nsnull) {
625
res = nsComponentManager::CreateInstance(kUnicodeEncodeHelperCID, NULL,
626
NS_GET_IID(nsIUnicodeEncodeHelper), (void**) & mHelper);
628
if (NS_FAILED(res)) return NS_ERROR_UENC_NOHELPER;
631
res = mHelper->FillInfo(aInfo, mMappingTable);
634
//----------------------------------------------------------------------
635
// Subclassing of nsEncoderSupport class [implementation]
637
NS_IMETHODIMP nsTableEncoderSupport::ConvertNoBuffNoErr(
638
const PRUnichar * aSrc,
639
PRInt32 * aSrcLength,
641
PRInt32 * aDestLength)
645
if (mHelper == nsnull) {
646
res = nsComponentManager::CreateInstance(kUnicodeEncodeHelperCID, NULL,
647
NS_GET_IID(nsIUnicodeEncodeHelper), (void**) & mHelper);
649
if (NS_FAILED(res)) return NS_ERROR_UENC_NOHELPER;
652
res = mHelper->ConvertByTable(aSrc, aSrcLength, aDest, aDestLength,
653
mShiftTable, mMappingTable);
657
//----------------------------------------------------------------------
658
// Class nsMultiTableEncoderSupport [implementation]
660
nsMultiTableEncoderSupport::nsMultiTableEncoderSupport(
662
uShiftTable ** aShiftTable,
663
uMappingTable ** aMappingTable,
664
PRUint32 aMaxLengthFactor)
665
: nsEncoderSupport(aMaxLengthFactor)
668
mTableCount = aTableCount;
669
mShiftTable = aShiftTable;
670
mMappingTable = aMappingTable;
673
nsMultiTableEncoderSupport::~nsMultiTableEncoderSupport()
675
NS_IF_RELEASE(mHelper);
678
NS_IMETHODIMP nsMultiTableEncoderSupport::FillInfo(PRUint32 *aInfo)
682
if (mHelper == nsnull) {
683
res = nsComponentManager::CreateInstance(kUnicodeEncodeHelperCID, NULL,
684
NS_GET_IID(nsIUnicodeEncodeHelper), (void**) & mHelper);
686
if (NS_FAILED(res)) return NS_ERROR_UENC_NOHELPER;
689
res = mHelper->FillInfo(aInfo,mTableCount, mMappingTable);
692
//----------------------------------------------------------------------
693
// Subclassing of nsEncoderSupport class [implementation]
695
NS_IMETHODIMP nsMultiTableEncoderSupport::ConvertNoBuffNoErr(
696
const PRUnichar * aSrc,
697
PRInt32 * aSrcLength,
699
PRInt32 * aDestLength)
703
if (mHelper == nsnull) {
704
res = nsComponentManager::CreateInstance(kUnicodeEncodeHelperCID, NULL,
705
NS_GET_IID(nsIUnicodeEncodeHelper), (void**) & mHelper);
707
if (NS_FAILED(res)) return NS_ERROR_UENC_NOHELPER;
710
res = mHelper->ConvertByMultiTable(aSrc, aSrcLength, aDest, aDestLength,
711
mTableCount, mShiftTable, mMappingTable);