1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (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 * http://www.mozilla.org/MPL/
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>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
40 #include "nsIComponentManager.h"
41 #include "nsICharRepresentable.h"
42 #include "nsUCSupport.h"
43 #include "nsUnicodeDecodeHelper.h"
44 #include "nsUnicodeEncodeHelper.h"
46 #define DEFAULT_BUFFER_CAPACITY 16
48 // XXX review the buffer growth limitation code
50 //----------------------------------------------------------------------
51 // Class nsBasicDecoderSupport [implementation]
53 nsBasicDecoderSupport::nsBasicDecoderSupport()
57 nsBasicDecoderSupport::~nsBasicDecoderSupport()
61 //----------------------------------------------------------------------
62 // Interface nsISupports [implementation]
64 NS_IMPL_ADDREF(nsBasicDecoderSupport
)
65 NS_IMPL_RELEASE(nsBasicDecoderSupport
)
67 NS_IMPL_QUERY_INTERFACE2(nsBasicDecoderSupport
, nsIUnicodeDecoder
, nsIBasicDecoder
)
69 NS_IMPL_QUERY_INTERFACE1(nsBasicDecoderSupport
, nsIUnicodeDecoder
)
72 //----------------------------------------------------------------------
73 // Interface nsIUnicodeDecoder [implementation]
75 //----------------------------------------------------------------------
76 // Class nsBufferDecoderSupport [implementation]
78 nsBufferDecoderSupport::nsBufferDecoderSupport(PRUint32 aMaxLengthFactor
)
79 : nsBasicDecoderSupport(),
80 mMaxLengthFactor(aMaxLengthFactor
)
82 mBufferCapacity
= DEFAULT_BUFFER_CAPACITY
;
83 mBuffer
= new char[mBufferCapacity
];
88 nsBufferDecoderSupport::~nsBufferDecoderSupport()
93 void nsBufferDecoderSupport::FillBuffer(const char ** aSrc
, PRInt32 aSrcLength
)
95 PRInt32 bcr
= PR_MIN(mBufferCapacity
- mBufferLength
, aSrcLength
);
96 memcpy(mBuffer
+ mBufferLength
, *aSrc
, bcr
);
101 void nsBufferDecoderSupport::DoubleBuffer()
103 mBufferCapacity
*= 2;
104 char * newBuffer
= new char [mBufferCapacity
];
105 if (mBufferLength
> 0) memcpy(newBuffer
, mBuffer
, mBufferLength
);
110 //----------------------------------------------------------------------
111 // Subclassing of nsBasicDecoderSupport class [implementation]
113 NS_IMETHODIMP
nsBufferDecoderSupport::Convert(const char * aSrc
,
114 PRInt32
* aSrcLength
,
116 PRInt32
* aDestLength
)
118 // we do all operations using pointers internally
119 const char * src
= aSrc
;
120 const char * srcEnd
= aSrc
+ *aSrcLength
;
121 PRUnichar
* dest
= aDest
;
122 PRUnichar
* destEnd
= aDest
+ *aDestLength
;
124 PRInt32 bcr
, bcw
; // byte counts for read & write;
125 nsresult res
= NS_OK
;
127 // do we have some residual data from the last conversion?
128 if (mBufferLength
> 0) if (dest
== destEnd
) {
129 res
= NS_OK_UDEC_MOREOUTPUT
;
131 // we need new data to add to the buffer
133 res
= NS_OK_UDEC_MOREINPUT
;
138 PRInt32 buffLen
= mBufferLength
; // initial buffer length
139 FillBuffer(&src
, srcEnd
- src
);
141 // convert that buffer
143 bcw
= destEnd
- dest
;
144 res
= ConvertNoBuff(mBuffer
, &bcr
, dest
, &bcw
);
147 if ((res
== NS_OK_UDEC_MOREINPUT
) && (bcw
== 0)) {
148 res
= NS_ERROR_UNEXPECTED
;
149 #if defined(DEBUG_yokoyama) || defined(DEBUG_ftang)
150 NS_ASSERTION(0, "This should not happen. Internal buffer may be corrupted.");
155 // we didn't convert that residual data - unfill the buffer
156 src
-= mBufferLength
- buffLen
;
157 mBufferLength
= buffLen
;
158 #if defined(DEBUG_yokoyama) || defined(DEBUG_ftang)
159 NS_ASSERTION(0, "This should not happen. Internal buffer may be corrupted.");
162 // the buffer and some extra data was converted - unget the rest
163 src
-= mBufferLength
- bcr
;
173 bcw
= destEnd
- dest
;
174 res
= ConvertNoBuff(src
, &bcr
, dest
, &bcw
);
178 // if we have partial input, store it in our internal buffer.
179 if (res
== NS_OK_UDEC_MOREINPUT
) {
181 // make sure buffer is large enough
182 if (bcr
> mBufferCapacity
) {
183 // somehow we got into an error state and the buffer is growing out of control
184 res
= NS_ERROR_UNEXPECTED
;
186 FillBuffer(&src
, bcr
);
191 *aSrcLength
-= srcEnd
- src
;
192 *aDestLength
-= destEnd
- dest
;
196 NS_IMETHODIMP
nsBufferDecoderSupport::Reset()
202 NS_IMETHODIMP
nsBufferDecoderSupport::GetMaxLength(const char* aSrc
,
204 PRInt32
* aDestLength
)
206 NS_ASSERTION(mMaxLengthFactor
!= 0, "Must override GetMaxLength!");
207 *aDestLength
= aSrcLength
* mMaxLengthFactor
;
211 //----------------------------------------------------------------------
212 // Class nsTableDecoderSupport [implementation]
214 nsTableDecoderSupport::nsTableDecoderSupport(uScanClassID aScanClass
,
215 uShiftInTable
* aShiftInTable
,
216 uMappingTable
* aMappingTable
,
217 PRUint32 aMaxLengthFactor
)
218 : nsBufferDecoderSupport(aMaxLengthFactor
)
220 mScanClass
= aScanClass
;
221 mShiftInTable
= aShiftInTable
;
222 mMappingTable
= aMappingTable
;
225 nsTableDecoderSupport::~nsTableDecoderSupport()
229 //----------------------------------------------------------------------
230 // Subclassing of nsBufferDecoderSupport class [implementation]
232 NS_IMETHODIMP
nsTableDecoderSupport::ConvertNoBuff(const char * aSrc
,
233 PRInt32
* aSrcLength
,
235 PRInt32
* aDestLength
)
237 return nsUnicodeDecodeHelper::ConvertByTable(aSrc
, aSrcLength
,
240 mShiftInTable
, mMappingTable
);
243 //----------------------------------------------------------------------
244 // Class nsMultiTableDecoderSupport [implementation]
246 nsMultiTableDecoderSupport::nsMultiTableDecoderSupport(
248 const uRange
* aRangeArray
,
249 uScanClassID
* aScanClassArray
,
250 uMappingTable
** aMappingTable
,
251 PRUint32 aMaxLengthFactor
)
252 : nsBufferDecoderSupport(aMaxLengthFactor
)
254 mTableCount
= aTableCount
;
255 mRangeArray
= aRangeArray
;
256 mScanClassArray
= aScanClassArray
;
257 mMappingTable
= aMappingTable
;
260 nsMultiTableDecoderSupport::~nsMultiTableDecoderSupport()
264 //----------------------------------------------------------------------
265 // Subclassing of nsBufferDecoderSupport class [implementation]
267 NS_IMETHODIMP
nsMultiTableDecoderSupport::ConvertNoBuff(const char * aSrc
,
268 PRInt32
* aSrcLength
,
270 PRInt32
* aDestLength
)
272 return nsUnicodeDecodeHelper::ConvertByMultiTable(aSrc
, aSrcLength
,
274 mTableCount
, mRangeArray
,
279 //----------------------------------------------------------------------
280 // Class nsOneByteDecoderSupport [implementation]
282 nsOneByteDecoderSupport::nsOneByteDecoderSupport(
283 uMappingTable
* aMappingTable
)
284 : nsBasicDecoderSupport()
286 mMappingTable
= aMappingTable
;
287 mFastTableCreated
= PR_FALSE
;
290 nsOneByteDecoderSupport::~nsOneByteDecoderSupport()
294 //----------------------------------------------------------------------
295 // Subclassing of nsBasicDecoderSupport class [implementation]
297 NS_IMETHODIMP
nsOneByteDecoderSupport::Convert(const char * aSrc
,
298 PRInt32
* aSrcLength
,
300 PRInt32
* aDestLength
)
302 if (!mFastTableCreated
) {
303 nsresult res
= nsUnicodeDecodeHelper::CreateFastTable(
304 mMappingTable
, mFastTable
, ONE_BYTE_TABLE_SIZE
);
305 if (NS_FAILED(res
)) return res
;
306 mFastTableCreated
= PR_TRUE
;
309 return nsUnicodeDecodeHelper::ConvertByFastTable(aSrc
, aSrcLength
,
312 ONE_BYTE_TABLE_SIZE
);
315 NS_IMETHODIMP
nsOneByteDecoderSupport::GetMaxLength(const char * aSrc
,
317 PRInt32
* aDestLength
)
319 // single byte to Unicode converter
320 *aDestLength
= aSrcLength
;
321 return NS_OK_UDEC_EXACTLENGTH
;
324 NS_IMETHODIMP
nsOneByteDecoderSupport::Reset()
326 // nothing to reset, no internal state in this case
330 //----------------------------------------------------------------------
331 // Class nsBasicEncoder [implementation]
332 nsBasicEncoder::nsBasicEncoder()
336 nsBasicEncoder::~nsBasicEncoder()
340 //----------------------------------------------------------------------
341 // Interface nsISupports [implementation]
343 NS_IMPL_ADDREF(nsBasicEncoder
)
344 NS_IMPL_RELEASE(nsBasicEncoder
)
346 NS_IMPL_QUERY_INTERFACE3(nsBasicEncoder
,
348 nsICharRepresentable
, nsIBasicEncoder
)
350 NS_IMPL_QUERY_INTERFACE2(nsBasicEncoder
,
352 nsICharRepresentable
)
354 //----------------------------------------------------------------------
355 // Class nsEncoderSupport [implementation]
357 nsEncoderSupport::nsEncoderSupport(PRUint32 aMaxLengthFactor
) :
358 mMaxLengthFactor(aMaxLengthFactor
)
360 mBufferCapacity
= DEFAULT_BUFFER_CAPACITY
;
361 mBuffer
= new char[mBufferCapacity
];
363 mErrBehavior
= kOnError_Signal
;
369 nsEncoderSupport::~nsEncoderSupport()
374 NS_IMETHODIMP
nsEncoderSupport::ConvertNoBuff(const PRUnichar
* aSrc
,
375 PRInt32
* aSrcLength
,
377 PRInt32
* aDestLength
)
379 // we do all operations using pointers internally
380 const PRUnichar
* src
= aSrc
;
381 const PRUnichar
* srcEnd
= aSrc
+ *aSrcLength
;
383 char * destEnd
= aDest
+ *aDestLength
;
385 PRInt32 bcr
, bcw
; // byte counts for read & write;
390 bcw
= destEnd
- dest
;
391 res
= ConvertNoBuffNoErr(src
, &bcr
, dest
, &bcw
);
395 if (res
== NS_ERROR_UENC_NOMAPPING
) {
396 if (mErrBehavior
== kOnError_Replace
) {
397 const PRUnichar buff
[] = {mErrChar
};
399 bcw
= destEnd
- dest
;
400 src
--; // back the input: maybe the guy won't consume consume anything.
401 res
= ConvertNoBuffNoErr(buff
, &bcr
, dest
, &bcw
);
404 if (res
!= NS_OK
) break;
405 } else if (mErrBehavior
== kOnError_CallBack
) {
406 bcw
= destEnd
- dest
;
408 res
= mErrEncoder
->Convert(*src
, dest
, &bcw
);
410 // if enought output space then the last char was used
411 if (res
!= NS_OK_UENC_MOREOUTPUT
) src
++;
412 if (res
!= NS_OK
) break;
418 *aSrcLength
-= srcEnd
- src
;
419 *aDestLength
-= destEnd
- dest
;
423 NS_IMETHODIMP
nsEncoderSupport::FinishNoBuff(char * aDest
,
424 PRInt32
* aDestLength
)
430 nsresult
nsEncoderSupport::FlushBuffer(char ** aDest
, const char * aDestEnd
)
432 PRInt32 bcr
, bcw
; // byte counts for read & write;
433 nsresult res
= NS_OK
;
434 char * dest
= *aDest
;
436 if (mBufferStart
< mBufferEnd
) {
437 bcr
= mBufferEnd
- mBufferStart
;
438 bcw
= aDestEnd
- dest
;
439 if (bcw
< bcr
) bcr
= bcw
;
440 memcpy(dest
, mBufferStart
, bcr
);
444 if (mBufferStart
< mBufferEnd
) res
= NS_OK_UENC_MOREOUTPUT
;
452 //----------------------------------------------------------------------
453 // Interface nsIUnicodeEncoder [implementation]
455 NS_IMETHODIMP
nsEncoderSupport::Convert(const PRUnichar
* aSrc
,
456 PRInt32
* aSrcLength
,
458 PRInt32
* aDestLength
)
460 // we do all operations using pointers internally
461 const PRUnichar
* src
= aSrc
;
462 const PRUnichar
* srcEnd
= aSrc
+ *aSrcLength
;
464 char * destEnd
= aDest
+ *aDestLength
;
466 PRInt32 bcr
, bcw
; // byte counts for read & write;
469 res
= FlushBuffer(&dest
, destEnd
);
470 if (res
== NS_OK_UENC_MOREOUTPUT
) goto final
;
473 bcw
= destEnd
- dest
;
474 res
= ConvertNoBuff(src
, &bcr
, dest
, &bcw
);
477 if ((res
== NS_OK_UENC_MOREOUTPUT
) && (dest
< destEnd
)) {
478 // convert exactly one character into the internal buffer
479 // at this point, there should be at least a char in the input
482 bcw
= mBufferCapacity
;
483 res
= ConvertNoBuff(src
, &bcr
, mBuffer
, &bcw
);
485 if (res
== NS_OK_UENC_MOREOUTPUT
) {
487 mBufferCapacity
*= 2;
488 mBuffer
= new char [mBufferCapacity
];
491 mBufferStart
= mBufferEnd
= mBuffer
;
497 res
= FlushBuffer(&dest
, destEnd
);
501 *aSrcLength
-= srcEnd
- src
;
502 *aDestLength
-= destEnd
- dest
;
506 NS_IMETHODIMP
nsEncoderSupport::Finish(char * aDest
, PRInt32
* aDestLength
)
508 // we do all operations using pointers internally
510 char * destEnd
= aDest
+ *aDestLength
;
512 PRInt32 bcw
; // byte count for write;
515 res
= FlushBuffer(&dest
, destEnd
);
516 if (res
== NS_OK_UENC_MOREOUTPUT
) goto final
;
518 // do the finish into the internal buffer.
520 bcw
= mBufferCapacity
;
521 res
= FinishNoBuff(mBuffer
, &bcw
);
523 if (res
== NS_OK_UENC_MOREOUTPUT
) {
525 mBufferCapacity
*= 2;
526 mBuffer
= new char [mBufferCapacity
];
528 mBufferStart
= mBufferEnd
= mBuffer
;
534 res
= FlushBuffer(&dest
, destEnd
);
537 *aDestLength
-= destEnd
- dest
;
541 NS_IMETHODIMP
nsEncoderSupport::Reset()
543 mBufferStart
= mBufferEnd
= mBuffer
;
547 NS_IMETHODIMP
nsEncoderSupport::SetOutputErrorBehavior(
549 nsIUnicharEncoder
* aEncoder
,
552 if (aBehavior
== kOnError_CallBack
&& aEncoder
== nsnull
)
553 return NS_ERROR_NULL_POINTER
;
555 mErrEncoder
= aEncoder
;
556 mErrBehavior
= aBehavior
;
562 nsEncoderSupport::GetMaxLength(const PRUnichar
* aSrc
,
564 PRInt32
* aDestLength
)
566 *aDestLength
= aSrcLength
* mMaxLengthFactor
;
571 //----------------------------------------------------------------------
572 // Class nsTableEncoderSupport [implementation]
574 nsTableEncoderSupport::nsTableEncoderSupport(uScanClassID aScanClass
,
575 uShiftOutTable
* aShiftOutTable
,
576 uMappingTable
* aMappingTable
,
577 PRUint32 aMaxLengthFactor
)
578 : nsEncoderSupport(aMaxLengthFactor
)
580 mScanClass
= aScanClass
;
581 mShiftOutTable
= aShiftOutTable
,
582 mMappingTable
= aMappingTable
;
585 nsTableEncoderSupport::nsTableEncoderSupport(uScanClassID aScanClass
,
586 uMappingTable
* aMappingTable
,
587 PRUint32 aMaxLengthFactor
)
588 : nsEncoderSupport(aMaxLengthFactor
)
590 mScanClass
= aScanClass
;
591 mShiftOutTable
= nsnull
;
592 mMappingTable
= aMappingTable
;
595 nsTableEncoderSupport::~nsTableEncoderSupport()
599 NS_IMETHODIMP
nsTableEncoderSupport::FillInfo(PRUint32
*aInfo
)
601 return nsUnicodeEncodeHelper::FillInfo(aInfo
, mMappingTable
);
603 //----------------------------------------------------------------------
604 // Subclassing of nsEncoderSupport class [implementation]
606 NS_IMETHODIMP
nsTableEncoderSupport::ConvertNoBuffNoErr(
607 const PRUnichar
* aSrc
,
608 PRInt32
* aSrcLength
,
610 PRInt32
* aDestLength
)
612 return nsUnicodeEncodeHelper::ConvertByTable(aSrc
, aSrcLength
,
615 mShiftOutTable
, mMappingTable
);
618 //----------------------------------------------------------------------
619 // Class nsMultiTableEncoderSupport [implementation]
621 nsMultiTableEncoderSupport::nsMultiTableEncoderSupport(
623 uScanClassID
* aScanClassArray
,
624 uShiftOutTable
** aShiftOutTable
,
625 uMappingTable
** aMappingTable
,
626 PRUint32 aMaxLengthFactor
)
627 : nsEncoderSupport(aMaxLengthFactor
)
629 mTableCount
= aTableCount
;
630 mScanClassArray
= aScanClassArray
;
631 mShiftOutTable
= aShiftOutTable
;
632 mMappingTable
= aMappingTable
;
635 nsMultiTableEncoderSupport::~nsMultiTableEncoderSupport()
639 NS_IMETHODIMP
nsMultiTableEncoderSupport::FillInfo(PRUint32
*aInfo
)
641 return nsUnicodeEncodeHelper::FillInfo(aInfo
,mTableCount
, mMappingTable
);
643 //----------------------------------------------------------------------
644 // Subclassing of nsEncoderSupport class [implementation]
646 NS_IMETHODIMP
nsMultiTableEncoderSupport::ConvertNoBuffNoErr(
647 const PRUnichar
* aSrc
,
648 PRInt32
* aSrcLength
,
650 PRInt32
* aDestLength
)
652 return nsUnicodeEncodeHelper::ConvertByMultiTable(aSrc
, aSrcLength
,