2000-08-05 00:51:37 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2004-04-18 14:21:17 +00:00
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
2000-08-05 00:51:37 +00:00
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
2004-04-18 14:21:17 +00:00
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2000
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
2000-08-05 00:51:37 +00:00
|
|
|
*
|
|
|
|
* Contributor(s):
|
2000-09-02 04:10:44 +00:00
|
|
|
* Scott Collins <scc@mozilla.org> (original author)
|
2004-04-18 14:21:17 +00:00
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
2000-08-05 00:51:37 +00:00
|
|
|
|
|
|
|
#include "nsReadableUtils.h"
|
2000-08-05 03:32:36 +00:00
|
|
|
#include "nsMemory.h"
|
2000-08-23 17:27:06 +00:00
|
|
|
#include "nsString.h"
|
2003-05-21 22:20:27 +00:00
|
|
|
#include "nsUTF8Utils.h"
|
2000-08-05 00:51:37 +00:00
|
|
|
|
2000-08-23 17:27:06 +00:00
|
|
|
NS_COM
|
|
|
|
void
|
2003-06-27 07:44:13 +00:00
|
|
|
LossyCopyUTF16toASCII( const nsAString& aSource, nsACString& aDest )
|
2000-08-23 17:27:06 +00:00
|
|
|
{
|
2003-11-02 12:58:29 +00:00
|
|
|
aDest.Truncate();
|
|
|
|
LossyAppendUTF16toASCII(aSource, aDest);
|
2000-08-23 17:27:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_COM
|
|
|
|
void
|
2003-06-23 04:30:57 +00:00
|
|
|
CopyASCIItoUTF16( const nsACString& aSource, nsAString& aDest )
|
2000-08-23 17:27:06 +00:00
|
|
|
{
|
2003-11-02 12:58:29 +00:00
|
|
|
aDest.Truncate();
|
|
|
|
AppendASCIItoUTF16(aSource, aDest);
|
2000-08-23 17:27:06 +00:00
|
|
|
}
|
|
|
|
|
2003-12-23 09:24:11 +00:00
|
|
|
NS_COM
|
|
|
|
void
|
|
|
|
LossyCopyUTF16toASCII( const PRUnichar* aSource, nsACString& aDest )
|
|
|
|
{
|
2004-01-14 19:26:17 +00:00
|
|
|
aDest.Truncate();
|
2003-12-23 09:24:11 +00:00
|
|
|
if (aSource) {
|
|
|
|
LossyAppendUTF16toASCII(nsDependentString(aSource), aDest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_COM
|
|
|
|
void
|
|
|
|
CopyASCIItoUTF16( const char* aSource, nsAString& aDest )
|
|
|
|
{
|
2004-01-14 19:26:17 +00:00
|
|
|
aDest.Truncate();
|
2003-12-23 09:24:11 +00:00
|
|
|
if (aSource) {
|
|
|
|
AppendASCIItoUTF16(nsDependentCString(aSource), aDest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-05-31 06:03:18 +00:00
|
|
|
NS_COM
|
|
|
|
void
|
2003-06-05 11:44:06 +00:00
|
|
|
CopyUTF16toUTF8( const nsAString& aSource, nsACString& aDest )
|
2003-05-31 06:03:18 +00:00
|
|
|
{
|
|
|
|
aDest.Truncate();
|
2003-06-05 11:44:06 +00:00
|
|
|
AppendUTF16toUTF8(aSource, aDest);
|
2003-05-31 06:03:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_COM
|
|
|
|
void
|
2003-06-05 11:44:06 +00:00
|
|
|
CopyUTF8toUTF16( const nsACString& aSource, nsAString& aDest )
|
2003-05-31 06:03:18 +00:00
|
|
|
{
|
|
|
|
aDest.Truncate();
|
2003-06-05 11:44:06 +00:00
|
|
|
AppendUTF8toUTF16(aSource, aDest);
|
2003-05-31 06:03:18 +00:00
|
|
|
}
|
|
|
|
|
2003-06-19 05:17:55 +00:00
|
|
|
NS_COM
|
|
|
|
void
|
|
|
|
CopyUTF16toUTF8( const PRUnichar* aSource, nsACString& aDest )
|
|
|
|
{
|
|
|
|
aDest.Truncate();
|
|
|
|
AppendUTF16toUTF8(aSource, aDest);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_COM
|
|
|
|
void
|
|
|
|
CopyUTF8toUTF16( const char* aSource, nsAString& aDest )
|
|
|
|
{
|
|
|
|
aDest.Truncate();
|
|
|
|
AppendUTF8toUTF16(aSource, aDest);
|
|
|
|
}
|
|
|
|
|
2007-07-03 06:03:11 +00:00
|
|
|
// Like GetMutableData, but returns false if it can't
|
|
|
|
// allocate enough memory (e.g. due to OOM) rather than
|
|
|
|
// returning zero (which could have other meanings) and
|
|
|
|
// throws away the out-param pointer.
|
|
|
|
PRBool
|
|
|
|
SetLengthForWriting(nsAString& aDest, PRUint32 aDesiredLength)
|
|
|
|
{
|
|
|
|
PRUnichar* dummy;
|
|
|
|
PRUint32 len = aDest.GetMutableData(&dummy, aDesiredLength);
|
|
|
|
return (len >= aDesiredLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
SetLengthForWritingC(nsACString& aDest, PRUint32 aDesiredLength)
|
|
|
|
{
|
|
|
|
char* dummy;
|
|
|
|
PRUint32 len = aDest.GetMutableData(&dummy, aDesiredLength);
|
|
|
|
return (len >= aDesiredLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-11-01 09:35:48 +00:00
|
|
|
NS_COM
|
|
|
|
void
|
|
|
|
LossyAppendUTF16toASCII( const nsAString& aSource, nsACString& aDest )
|
|
|
|
{
|
|
|
|
PRUint32 old_dest_length = aDest.Length();
|
2007-07-03 06:03:11 +00:00
|
|
|
if (!SetLengthForWritingC(aDest, old_dest_length + aSource.Length()))
|
|
|
|
return;
|
2003-11-01 09:35:48 +00:00
|
|
|
|
|
|
|
nsAString::const_iterator fromBegin, fromEnd;
|
|
|
|
|
|
|
|
nsACString::iterator dest;
|
|
|
|
aDest.BeginWriting(dest);
|
|
|
|
|
|
|
|
dest.advance(old_dest_length);
|
|
|
|
|
|
|
|
// right now, this won't work on multi-fragment destinations
|
|
|
|
LossyConvertEncoding<PRUnichar, char> converter(dest.get());
|
|
|
|
|
|
|
|
copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_COM
|
|
|
|
void
|
|
|
|
AppendASCIItoUTF16( const nsACString& aSource, nsAString& aDest )
|
|
|
|
{
|
|
|
|
PRUint32 old_dest_length = aDest.Length();
|
2007-07-03 06:03:11 +00:00
|
|
|
if (!SetLengthForWriting(aDest, old_dest_length + aSource.Length()))
|
|
|
|
return;
|
2003-11-01 09:35:48 +00:00
|
|
|
|
|
|
|
nsACString::const_iterator fromBegin, fromEnd;
|
|
|
|
|
|
|
|
nsAString::iterator dest;
|
|
|
|
aDest.BeginWriting(dest);
|
|
|
|
|
|
|
|
dest.advance(old_dest_length);
|
|
|
|
|
|
|
|
// right now, this won't work on multi-fragment destinations
|
|
|
|
LossyConvertEncoding<char, PRUnichar> converter(dest.get());
|
|
|
|
|
|
|
|
copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_COM
|
|
|
|
void
|
|
|
|
LossyAppendUTF16toASCII( const PRUnichar* aSource, nsACString& aDest )
|
|
|
|
{
|
|
|
|
if (aSource) {
|
|
|
|
LossyAppendUTF16toASCII(nsDependentString(aSource), aDest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_COM
|
|
|
|
void
|
|
|
|
AppendASCIItoUTF16( const char* aSource, nsAString& aDest )
|
|
|
|
{
|
|
|
|
if (aSource) {
|
|
|
|
AppendASCIItoUTF16(nsDependentCString(aSource), aDest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-05-31 06:03:18 +00:00
|
|
|
NS_COM
|
|
|
|
void
|
2003-06-05 11:44:06 +00:00
|
|
|
AppendUTF16toUTF8( const nsAString& aSource, nsACString& aDest )
|
2003-05-31 06:03:18 +00:00
|
|
|
{
|
2003-06-17 16:30:17 +00:00
|
|
|
nsAString::const_iterator source_start, source_end;
|
|
|
|
CalculateUTF8Size calculator;
|
|
|
|
copy_string(aSource.BeginReading(source_start),
|
|
|
|
aSource.EndReading(source_end), calculator);
|
|
|
|
|
|
|
|
PRUint32 count = calculator.Size();
|
|
|
|
|
|
|
|
if (count)
|
|
|
|
{
|
|
|
|
PRUint32 old_dest_length = aDest.Length();
|
|
|
|
|
|
|
|
// Grow the buffer if we need to.
|
2007-07-03 06:03:11 +00:00
|
|
|
if(!SetLengthForWritingC(aDest, old_dest_length + count))
|
|
|
|
return;
|
2003-06-17 16:30:17 +00:00
|
|
|
|
|
|
|
nsACString::iterator dest;
|
|
|
|
aDest.BeginWriting(dest);
|
|
|
|
|
|
|
|
dest.advance(old_dest_length);
|
|
|
|
|
|
|
|
if (count <= (PRUint32)dest.size_forward())
|
|
|
|
{
|
|
|
|
// aDest has enough room in the fragment just past the end
|
|
|
|
// of its old data that it can hold what we're about to
|
|
|
|
// append. Append using copy_string().
|
|
|
|
|
|
|
|
// All ready? Time to convert
|
|
|
|
|
2003-06-23 04:30:57 +00:00
|
|
|
ConvertUTF16toUTF8 converter(dest.get());
|
2003-06-17 16:30:17 +00:00
|
|
|
copy_string(aSource.BeginReading(source_start),
|
|
|
|
aSource.EndReading(source_end), converter);
|
|
|
|
|
|
|
|
if (converter.Size() != count)
|
|
|
|
{
|
|
|
|
NS_ERROR("Input invalid or incorrect length was calculated");
|
|
|
|
|
|
|
|
aDest.SetLength(old_dest_length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// This isn't the fastest way to do this, but it gets
|
|
|
|
// complicated to convert UTF16 into a fragmented UTF8
|
|
|
|
// string, so we'll take the easy way out here in this
|
|
|
|
// rare situation.
|
|
|
|
|
|
|
|
aDest.Replace(old_dest_length, count,
|
2003-06-23 04:30:57 +00:00
|
|
|
NS_ConvertUTF16toUTF8(aSource));
|
2003-06-17 16:30:17 +00:00
|
|
|
}
|
|
|
|
}
|
2003-05-31 06:03:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_COM
|
|
|
|
void
|
2003-06-05 11:44:06 +00:00
|
|
|
AppendUTF8toUTF16( const nsACString& aSource, nsAString& aDest )
|
2003-05-31 06:03:18 +00:00
|
|
|
{
|
2003-06-17 16:30:17 +00:00
|
|
|
nsACString::const_iterator source_start, source_end;
|
|
|
|
CalculateUTF8Length calculator;
|
|
|
|
copy_string(aSource.BeginReading(source_start),
|
|
|
|
aSource.EndReading(source_end), calculator);
|
|
|
|
|
|
|
|
PRUint32 count = calculator.Length();
|
|
|
|
|
|
|
|
if (count)
|
|
|
|
{
|
|
|
|
PRUint32 old_dest_length = aDest.Length();
|
|
|
|
|
|
|
|
// Grow the buffer if we need to.
|
2007-07-03 06:03:11 +00:00
|
|
|
if(!SetLengthForWriting(aDest, old_dest_length + count))
|
|
|
|
return;
|
2003-06-17 16:30:17 +00:00
|
|
|
|
|
|
|
nsAString::iterator dest;
|
|
|
|
aDest.BeginWriting(dest);
|
|
|
|
|
|
|
|
dest.advance(old_dest_length);
|
|
|
|
|
|
|
|
if (count <= (PRUint32)dest.size_forward())
|
|
|
|
{
|
|
|
|
// aDest has enough room in the fragment just past the end
|
|
|
|
// of its old data that it can hold what we're about to
|
|
|
|
// append. Append using copy_string().
|
|
|
|
|
|
|
|
// All ready? Time to convert
|
|
|
|
|
2003-06-23 04:30:57 +00:00
|
|
|
ConvertUTF8toUTF16 converter(dest.get());
|
2003-06-17 16:30:17 +00:00
|
|
|
copy_string(aSource.BeginReading(source_start),
|
|
|
|
aSource.EndReading(source_end), converter);
|
|
|
|
|
|
|
|
if (converter.Length() != count)
|
|
|
|
{
|
|
|
|
NS_ERROR("Input wasn't UTF8 or incorrect length was calculated");
|
|
|
|
aDest.SetLength(old_dest_length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// This isn't the fastest way to do this, but it gets
|
|
|
|
// complicated to convert parts of a UTF8 string into a
|
|
|
|
// UTF16 string, so we'll take the easy way out here in
|
|
|
|
// this rare situation.
|
|
|
|
|
|
|
|
aDest.Replace(old_dest_length, count,
|
2003-06-23 04:30:57 +00:00
|
|
|
NS_ConvertUTF8toUTF16(aSource));
|
2003-06-17 16:30:17 +00:00
|
|
|
}
|
|
|
|
}
|
2003-05-31 06:03:18 +00:00
|
|
|
}
|
|
|
|
|
2003-06-19 05:17:55 +00:00
|
|
|
NS_COM
|
|
|
|
void
|
|
|
|
AppendUTF16toUTF8( const PRUnichar* aSource, nsACString& aDest )
|
|
|
|
{
|
|
|
|
if (aSource) {
|
|
|
|
AppendUTF16toUTF8(nsDependentString(aSource), aDest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_COM
|
|
|
|
void
|
|
|
|
AppendUTF8toUTF16( const char* aSource, nsAString& aDest )
|
|
|
|
{
|
|
|
|
if (aSource) {
|
|
|
|
AppendUTF8toUTF16(nsDependentCString(aSource), aDest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-08-05 04:25:49 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* A helper function that allocates a buffer of the desired character type big enough to hold a copy of the supplied string (plus a zero terminator).
|
|
|
|
*
|
|
|
|
* @param aSource an string you will eventually be making a copy of
|
|
|
|
* @return a new buffer (of the type specified by the second parameter) which you must free with |nsMemory::Free|.
|
|
|
|
*
|
|
|
|
*/
|
2001-04-02 19:40:52 +00:00
|
|
|
template <class FromStringT, class ToCharT>
|
2000-08-05 03:32:36 +00:00
|
|
|
inline
|
|
|
|
ToCharT*
|
2001-04-02 19:40:52 +00:00
|
|
|
AllocateStringCopy( const FromStringT& aSource, ToCharT* )
|
2000-08-05 03:32:36 +00:00
|
|
|
{
|
2007-07-08 07:08:04 +00:00
|
|
|
return static_cast<ToCharT*>(nsMemory::Alloc((aSource.Length()+1) * sizeof(ToCharT)));
|
2000-08-05 03:32:36 +00:00
|
|
|
}
|
2000-08-05 02:13:59 +00:00
|
|
|
|
2000-08-05 01:15:45 +00:00
|
|
|
|
2000-08-05 07:44:08 +00:00
|
|
|
NS_COM
|
2000-08-05 01:15:45 +00:00
|
|
|
char*
|
2001-04-02 19:40:52 +00:00
|
|
|
ToNewCString( const nsAString& aSource )
|
2000-08-05 00:51:37 +00:00
|
|
|
{
|
2000-08-05 03:32:36 +00:00
|
|
|
char* result = AllocateStringCopy(aSource, (char*)0);
|
2005-03-01 05:14:22 +00:00
|
|
|
if (!result)
|
|
|
|
return nsnull;
|
2000-09-02 04:10:44 +00:00
|
|
|
|
2001-09-25 09:35:50 +00:00
|
|
|
nsAString::const_iterator fromBegin, fromEnd;
|
2000-09-02 04:10:44 +00:00
|
|
|
LossyConvertEncoding<PRUnichar, char> converter(result);
|
|
|
|
copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter).write_terminator();
|
2000-08-05 02:13:59 +00:00
|
|
|
return result;
|
2000-08-05 00:51:37 +00:00
|
|
|
}
|
|
|
|
|
2000-08-23 17:27:06 +00:00
|
|
|
NS_COM
|
|
|
|
char*
|
2004-05-13 17:45:03 +00:00
|
|
|
ToNewUTF8String( const nsAString& aSource, PRUint32 *aUTF8Count )
|
2000-08-23 17:27:06 +00:00
|
|
|
{
|
2003-06-11 04:27:13 +00:00
|
|
|
nsAString::const_iterator start, end;
|
|
|
|
CalculateUTF8Size calculator;
|
|
|
|
copy_string(aSource.BeginReading(start), aSource.EndReading(end),
|
|
|
|
calculator);
|
|
|
|
|
2004-05-13 17:45:03 +00:00
|
|
|
if (aUTF8Count)
|
|
|
|
*aUTF8Count = calculator.Size();
|
|
|
|
|
2007-07-08 07:08:04 +00:00
|
|
|
char *result = static_cast<char*>
|
|
|
|
(nsMemory::Alloc(calculator.Size() + 1));
|
2005-03-01 05:14:22 +00:00
|
|
|
if (!result)
|
|
|
|
return nsnull;
|
2003-06-11 04:27:13 +00:00
|
|
|
|
2003-06-23 04:30:57 +00:00
|
|
|
ConvertUTF16toUTF8 converter(result);
|
2003-06-11 04:27:13 +00:00
|
|
|
copy_string(aSource.BeginReading(start), aSource.EndReading(end),
|
|
|
|
converter).write_terminator();
|
|
|
|
NS_ASSERTION(calculator.Size() == converter.Size(), "length mismatch");
|
2000-08-23 17:27:06 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2000-08-05 07:44:08 +00:00
|
|
|
NS_COM
|
2000-08-05 03:32:36 +00:00
|
|
|
char*
|
2001-04-02 19:40:52 +00:00
|
|
|
ToNewCString( const nsACString& aSource )
|
2000-08-05 00:51:37 +00:00
|
|
|
{
|
2000-08-05 03:32:36 +00:00
|
|
|
// no conversion needed, just allocate a buffer of the correct length and copy into it
|
|
|
|
|
|
|
|
char* result = AllocateStringCopy(aSource, (char*)0);
|
2005-03-01 05:14:22 +00:00
|
|
|
if (!result)
|
|
|
|
return nsnull;
|
2000-09-02 04:10:44 +00:00
|
|
|
|
2001-09-25 09:35:50 +00:00
|
|
|
nsACString::const_iterator fromBegin, fromEnd;
|
2000-09-02 04:10:44 +00:00
|
|
|
char* toBegin = result;
|
|
|
|
*copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), toBegin) = char(0);
|
2000-08-05 02:13:59 +00:00
|
|
|
return result;
|
2000-08-05 00:51:37 +00:00
|
|
|
}
|
|
|
|
|
2000-08-05 07:44:08 +00:00
|
|
|
NS_COM
|
2000-08-05 03:32:36 +00:00
|
|
|
PRUnichar*
|
2001-04-02 19:40:52 +00:00
|
|
|
ToNewUnicode( const nsAString& aSource )
|
2000-08-05 03:32:36 +00:00
|
|
|
{
|
|
|
|
// no conversion needed, just allocate a buffer of the correct length and copy into it
|
2000-08-05 01:15:45 +00:00
|
|
|
|
2000-08-05 03:32:36 +00:00
|
|
|
PRUnichar* result = AllocateStringCopy(aSource, (PRUnichar*)0);
|
2005-03-01 05:14:22 +00:00
|
|
|
if (!result)
|
|
|
|
return nsnull;
|
2000-09-02 04:10:44 +00:00
|
|
|
|
2001-09-25 09:35:50 +00:00
|
|
|
nsAString::const_iterator fromBegin, fromEnd;
|
2000-09-02 04:10:44 +00:00
|
|
|
PRUnichar* toBegin = result;
|
|
|
|
*copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), toBegin) = PRUnichar(0);
|
2000-08-05 03:32:36 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2000-08-05 07:44:08 +00:00
|
|
|
NS_COM
|
2000-08-05 03:32:36 +00:00
|
|
|
PRUnichar*
|
2001-04-02 19:40:52 +00:00
|
|
|
ToNewUnicode( const nsACString& aSource )
|
2000-08-05 03:32:36 +00:00
|
|
|
{
|
|
|
|
PRUnichar* result = AllocateStringCopy(aSource, (PRUnichar*)0);
|
2005-03-01 05:14:22 +00:00
|
|
|
if (!result)
|
|
|
|
return nsnull;
|
2000-09-02 04:10:44 +00:00
|
|
|
|
2001-09-25 09:35:50 +00:00
|
|
|
nsACString::const_iterator fromBegin, fromEnd;
|
2000-09-02 04:10:44 +00:00
|
|
|
LossyConvertEncoding<char, PRUnichar> converter(result);
|
|
|
|
copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter).write_terminator();
|
2000-08-05 03:32:36 +00:00
|
|
|
return result;
|
|
|
|
}
|
2000-08-05 01:15:45 +00:00
|
|
|
|
2003-05-21 22:20:27 +00:00
|
|
|
NS_COM
|
|
|
|
PRUnichar*
|
2004-05-13 17:45:03 +00:00
|
|
|
UTF8ToNewUnicode( const nsACString& aSource, PRUint32 *aUTF16Count )
|
2003-05-21 22:20:27 +00:00
|
|
|
{
|
|
|
|
nsACString::const_iterator start, end;
|
|
|
|
CalculateUTF8Length calculator;
|
|
|
|
copy_string(aSource.BeginReading(start), aSource.EndReading(end),
|
|
|
|
calculator);
|
|
|
|
|
2004-05-13 17:45:03 +00:00
|
|
|
if (aUTF16Count)
|
|
|
|
*aUTF16Count = calculator.Length();
|
|
|
|
|
2007-07-08 07:08:04 +00:00
|
|
|
PRUnichar *result = static_cast<PRUnichar*>
|
|
|
|
(nsMemory::Alloc(sizeof(PRUnichar) * (calculator.Length() + 1)));
|
2005-03-01 05:14:22 +00:00
|
|
|
if (!result)
|
|
|
|
return nsnull;
|
2003-05-21 22:20:27 +00:00
|
|
|
|
2003-06-23 04:30:57 +00:00
|
|
|
ConvertUTF8toUTF16 converter(result);
|
2003-05-21 22:20:27 +00:00
|
|
|
copy_string(aSource.BeginReading(start), aSource.EndReading(end),
|
2003-05-22 21:25:43 +00:00
|
|
|
converter).write_terminator();
|
2003-05-21 22:20:27 +00:00
|
|
|
NS_ASSERTION(calculator.Length() == converter.Length(), "length mismatch");
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2000-08-23 17:27:06 +00:00
|
|
|
NS_COM
|
|
|
|
PRUnichar*
|
2001-04-02 19:40:52 +00:00
|
|
|
CopyUnicodeTo( const nsAString& aSource, PRUint32 aSrcOffset, PRUnichar* aDest, PRUint32 aLength )
|
2000-08-23 17:27:06 +00:00
|
|
|
{
|
2001-09-25 09:35:50 +00:00
|
|
|
nsAString::const_iterator fromBegin, fromEnd;
|
2000-12-12 21:58:14 +00:00
|
|
|
PRUnichar* toBegin = aDest;
|
|
|
|
copy_string(aSource.BeginReading(fromBegin).advance( PRInt32(aSrcOffset) ), aSource.BeginReading(fromEnd).advance( PRInt32(aSrcOffset+aLength) ), toBegin);
|
2000-08-23 17:27:06 +00:00
|
|
|
return aDest;
|
|
|
|
}
|
|
|
|
|
2000-12-12 21:58:14 +00:00
|
|
|
NS_COM
|
|
|
|
void
|
2001-09-25 09:35:50 +00:00
|
|
|
CopyUnicodeTo( const nsAString::const_iterator& aSrcStart,
|
|
|
|
const nsAString::const_iterator& aSrcEnd,
|
2001-04-02 19:40:52 +00:00
|
|
|
nsAString& aDest )
|
2000-12-12 21:58:14 +00:00
|
|
|
{
|
2001-09-25 09:35:50 +00:00
|
|
|
nsAString::iterator writer;
|
2007-07-03 06:03:11 +00:00
|
|
|
if (!SetLengthForWriting(aDest, Distance(aSrcStart, aSrcEnd)))
|
|
|
|
return;
|
|
|
|
|
2000-12-12 21:58:14 +00:00
|
|
|
aDest.BeginWriting(writer);
|
2001-09-25 09:35:50 +00:00
|
|
|
nsAString::const_iterator fromBegin(aSrcStart);
|
2000-12-12 21:58:14 +00:00
|
|
|
|
|
|
|
copy_string(fromBegin, aSrcEnd, writer);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_COM
|
|
|
|
void
|
2001-09-25 09:35:50 +00:00
|
|
|
AppendUnicodeTo( const nsAString::const_iterator& aSrcStart,
|
|
|
|
const nsAString::const_iterator& aSrcEnd,
|
2001-04-02 19:40:52 +00:00
|
|
|
nsAString& aDest )
|
2000-12-12 21:58:14 +00:00
|
|
|
{
|
2001-09-25 09:35:50 +00:00
|
|
|
nsAString::iterator writer;
|
2000-12-12 21:58:14 +00:00
|
|
|
PRUint32 oldLength = aDest.Length();
|
2007-07-03 06:03:11 +00:00
|
|
|
if(!SetLengthForWriting(aDest, oldLength + Distance(aSrcStart, aSrcEnd)))
|
|
|
|
return;
|
|
|
|
|
2000-12-12 21:58:14 +00:00
|
|
|
aDest.BeginWriting(writer).advance(oldLength);
|
2001-09-25 09:35:50 +00:00
|
|
|
nsAString::const_iterator fromBegin(aSrcStart);
|
2000-12-12 21:58:14 +00:00
|
|
|
|
|
|
|
copy_string(fromBegin, aSrcEnd, writer);
|
|
|
|
}
|
|
|
|
|
2000-08-05 07:44:08 +00:00
|
|
|
NS_COM
|
2000-08-05 00:51:37 +00:00
|
|
|
PRBool
|
2001-04-02 19:40:52 +00:00
|
|
|
IsASCII( const nsAString& aString )
|
2000-08-05 00:51:37 +00:00
|
|
|
{
|
2000-08-05 04:25:49 +00:00
|
|
|
static const PRUnichar NOT_ASCII = PRUnichar(~0x007F);
|
2000-08-05 00:51:37 +00:00
|
|
|
|
|
|
|
|
|
|
|
// Don't want to use |copy_string| for this task, since we can stop at the first non-ASCII character
|
|
|
|
|
2001-09-25 09:35:50 +00:00
|
|
|
nsAString::const_iterator done_reading;
|
2000-09-02 04:10:44 +00:00
|
|
|
aString.EndReading(done_reading);
|
2000-08-05 00:51:37 +00:00
|
|
|
|
2000-08-05 03:32:36 +00:00
|
|
|
// for each chunk of |aString|...
|
2000-09-02 04:10:44 +00:00
|
|
|
PRUint32 fragmentLength = 0;
|
2001-09-25 09:35:50 +00:00
|
|
|
nsAString::const_iterator iter;
|
2000-09-02 04:10:44 +00:00
|
|
|
for ( aString.BeginReading(iter); iter != done_reading; iter.advance( PRInt32(fragmentLength) ) )
|
2000-08-05 00:51:37 +00:00
|
|
|
{
|
2000-09-09 07:30:55 +00:00
|
|
|
fragmentLength = PRUint32(iter.size_forward());
|
2000-08-05 00:51:37 +00:00
|
|
|
const PRUnichar* c = iter.get();
|
2000-09-02 04:10:44 +00:00
|
|
|
const PRUnichar* fragmentEnd = c + fragmentLength;
|
2000-08-05 00:51:37 +00:00
|
|
|
|
|
|
|
// for each character in this chunk...
|
2000-09-02 04:10:44 +00:00
|
|
|
while ( c < fragmentEnd )
|
2000-08-05 00:51:37 +00:00
|
|
|
if ( *c++ & NOT_ASCII )
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return PR_TRUE;
|
2000-08-05 02:13:59 +00:00
|
|
|
}
|
|
|
|
|
2002-03-06 07:48:55 +00:00
|
|
|
NS_COM
|
|
|
|
PRBool
|
|
|
|
IsASCII( const nsACString& aString )
|
|
|
|
{
|
|
|
|
static const char NOT_ASCII = char(~0x7F);
|
|
|
|
|
|
|
|
|
|
|
|
// Don't want to use |copy_string| for this task, since we can stop at the first non-ASCII character
|
|
|
|
|
|
|
|
nsACString::const_iterator done_reading;
|
|
|
|
aString.EndReading(done_reading);
|
|
|
|
|
|
|
|
// for each chunk of |aString|...
|
|
|
|
PRUint32 fragmentLength = 0;
|
|
|
|
nsACString::const_iterator iter;
|
|
|
|
for ( aString.BeginReading(iter); iter != done_reading; iter.advance( PRInt32(fragmentLength) ) )
|
|
|
|
{
|
|
|
|
fragmentLength = PRUint32(iter.size_forward());
|
|
|
|
const char* c = iter.get();
|
|
|
|
const char* fragmentEnd = c + fragmentLength;
|
|
|
|
|
|
|
|
// for each character in this chunk...
|
|
|
|
while ( c < fragmentEnd )
|
|
|
|
if ( *c++ & NOT_ASCII )
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
2003-03-25 08:11:13 +00:00
|
|
|
NS_COM
|
|
|
|
PRBool
|
|
|
|
IsUTF8( const nsACString& aString )
|
|
|
|
{
|
|
|
|
nsReadingIterator<char> done_reading;
|
|
|
|
aString.EndReading(done_reading);
|
|
|
|
|
|
|
|
PRInt32 state = 0;
|
|
|
|
PRBool overlong = PR_FALSE;
|
|
|
|
PRBool surrogate = PR_FALSE;
|
|
|
|
PRBool nonchar = PR_FALSE;
|
|
|
|
PRUint16 olupper = 0; // overlong byte upper bound.
|
|
|
|
PRUint16 slower = 0; // surrogate byte lower bound.
|
|
|
|
|
|
|
|
// for each chunk of |aString|...
|
|
|
|
PRUint32 fragmentLength = 0;
|
|
|
|
nsReadingIterator<char> iter;
|
2000-09-09 07:30:55 +00:00
|
|
|
|
2003-03-25 08:11:13 +00:00
|
|
|
for ( aString.BeginReading(iter); iter != done_reading; iter.advance( PRInt32(fragmentLength) ) )
|
|
|
|
{
|
|
|
|
fragmentLength = PRUint32(iter.size_forward());
|
|
|
|
const char* ptr = iter.get();
|
|
|
|
const char* fragmentEnd = ptr + fragmentLength;
|
|
|
|
|
|
|
|
// for each character in this chunk...
|
|
|
|
while ( ptr < fragmentEnd )
|
|
|
|
{
|
|
|
|
PRUint8 c;
|
|
|
|
|
|
|
|
if (0 == state)
|
|
|
|
{
|
|
|
|
c = *ptr++;
|
|
|
|
|
|
|
|
if ( UTF8traits::isASCII(c) )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ( c <= 0xC1 ) // [80-BF] where not expected, [C0-C1] for overlong.
|
|
|
|
return PR_FALSE;
|
|
|
|
else if ( UTF8traits::is2byte(c) )
|
|
|
|
state = 1;
|
|
|
|
else if ( UTF8traits::is3byte(c) )
|
|
|
|
{
|
|
|
|
state = 2;
|
|
|
|
if ( c == 0xE0 ) // to exclude E0[80-9F][80-BF]
|
|
|
|
{
|
|
|
|
overlong = PR_TRUE;
|
|
|
|
olupper = 0x9F;
|
|
|
|
}
|
|
|
|
else if ( c == 0xED ) // ED[A0-BF][80-BF] : surrogate codepoint
|
|
|
|
{
|
|
|
|
surrogate = PR_TRUE;
|
|
|
|
slower = 0xA0;
|
|
|
|
}
|
|
|
|
else if ( c == 0xEF ) // EF BF [BE-BF] : non-character
|
|
|
|
nonchar = PR_TRUE;
|
|
|
|
}
|
|
|
|
else if ( c <= 0xF4 ) // XXX replace /w UTF8traits::is4byte when it's updated to exclude [F5-F7].(bug 199090)
|
|
|
|
{
|
|
|
|
state = 3;
|
|
|
|
nonchar = PR_TRUE;
|
|
|
|
if ( c == 0xF0 ) // to exclude F0[80-8F][80-BF]{2}
|
|
|
|
{
|
|
|
|
overlong = PR_TRUE;
|
|
|
|
olupper = 0x8F;
|
|
|
|
}
|
|
|
|
else if ( c == 0xF4 ) // to exclude F4[90-BF][80-BF]
|
|
|
|
{
|
|
|
|
// actually not surrogates but codepoints beyond 0x10FFFF
|
|
|
|
surrogate = PR_TRUE;
|
|
|
|
slower = 0x90;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2003-06-23 04:30:57 +00:00
|
|
|
return PR_FALSE; // Not UTF-8 string
|
2003-03-25 08:11:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
while (ptr < fragmentEnd && state)
|
|
|
|
{
|
|
|
|
c = *ptr++;
|
|
|
|
--state;
|
|
|
|
|
|
|
|
// non-character : EF BF [BE-BF] or F[0-7] [89AB]F BF [BE-BF]
|
|
|
|
if ( nonchar && ( !state && c < 0xBE ||
|
|
|
|
state == 1 && c != 0xBF ||
|
|
|
|
state == 2 && 0x0F != (0x0F & c) ))
|
|
|
|
nonchar = PR_FALSE;
|
|
|
|
|
|
|
|
if ( !UTF8traits::isInSeq(c) || overlong && c <= olupper ||
|
|
|
|
surrogate && slower <= c || nonchar && !state )
|
2003-06-23 04:30:57 +00:00
|
|
|
return PR_FALSE; // Not UTF-8 string
|
2003-03-25 08:11:13 +00:00
|
|
|
overlong = surrogate = PR_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return !state; // state != 0 at the end indicates an invalid UTF-8 seq.
|
|
|
|
}
|
2000-09-09 07:30:55 +00:00
|
|
|
|
|
|
|
/**
|
2001-12-08 07:08:38 +00:00
|
|
|
* A character sink for in-place case conversion.
|
2000-09-09 07:30:55 +00:00
|
|
|
*/
|
|
|
|
class ConvertToUpperCase
|
|
|
|
{
|
|
|
|
public:
|
2001-11-28 04:59:29 +00:00
|
|
|
typedef char value_type;
|
2000-09-09 07:30:55 +00:00
|
|
|
|
|
|
|
PRUint32
|
2001-11-28 04:59:29 +00:00
|
|
|
write( const char* aSource, PRUint32 aSourceLength )
|
2000-09-09 07:30:55 +00:00
|
|
|
{
|
2007-07-08 07:08:04 +00:00
|
|
|
char* cp = const_cast<char*>(aSource);
|
2001-11-28 04:59:29 +00:00
|
|
|
const char* end = aSource + aSourceLength;
|
|
|
|
while (cp != end) {
|
|
|
|
char ch = *cp;
|
|
|
|
if ((ch >= 'a') && (ch <= 'z'))
|
|
|
|
*cp = ch - ('a' - 'A');
|
|
|
|
++cp;
|
|
|
|
}
|
2000-09-09 07:30:55 +00:00
|
|
|
return aSourceLength;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2005-01-24 16:44:41 +00:00
|
|
|
#ifdef MOZ_V1_STRING_ABI
|
2000-09-09 07:30:55 +00:00
|
|
|
NS_COM
|
|
|
|
void
|
2001-04-02 19:40:52 +00:00
|
|
|
ToUpperCase( nsACString& aCString )
|
2000-09-09 07:30:55 +00:00
|
|
|
{
|
2001-04-02 19:40:52 +00:00
|
|
|
nsACString::iterator fromBegin, fromEnd;
|
2001-11-28 04:59:29 +00:00
|
|
|
ConvertToUpperCase converter;
|
2000-09-09 07:30:55 +00:00
|
|
|
copy_string(aCString.BeginWriting(fromBegin), aCString.EndWriting(fromEnd), converter);
|
|
|
|
}
|
2005-01-24 16:44:41 +00:00
|
|
|
#endif
|
2000-09-09 07:30:55 +00:00
|
|
|
|
2001-12-23 02:56:41 +00:00
|
|
|
NS_COM
|
|
|
|
void
|
2004-02-19 02:44:03 +00:00
|
|
|
ToUpperCase( nsCSubstring& aCString )
|
2001-12-23 02:56:41 +00:00
|
|
|
{
|
|
|
|
ConvertToUpperCase converter;
|
|
|
|
char* start;
|
|
|
|
converter.write(aCString.BeginWriting(start), aCString.Length());
|
|
|
|
}
|
|
|
|
|
2001-12-08 07:08:38 +00:00
|
|
|
/**
|
|
|
|
* A character sink for copying with case conversion.
|
|
|
|
*/
|
|
|
|
class CopyToUpperCase
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
typedef char value_type;
|
|
|
|
|
|
|
|
CopyToUpperCase( nsACString::iterator& aDestIter )
|
|
|
|
: mIter(aDestIter)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint32
|
|
|
|
write( const char* aSource, PRUint32 aSourceLength )
|
|
|
|
{
|
|
|
|
PRUint32 len = PR_MIN(PRUint32(mIter.size_forward()), aSourceLength);
|
|
|
|
char* cp = mIter.get();
|
|
|
|
const char* end = aSource + len;
|
|
|
|
while (aSource != end) {
|
|
|
|
char ch = *aSource;
|
|
|
|
if ((ch >= 'a') && (ch <= 'z'))
|
|
|
|
*cp = ch - ('a' - 'A');
|
2002-05-01 14:02:11 +00:00
|
|
|
else
|
|
|
|
*cp = ch;
|
2001-12-08 07:08:38 +00:00
|
|
|
++aSource;
|
|
|
|
++cp;
|
|
|
|
}
|
|
|
|
mIter.advance(len);
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
nsACString::iterator& mIter;
|
|
|
|
};
|
|
|
|
|
|
|
|
NS_COM
|
|
|
|
void
|
|
|
|
ToUpperCase( const nsACString& aSource, nsACString& aDest )
|
|
|
|
{
|
|
|
|
nsACString::const_iterator fromBegin, fromEnd;
|
|
|
|
nsACString::iterator toBegin;
|
2007-07-03 06:03:11 +00:00
|
|
|
if (!SetLengthForWritingC(aDest, aSource.Length()))
|
|
|
|
return;
|
|
|
|
|
2001-12-08 07:08:38 +00:00
|
|
|
CopyToUpperCase converter(aDest.BeginWriting(toBegin));
|
|
|
|
copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter);
|
|
|
|
}
|
|
|
|
|
2000-09-09 07:30:55 +00:00
|
|
|
/**
|
|
|
|
* A character sink for case conversion.
|
|
|
|
*/
|
|
|
|
class ConvertToLowerCase
|
|
|
|
{
|
|
|
|
public:
|
2001-11-28 04:59:29 +00:00
|
|
|
typedef char value_type;
|
2000-09-09 07:30:55 +00:00
|
|
|
|
|
|
|
PRUint32
|
2001-11-28 04:59:29 +00:00
|
|
|
write( const char* aSource, PRUint32 aSourceLength )
|
2000-09-09 07:30:55 +00:00
|
|
|
{
|
2007-07-08 07:08:04 +00:00
|
|
|
char* cp = const_cast<char*>(aSource);
|
2001-11-28 04:59:29 +00:00
|
|
|
const char* end = aSource + aSourceLength;
|
|
|
|
while (cp != end) {
|
|
|
|
char ch = *cp;
|
|
|
|
if ((ch >= 'A') && (ch <= 'Z'))
|
|
|
|
*cp = ch + ('a' - 'A');
|
|
|
|
++cp;
|
|
|
|
}
|
2000-09-09 07:30:55 +00:00
|
|
|
return aSourceLength;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2005-01-24 16:44:41 +00:00
|
|
|
#ifdef MOZ_V1_STRING_ABI
|
2000-09-09 07:30:55 +00:00
|
|
|
NS_COM
|
|
|
|
void
|
2001-04-02 19:40:52 +00:00
|
|
|
ToLowerCase( nsACString& aCString )
|
2000-09-09 07:30:55 +00:00
|
|
|
{
|
2001-04-02 19:40:52 +00:00
|
|
|
nsACString::iterator fromBegin, fromEnd;
|
2001-11-28 04:59:29 +00:00
|
|
|
ConvertToLowerCase converter;
|
2000-09-09 07:30:55 +00:00
|
|
|
copy_string(aCString.BeginWriting(fromBegin), aCString.EndWriting(fromEnd), converter);
|
|
|
|
}
|
2005-01-24 16:44:41 +00:00
|
|
|
#endif
|
2000-12-12 21:58:14 +00:00
|
|
|
|
2001-12-23 02:56:41 +00:00
|
|
|
NS_COM
|
|
|
|
void
|
2004-02-19 02:44:03 +00:00
|
|
|
ToLowerCase( nsCSubstring& aCString )
|
2001-12-23 02:56:41 +00:00
|
|
|
{
|
|
|
|
ConvertToLowerCase converter;
|
|
|
|
char* start;
|
|
|
|
converter.write(aCString.BeginWriting(start), aCString.Length());
|
|
|
|
}
|
|
|
|
|
2001-12-08 07:08:38 +00:00
|
|
|
/**
|
|
|
|
* A character sink for copying with case conversion.
|
|
|
|
*/
|
|
|
|
class CopyToLowerCase
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
typedef char value_type;
|
|
|
|
|
|
|
|
CopyToLowerCase( nsACString::iterator& aDestIter )
|
|
|
|
: mIter(aDestIter)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint32
|
|
|
|
write( const char* aSource, PRUint32 aSourceLength )
|
|
|
|
{
|
|
|
|
PRUint32 len = PR_MIN(PRUint32(mIter.size_forward()), aSourceLength);
|
|
|
|
char* cp = mIter.get();
|
|
|
|
const char* end = aSource + len;
|
|
|
|
while (aSource != end) {
|
|
|
|
char ch = *aSource;
|
|
|
|
if ((ch >= 'A') && (ch <= 'Z'))
|
|
|
|
*cp = ch + ('a' - 'A');
|
2002-05-01 14:02:11 +00:00
|
|
|
else
|
|
|
|
*cp = ch;
|
2001-12-08 07:08:38 +00:00
|
|
|
++aSource;
|
|
|
|
++cp;
|
|
|
|
}
|
|
|
|
mIter.advance(len);
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
nsACString::iterator& mIter;
|
|
|
|
};
|
|
|
|
|
|
|
|
NS_COM
|
|
|
|
void
|
|
|
|
ToLowerCase( const nsACString& aSource, nsACString& aDest )
|
|
|
|
{
|
|
|
|
nsACString::const_iterator fromBegin, fromEnd;
|
|
|
|
nsACString::iterator toBegin;
|
2007-07-03 06:03:11 +00:00
|
|
|
if (!SetLengthForWritingC(aDest, aSource.Length()))
|
|
|
|
return;
|
|
|
|
|
2001-12-08 07:08:38 +00:00
|
|
|
CopyToLowerCase converter(aDest.BeginWriting(toBegin));
|
|
|
|
copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter);
|
|
|
|
}
|
|
|
|
|
2001-05-13 07:03:29 +00:00
|
|
|
template <class StringT, class IteratorT, class Comparator>
|
2000-12-12 21:58:14 +00:00
|
|
|
PRBool
|
2001-05-13 07:03:29 +00:00
|
|
|
FindInReadable_Impl( const StringT& aPattern, IteratorT& aSearchStart, IteratorT& aSearchEnd, const Comparator& compare )
|
2000-12-12 21:58:14 +00:00
|
|
|
{
|
|
|
|
PRBool found_it = PR_FALSE;
|
|
|
|
|
|
|
|
// only bother searching at all if we're given a non-empty range to search
|
|
|
|
if ( aSearchStart != aSearchEnd )
|
|
|
|
{
|
2001-05-13 07:03:29 +00:00
|
|
|
IteratorT aPatternStart, aPatternEnd;
|
2000-12-12 21:58:14 +00:00
|
|
|
aPattern.BeginReading(aPatternStart);
|
|
|
|
aPattern.EndReading(aPatternEnd);
|
|
|
|
|
|
|
|
// outer loop keeps searching till we find it or run out of string to search
|
|
|
|
while ( !found_it )
|
|
|
|
{
|
|
|
|
// fast inner loop (that's what it's called, not what it is) looks for a potential match
|
2001-10-30 03:39:18 +00:00
|
|
|
while ( aSearchStart != aSearchEnd &&
|
|
|
|
compare(*aPatternStart, *aSearchStart) )
|
2000-12-12 21:58:14 +00:00
|
|
|
++aSearchStart;
|
|
|
|
|
|
|
|
// if we broke out of the `fast' loop because we're out of string ... we're done: no match
|
|
|
|
if ( aSearchStart == aSearchEnd )
|
|
|
|
break;
|
|
|
|
|
|
|
|
// otherwise, we're at a potential match, let's see if we really hit one
|
2001-05-13 07:03:29 +00:00
|
|
|
IteratorT testPattern(aPatternStart);
|
|
|
|
IteratorT testSearch(aSearchStart);
|
2000-12-12 21:58:14 +00:00
|
|
|
|
|
|
|
// slow inner loop verifies the potential match (found by the `fast' loop) at the current position
|
|
|
|
for(;;)
|
|
|
|
{
|
|
|
|
// we already compared the first character in the outer loop,
|
|
|
|
// so we'll advance before the next comparison
|
|
|
|
++testPattern;
|
|
|
|
++testSearch;
|
|
|
|
|
|
|
|
// if we verified all the way to the end of the pattern, then we found it!
|
|
|
|
if ( testPattern == aPatternEnd )
|
|
|
|
{
|
|
|
|
found_it = PR_TRUE;
|
|
|
|
aSearchEnd = testSearch; // return the exact found range through the parameters
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if we got to end of the string we're searching before we hit the end of the
|
|
|
|
// pattern, we'll never find what we're looking for
|
|
|
|
if ( testSearch == aSearchEnd )
|
|
|
|
{
|
|
|
|
aSearchStart = aSearchEnd;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// else if we mismatched ... it's time to advance to the next search position
|
|
|
|
// and get back into the `fast' loop
|
2001-10-30 03:39:18 +00:00
|
|
|
if ( compare(*testPattern, *testSearch) )
|
2000-12-12 21:58:14 +00:00
|
|
|
{
|
|
|
|
++aSearchStart;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return found_it;
|
|
|
|
}
|
|
|
|
|
2001-04-02 22:00:34 +00:00
|
|
|
|
2001-05-13 05:16:10 +00:00
|
|
|
NS_COM
|
|
|
|
PRBool
|
2001-10-30 03:39:18 +00:00
|
|
|
FindInReadable( const nsAString& aPattern, nsAString::const_iterator& aSearchStart, nsAString::const_iterator& aSearchEnd, const nsStringComparator& aComparator )
|
2001-05-13 05:16:10 +00:00
|
|
|
{
|
2001-10-30 03:39:18 +00:00
|
|
|
return FindInReadable_Impl(aPattern, aSearchStart, aSearchEnd, aComparator);
|
2001-05-13 05:16:10 +00:00
|
|
|
}
|
2001-04-02 22:00:34 +00:00
|
|
|
|
2001-05-13 05:16:10 +00:00
|
|
|
NS_COM
|
|
|
|
PRBool
|
2001-10-30 03:39:18 +00:00
|
|
|
FindInReadable( const nsACString& aPattern, nsACString::const_iterator& aSearchStart, nsACString::const_iterator& aSearchEnd, const nsCStringComparator& aComparator)
|
2001-05-13 05:16:10 +00:00
|
|
|
{
|
2001-10-30 03:39:18 +00:00
|
|
|
return FindInReadable_Impl(aPattern, aSearchStart, aSearchEnd, aComparator);
|
2001-05-13 05:16:10 +00:00
|
|
|
}
|
2001-04-02 22:00:34 +00:00
|
|
|
|
2001-05-13 05:16:10 +00:00
|
|
|
NS_COM
|
|
|
|
PRBool
|
2001-09-25 09:35:50 +00:00
|
|
|
CaseInsensitiveFindInReadable( const nsACString& aPattern, nsACString::const_iterator& aSearchStart, nsACString::const_iterator& aSearchEnd )
|
2001-05-13 05:16:10 +00:00
|
|
|
{
|
2001-10-30 03:39:18 +00:00
|
|
|
return FindInReadable_Impl(aPattern, aSearchStart, aSearchEnd, nsCaseInsensitiveCStringComparator());
|
2000-12-12 21:58:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This implementation is simple, but does too much work.
|
|
|
|
* It searches the entire string from left to right, and returns the last match found, if any.
|
|
|
|
* This implementation will be replaced when I get |reverse_iterator|s working.
|
|
|
|
*/
|
2001-04-02 22:00:34 +00:00
|
|
|
NS_COM
|
2000-12-12 21:58:14 +00:00
|
|
|
PRBool
|
2002-03-19 06:46:56 +00:00
|
|
|
RFindInReadable( const nsAString& aPattern, nsAString::const_iterator& aSearchStart, nsAString::const_iterator& aSearchEnd, const nsStringComparator& aComparator)
|
2000-12-12 21:58:14 +00:00
|
|
|
{
|
|
|
|
PRBool found_it = PR_FALSE;
|
|
|
|
|
2001-09-25 09:35:50 +00:00
|
|
|
nsAString::const_iterator savedSearchEnd(aSearchEnd);
|
|
|
|
nsAString::const_iterator searchStart(aSearchStart), searchEnd(aSearchEnd);
|
2000-12-12 21:58:14 +00:00
|
|
|
|
|
|
|
while ( searchStart != searchEnd )
|
|
|
|
{
|
2002-03-19 06:46:56 +00:00
|
|
|
if ( FindInReadable(aPattern, searchStart, searchEnd, aComparator) )
|
2000-12-12 21:58:14 +00:00
|
|
|
{
|
|
|
|
found_it = PR_TRUE;
|
|
|
|
|
|
|
|
// this is the best match so far, so remember it
|
|
|
|
aSearchStart = searchStart;
|
|
|
|
aSearchEnd = searchEnd;
|
|
|
|
|
|
|
|
// ...and get ready to search some more
|
|
|
|
// (it's tempting to set |searchStart=searchEnd| ... but that misses overlapping patterns)
|
|
|
|
++searchStart;
|
|
|
|
searchEnd = savedSearchEnd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if we never found it, return an empty range
|
|
|
|
if ( !found_it )
|
|
|
|
aSearchStart = aSearchEnd;
|
|
|
|
|
|
|
|
return found_it;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_COM
|
|
|
|
PRBool
|
2002-03-19 06:46:56 +00:00
|
|
|
RFindInReadable( const nsACString& aPattern, nsACString::const_iterator& aSearchStart, nsACString::const_iterator& aSearchEnd, const nsCStringComparator& aComparator)
|
2000-12-12 21:58:14 +00:00
|
|
|
{
|
2001-04-02 22:00:34 +00:00
|
|
|
PRBool found_it = PR_FALSE;
|
|
|
|
|
2001-09-25 09:35:50 +00:00
|
|
|
nsACString::const_iterator savedSearchEnd(aSearchEnd);
|
|
|
|
nsACString::const_iterator searchStart(aSearchStart), searchEnd(aSearchEnd);
|
2001-04-02 22:00:34 +00:00
|
|
|
|
|
|
|
while ( searchStart != searchEnd )
|
|
|
|
{
|
2002-03-19 06:46:56 +00:00
|
|
|
if ( FindInReadable(aPattern, searchStart, searchEnd, aComparator) )
|
2001-04-02 22:00:34 +00:00
|
|
|
{
|
|
|
|
found_it = PR_TRUE;
|
|
|
|
|
|
|
|
// this is the best match so far, so remember it
|
|
|
|
aSearchStart = searchStart;
|
|
|
|
aSearchEnd = searchEnd;
|
|
|
|
|
|
|
|
// ...and get ready to search some more
|
|
|
|
// (it's tempting to set |searchStart=searchEnd| ... but that misses overlapping patterns)
|
|
|
|
++searchStart;
|
|
|
|
searchEnd = savedSearchEnd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if we never found it, return an empty range
|
|
|
|
if ( !found_it )
|
|
|
|
aSearchStart = aSearchEnd;
|
|
|
|
|
|
|
|
return found_it;
|
2000-12-12 21:58:14 +00:00
|
|
|
}
|
|
|
|
|
2001-04-02 22:00:34 +00:00
|
|
|
NS_COM
|
|
|
|
PRBool
|
2001-09-25 09:35:50 +00:00
|
|
|
FindCharInReadable( PRUnichar aChar, nsAString::const_iterator& aSearchStart, const nsAString::const_iterator& aSearchEnd )
|
2000-12-12 21:58:14 +00:00
|
|
|
{
|
2004-02-19 02:44:03 +00:00
|
|
|
PRInt32 fragmentLength = aSearchEnd.get() - aSearchStart.get();
|
2000-12-12 21:58:14 +00:00
|
|
|
|
2004-02-19 02:44:03 +00:00
|
|
|
const PRUnichar* charFoundAt = nsCharTraits<PRUnichar>::find(aSearchStart.get(), fragmentLength, aChar);
|
|
|
|
if ( charFoundAt ) {
|
|
|
|
aSearchStart.advance( charFoundAt - aSearchStart.get() );
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
2000-12-12 21:58:14 +00:00
|
|
|
|
2004-02-19 02:44:03 +00:00
|
|
|
aSearchStart.advance(fragmentLength);
|
2000-12-12 21:58:14 +00:00
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_COM
|
|
|
|
PRBool
|
2001-09-25 09:35:50 +00:00
|
|
|
FindCharInReadable( char aChar, nsACString::const_iterator& aSearchStart, const nsACString::const_iterator& aSearchEnd )
|
2000-12-12 21:58:14 +00:00
|
|
|
{
|
2004-02-19 02:44:03 +00:00
|
|
|
PRInt32 fragmentLength = aSearchEnd.get() - aSearchStart.get();
|
2001-04-02 22:00:34 +00:00
|
|
|
|
2004-02-19 02:44:03 +00:00
|
|
|
const char* charFoundAt = nsCharTraits<char>::find(aSearchStart.get(), fragmentLength, aChar);
|
|
|
|
if ( charFoundAt ) {
|
|
|
|
aSearchStart.advance( charFoundAt - aSearchStart.get() );
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
2001-04-02 22:00:34 +00:00
|
|
|
|
2004-02-19 02:44:03 +00:00
|
|
|
aSearchStart.advance(fragmentLength);
|
2001-04-02 22:00:34 +00:00
|
|
|
return PR_FALSE;
|
2000-12-12 21:58:14 +00:00
|
|
|
}
|
|
|
|
|
2001-04-02 22:00:34 +00:00
|
|
|
NS_COM
|
2000-12-12 21:58:14 +00:00
|
|
|
PRUint32
|
2001-04-02 22:00:34 +00:00
|
|
|
CountCharInReadable( const nsAString& aStr,
|
|
|
|
PRUnichar aChar )
|
2000-12-12 21:58:14 +00:00
|
|
|
{
|
|
|
|
PRUint32 count = 0;
|
2001-09-25 09:35:50 +00:00
|
|
|
nsAString::const_iterator begin, end;
|
2000-12-12 21:58:14 +00:00
|
|
|
|
|
|
|
aStr.BeginReading(begin);
|
|
|
|
aStr.EndReading(end);
|
|
|
|
|
|
|
|
while (begin != end) {
|
|
|
|
if (*begin == aChar) {
|
2001-06-19 22:38:45 +00:00
|
|
|
++count;
|
2000-12-12 21:58:14 +00:00
|
|
|
}
|
2001-06-19 22:38:45 +00:00
|
|
|
++begin;
|
2000-12-12 21:58:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_COM
|
|
|
|
PRUint32
|
2001-04-02 19:40:52 +00:00
|
|
|
CountCharInReadable( const nsACString& aStr,
|
2000-12-12 21:58:14 +00:00
|
|
|
char aChar )
|
|
|
|
{
|
2001-04-02 22:00:34 +00:00
|
|
|
PRUint32 count = 0;
|
2001-09-25 09:35:50 +00:00
|
|
|
nsACString::const_iterator begin, end;
|
2001-04-02 22:00:34 +00:00
|
|
|
|
|
|
|
aStr.BeginReading(begin);
|
|
|
|
aStr.EndReading(end);
|
|
|
|
|
|
|
|
while (begin != end) {
|
|
|
|
if (*begin == aChar) {
|
2001-06-19 22:38:45 +00:00
|
|
|
++count;
|
2001-04-02 22:00:34 +00:00
|
|
|
}
|
2001-06-19 22:38:45 +00:00
|
|
|
++begin;
|
2001-04-02 22:00:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
2000-12-12 21:58:14 +00:00
|
|
|
}
|
2002-01-17 04:08:14 +00:00
|
|
|
|
2003-05-21 22:20:27 +00:00
|
|
|
NS_COM PRBool
|
2003-06-21 02:59:51 +00:00
|
|
|
StringBeginsWith( const nsAString& aSource, const nsAString& aSubstring,
|
|
|
|
const nsStringComparator& aComparator )
|
2003-05-21 22:20:27 +00:00
|
|
|
{
|
|
|
|
nsAString::size_type src_len = aSource.Length(),
|
|
|
|
sub_len = aSubstring.Length();
|
|
|
|
if (sub_len > src_len)
|
|
|
|
return PR_FALSE;
|
2003-06-21 02:59:51 +00:00
|
|
|
return Substring(aSource, 0, sub_len).Equals(aSubstring, aComparator);
|
2003-05-21 22:20:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_COM PRBool
|
2003-06-21 02:59:51 +00:00
|
|
|
StringBeginsWith( const nsACString& aSource, const nsACString& aSubstring,
|
|
|
|
const nsCStringComparator& aComparator )
|
2003-05-21 22:20:27 +00:00
|
|
|
{
|
|
|
|
nsACString::size_type src_len = aSource.Length(),
|
|
|
|
sub_len = aSubstring.Length();
|
|
|
|
if (sub_len > src_len)
|
|
|
|
return PR_FALSE;
|
2003-06-21 02:59:51 +00:00
|
|
|
return Substring(aSource, 0, sub_len).Equals(aSubstring, aComparator);
|
2003-05-21 22:20:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_COM PRBool
|
2003-06-21 02:59:51 +00:00
|
|
|
StringEndsWith( const nsAString& aSource, const nsAString& aSubstring,
|
|
|
|
const nsStringComparator& aComparator )
|
2003-05-21 22:20:27 +00:00
|
|
|
{
|
|
|
|
nsAString::size_type src_len = aSource.Length(),
|
|
|
|
sub_len = aSubstring.Length();
|
|
|
|
if (sub_len > src_len)
|
|
|
|
return PR_FALSE;
|
2003-06-21 02:59:51 +00:00
|
|
|
return Substring(aSource, src_len - sub_len, sub_len).Equals(aSubstring,
|
|
|
|
aComparator);
|
2003-05-21 22:20:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_COM PRBool
|
2003-06-21 02:59:51 +00:00
|
|
|
StringEndsWith( const nsACString& aSource, const nsACString& aSubstring,
|
|
|
|
const nsCStringComparator& aComparator )
|
2003-05-21 22:20:27 +00:00
|
|
|
{
|
|
|
|
nsACString::size_type src_len = aSource.Length(),
|
|
|
|
sub_len = aSubstring.Length();
|
|
|
|
if (sub_len > src_len)
|
|
|
|
return PR_FALSE;
|
2003-06-21 02:59:51 +00:00
|
|
|
return Substring(aSource, src_len - sub_len, sub_len).Equals(aSubstring,
|
|
|
|
aComparator);
|
2003-05-21 22:20:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-01-21 21:36:40 +00:00
|
|
|
static const PRUnichar empty_buffer[1] = { '\0' };
|
|
|
|
|
2005-11-04 19:52:18 +00:00
|
|
|
NS_COM
|
|
|
|
const nsAFlatString&
|
|
|
|
EmptyString()
|
2004-01-21 21:36:40 +00:00
|
|
|
{
|
|
|
|
static const nsDependentString sEmpty(empty_buffer);
|
|
|
|
|
|
|
|
return sEmpty;
|
|
|
|
}
|
|
|
|
|
2005-11-04 19:52:18 +00:00
|
|
|
NS_COM
|
|
|
|
const nsAFlatCString&
|
|
|
|
EmptyCString()
|
2004-01-21 21:36:40 +00:00
|
|
|
{
|
|
|
|
static const nsDependentCString sEmpty((const char *)empty_buffer);
|
|
|
|
|
|
|
|
return sEmpty;
|
|
|
|
}
|
2005-11-04 19:52:18 +00:00
|
|
|
|
|
|
|
NS_COM PRInt32
|
|
|
|
CompareUTF8toUTF16(const nsASingleFragmentCString& aUTF8String,
|
|
|
|
const nsASingleFragmentString& aUTF16String)
|
|
|
|
{
|
|
|
|
static const PRUint32 NOT_ASCII = PRUint32(~0x7F);
|
|
|
|
|
|
|
|
const char *u8, *u8end;
|
|
|
|
aUTF8String.BeginReading(u8);
|
|
|
|
aUTF8String.EndReading(u8end);
|
|
|
|
|
|
|
|
const PRUnichar *u16, *u16end;
|
|
|
|
aUTF16String.BeginReading(u16);
|
|
|
|
aUTF16String.EndReading(u16end);
|
|
|
|
|
|
|
|
while (u8 != u8end && u16 != u16end)
|
|
|
|
{
|
|
|
|
// Cast away the signedness of *u8 to prevent signextension when
|
|
|
|
// converting to PRUint32
|
|
|
|
PRUint32 c8_32 = (PRUint8)*u8;
|
|
|
|
|
|
|
|
if (c8_32 & NOT_ASCII)
|
|
|
|
{
|
|
|
|
PRBool err;
|
|
|
|
c8_32 = UTF8CharEnumerator::NextChar(&u8, u8end, &err);
|
|
|
|
if (err)
|
|
|
|
return PR_INT32_MIN;
|
|
|
|
|
|
|
|
PRUint32 c16_32 = UTF16CharEnumerator::NextChar(&u16, u16end,
|
|
|
|
&err);
|
|
|
|
if (err)
|
|
|
|
return PR_INT32_MIN;
|
|
|
|
|
|
|
|
if (c8_32 != c16_32)
|
|
|
|
return c8_32 < c16_32 ? -1 : 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (c8_32 != *u16)
|
|
|
|
return c8_32 > *u16 ? 1 : -1;
|
|
|
|
|
|
|
|
++u8;
|
|
|
|
++u16;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (u8 != u8end)
|
|
|
|
{
|
|
|
|
// We get to the end of the UTF16 string, but no to the end of
|
|
|
|
// the UTF8 string. The UTF8 string is longer than the UTF16
|
|
|
|
// string
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (u16 != u16end)
|
|
|
|
{
|
|
|
|
// We get to the end of the UTF8 string, but no to the end of
|
|
|
|
// the UTF16 string. The UTF16 string is longer than the UTF8
|
|
|
|
// string
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The two strings match.
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2005-11-15 18:17:22 +00:00
|
|
|
|
|
|
|
NS_COM
|
|
|
|
void
|
2005-11-20 19:21:48 +00:00
|
|
|
AppendUCS4ToUTF16(const PRUint32 aSource, nsAString& aDest)
|
2005-11-15 18:17:22 +00:00
|
|
|
{
|
|
|
|
NS_ASSERTION(IS_VALID_CHAR(aSource), "Invalid UCS4 char");
|
|
|
|
if (IS_IN_BMP(aSource))
|
|
|
|
{
|
|
|
|
aDest.Append(PRUnichar(aSource));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
aDest.Append(H_SURROGATE(aSource));
|
|
|
|
aDest.Append(L_SURROGATE(aSource));
|
|
|
|
}
|
|
|
|
}
|