Whitespace change to force builds.
[wine-gecko.git] / intl / uconv / util / nsUCSupport.cpp
blob682b17cb53dc8fa11b169e7176bcc6993088970b
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
13 * License.
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.
22 * Contributor(s):
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 ***** */
39 #include "pratom.h"
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)
66 #ifdef NS_DEBUG
67 NS_IMPL_QUERY_INTERFACE2(nsBasicDecoderSupport, nsIUnicodeDecoder, nsIBasicDecoder)
68 #else
69 NS_IMPL_QUERY_INTERFACE1(nsBasicDecoderSupport, nsIUnicodeDecoder)
70 #endif
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];
85 Reset();
88 nsBufferDecoderSupport::~nsBufferDecoderSupport()
90 delete [] mBuffer;
93 void nsBufferDecoderSupport::FillBuffer(const char ** aSrc, PRInt32 aSrcLength)
95 PRInt32 bcr = PR_MIN(mBufferCapacity - mBufferLength, aSrcLength);
96 memcpy(mBuffer + mBufferLength, *aSrc, bcr);
97 mBufferLength += bcr;
98 (*aSrc) += bcr;
101 void nsBufferDecoderSupport::DoubleBuffer()
103 mBufferCapacity *= 2;
104 char * newBuffer = new char [mBufferCapacity];
105 if (mBufferLength > 0) memcpy(newBuffer, mBuffer, mBufferLength);
106 delete [] mBuffer;
107 mBuffer = newBuffer;
110 //----------------------------------------------------------------------
111 // Subclassing of nsBasicDecoderSupport class [implementation]
113 NS_IMETHODIMP nsBufferDecoderSupport::Convert(const char * aSrc,
114 PRInt32 * aSrcLength,
115 PRUnichar * aDest,
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;
130 } else for (;;) {
131 // we need new data to add to the buffer
132 if (src == srcEnd) {
133 res = NS_OK_UDEC_MOREINPUT;
134 break;
137 // fill that buffer
138 PRInt32 buffLen = mBufferLength; // initial buffer length
139 FillBuffer(&src, srcEnd - src);
141 // convert that buffer
142 bcr = mBufferLength;
143 bcw = destEnd - dest;
144 res = ConvertNoBuff(mBuffer, &bcr, dest, &bcw);
145 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.");
151 #endif
152 break;
153 } else {
154 if (bcr < buffLen) {
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.");
160 #endif
161 } else {
162 // the buffer and some extra data was converted - unget the rest
163 src -= mBufferLength - bcr;
164 mBufferLength = 0;
165 res = NS_OK;
167 break;
171 if (res == NS_OK) {
172 bcr = srcEnd - src;
173 bcw = destEnd - dest;
174 res = ConvertNoBuff(src, &bcr, dest, &bcw);
175 src += bcr;
176 dest += bcw;
178 // if we have partial input, store it in our internal buffer.
179 if (res == NS_OK_UDEC_MOREINPUT) {
180 bcr = srcEnd - src;
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;
185 } else {
186 FillBuffer(&src, bcr);
191 *aSrcLength -= srcEnd - src;
192 *aDestLength -= destEnd - dest;
193 return res;
196 NS_IMETHODIMP nsBufferDecoderSupport::Reset()
198 mBufferLength = 0;
199 return NS_OK;
202 NS_IMETHODIMP nsBufferDecoderSupport::GetMaxLength(const char* aSrc,
203 PRInt32 aSrcLength,
204 PRInt32* aDestLength)
206 NS_ASSERTION(mMaxLengthFactor != 0, "Must override GetMaxLength!");
207 *aDestLength = aSrcLength * mMaxLengthFactor;
208 return NS_OK;
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,
234 PRUnichar * aDest,
235 PRInt32 * aDestLength)
237 return nsUnicodeDecodeHelper::ConvertByTable(aSrc, aSrcLength,
238 aDest, aDestLength,
239 mScanClass,
240 mShiftInTable, mMappingTable);
243 //----------------------------------------------------------------------
244 // Class nsMultiTableDecoderSupport [implementation]
246 nsMultiTableDecoderSupport::nsMultiTableDecoderSupport(
247 PRInt32 aTableCount,
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,
269 PRUnichar * aDest,
270 PRInt32 * aDestLength)
272 return nsUnicodeDecodeHelper::ConvertByMultiTable(aSrc, aSrcLength,
273 aDest, aDestLength,
274 mTableCount, mRangeArray,
275 mScanClassArray,
276 mMappingTable);
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,
299 PRUnichar * aDest,
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,
310 aDest, aDestLength,
311 mFastTable,
312 ONE_BYTE_TABLE_SIZE);
315 NS_IMETHODIMP nsOneByteDecoderSupport::GetMaxLength(const char * aSrc,
316 PRInt32 aSrcLength,
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
327 return NS_OK;
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)
345 #ifdef NS_DEBUG
346 NS_IMPL_QUERY_INTERFACE3(nsBasicEncoder,
347 nsIUnicodeEncoder,
348 nsICharRepresentable, nsIBasicEncoder)
349 #else
350 NS_IMPL_QUERY_INTERFACE2(nsBasicEncoder,
351 nsIUnicodeEncoder,
352 nsICharRepresentable)
353 #endif
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;
364 mErrChar = 0;
366 Reset();
369 nsEncoderSupport::~nsEncoderSupport()
371 delete [] mBuffer;
374 NS_IMETHODIMP nsEncoderSupport::ConvertNoBuff(const PRUnichar * aSrc,
375 PRInt32 * aSrcLength,
376 char * aDest,
377 PRInt32 * aDestLength)
379 // we do all operations using pointers internally
380 const PRUnichar * src = aSrc;
381 const PRUnichar * srcEnd = aSrc + *aSrcLength;
382 char * dest = aDest;
383 char * destEnd = aDest + *aDestLength;
385 PRInt32 bcr, bcw; // byte counts for read & write;
386 nsresult res;
388 for (;;) {
389 bcr = srcEnd - src;
390 bcw = destEnd - dest;
391 res = ConvertNoBuffNoErr(src, &bcr, dest, &bcw);
392 src += bcr;
393 dest += bcw;
395 if (res == NS_ERROR_UENC_NOMAPPING) {
396 if (mErrBehavior == kOnError_Replace) {
397 const PRUnichar buff[] = {mErrChar};
398 bcr = 1;
399 bcw = destEnd - dest;
400 src--; // back the input: maybe the guy won't consume consume anything.
401 res = ConvertNoBuffNoErr(buff, &bcr, dest, &bcw);
402 src += bcr;
403 dest += bcw;
404 if (res != NS_OK) break;
405 } else if (mErrBehavior == kOnError_CallBack) {
406 bcw = destEnd - dest;
407 src--;
408 res = mErrEncoder->Convert(*src, dest, &bcw);
409 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;
413 } else break;
415 else break;
418 *aSrcLength -= srcEnd - src;
419 *aDestLength -= destEnd - dest;
420 return res;
423 NS_IMETHODIMP nsEncoderSupport::FinishNoBuff(char * aDest,
424 PRInt32 * aDestLength)
426 *aDestLength = 0;
427 return NS_OK;
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);
441 dest += bcr;
442 mBufferStart += bcr;
444 if (mBufferStart < mBufferEnd) res = NS_OK_UENC_MOREOUTPUT;
447 *aDest = dest;
448 return res;
452 //----------------------------------------------------------------------
453 // Interface nsIUnicodeEncoder [implementation]
455 NS_IMETHODIMP nsEncoderSupport::Convert(const PRUnichar * aSrc,
456 PRInt32 * aSrcLength,
457 char * aDest,
458 PRInt32 * aDestLength)
460 // we do all operations using pointers internally
461 const PRUnichar * src = aSrc;
462 const PRUnichar * srcEnd = aSrc + *aSrcLength;
463 char * dest = aDest;
464 char * destEnd = aDest + *aDestLength;
466 PRInt32 bcr, bcw; // byte counts for read & write;
467 nsresult res;
469 res = FlushBuffer(&dest, destEnd);
470 if (res == NS_OK_UENC_MOREOUTPUT) goto final;
472 bcr = srcEnd - src;
473 bcw = destEnd - dest;
474 res = ConvertNoBuff(src, &bcr, dest, &bcw);
475 src += bcr;
476 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
480 for (;;) {
481 bcr = 1;
482 bcw = mBufferCapacity;
483 res = ConvertNoBuff(src, &bcr, mBuffer, &bcw);
485 if (res == NS_OK_UENC_MOREOUTPUT) {
486 delete [] mBuffer;
487 mBufferCapacity *= 2;
488 mBuffer = new char [mBufferCapacity];
489 } else {
490 src += bcr;
491 mBufferStart = mBufferEnd = mBuffer;
492 mBufferEnd += bcw;
493 break;
497 res = FlushBuffer(&dest, destEnd);
500 final:
501 *aSrcLength -= srcEnd - src;
502 *aDestLength -= destEnd - dest;
503 return res;
506 NS_IMETHODIMP nsEncoderSupport::Finish(char * aDest, PRInt32 * aDestLength)
508 // we do all operations using pointers internally
509 char * dest = aDest;
510 char * destEnd = aDest + *aDestLength;
512 PRInt32 bcw; // byte count for write;
513 nsresult res;
515 res = FlushBuffer(&dest, destEnd);
516 if (res == NS_OK_UENC_MOREOUTPUT) goto final;
518 // do the finish into the internal buffer.
519 for (;;) {
520 bcw = mBufferCapacity;
521 res = FinishNoBuff(mBuffer, &bcw);
523 if (res == NS_OK_UENC_MOREOUTPUT) {
524 delete [] mBuffer;
525 mBufferCapacity *= 2;
526 mBuffer = new char [mBufferCapacity];
527 } else {
528 mBufferStart = mBufferEnd = mBuffer;
529 mBufferEnd += bcw;
530 break;
534 res = FlushBuffer(&dest, destEnd);
536 final:
537 *aDestLength -= destEnd - dest;
538 return res;
541 NS_IMETHODIMP nsEncoderSupport::Reset()
543 mBufferStart = mBufferEnd = mBuffer;
544 return NS_OK;
547 NS_IMETHODIMP nsEncoderSupport::SetOutputErrorBehavior(
548 PRInt32 aBehavior,
549 nsIUnicharEncoder * aEncoder,
550 PRUnichar aChar)
552 if (aBehavior == kOnError_CallBack && aEncoder == nsnull)
553 return NS_ERROR_NULL_POINTER;
555 mErrEncoder = aEncoder;
556 mErrBehavior = aBehavior;
557 mErrChar = aChar;
558 return NS_OK;
561 NS_IMETHODIMP
562 nsEncoderSupport::GetMaxLength(const PRUnichar * aSrc,
563 PRInt32 aSrcLength,
564 PRInt32 * aDestLength)
566 *aDestLength = aSrcLength * mMaxLengthFactor;
567 return NS_OK;
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,
609 char * aDest,
610 PRInt32 * aDestLength)
612 return nsUnicodeEncodeHelper::ConvertByTable(aSrc, aSrcLength,
613 aDest, aDestLength,
614 mScanClass,
615 mShiftOutTable, mMappingTable);
618 //----------------------------------------------------------------------
619 // Class nsMultiTableEncoderSupport [implementation]
621 nsMultiTableEncoderSupport::nsMultiTableEncoderSupport(
622 PRInt32 aTableCount,
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,
649 char * aDest,
650 PRInt32 * aDestLength)
652 return nsUnicodeEncodeHelper::ConvertByMultiTable(aSrc, aSrcLength,
653 aDest, aDestLength,
654 mTableCount,
655 mScanClassArray,
656 mShiftOutTable,
657 mMappingTable);