nsUTF8Utils.h revision 677833bc953b6cb418c701facbdcf4aa18d6c44e
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** 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
*
* 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.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Peter Annema <jaggernaut@netscape.com> (original author)
*
* 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 ***** */
#ifndef nsUTF8Utils_h_
#define nsUTF8Utils_h_
{
};
#define PLANE1_BASE 0x00010000
#define UCS2_REPLACEMENT_CHAR 0xfffd
#ifdef __GNUC__
#else
#define NS_ALWAYS_INLINE
#endif
/**
* A character sink (see |copy_string| in nsAlgorithm.h) for converting
* UTF-8 to UTF-16
*/
{
{
if ( mErrorEncountered )
return N;
// algorithm assumes utf8 units won't
// be spread across fragments
const value_type* p = start;
for ( ; p != end /* && *p */; )
{
char c = *p++;
if ( UTF8traits::isASCII(c) )
{
*out++ = buffer_type(c);
continue;
}
if ( UTF8traits::is2byte(c) )
{
state = 1;
minUcs4 = 0x00000080;
}
else if ( UTF8traits::is3byte(c) )
{
state = 2;
minUcs4 = 0x00000800;
}
else if ( UTF8traits::is4byte(c) )
{
state = 3;
minUcs4 = 0x00010000;
}
else if ( UTF8traits::is5byte(c) )
{
state = 4;
minUcs4 = 0x00200000;
}
else if ( UTF8traits::is6byte(c) )
{
state = 5;
minUcs4 = 0x04000000;
}
else
{
NS_ERROR("Not a UTF-8 string. This code should only be used for converting from known UTF-8 strings.");
return N;
}
while ( state-- )
{
c = *p++;
if ( UTF8traits::isInSeq(c) )
{
}
else
{
NS_ERROR("not a UTF8 string");
return N;
}
}
{
// Overlong sequence
*out++ = UCS2_REPLACEMENT_CHAR;
}
else if ( ucs4 <= 0xD7FF )
{
}
{
// Surrogates
*out++ = UCS2_REPLACEMENT_CHAR;
}
{
// Prohibited characters
*out++ = UCS2_REPLACEMENT_CHAR;
}
else if ( ucs4 >= PLANE1_BASE )
{
if ( ucs4 >= 0x00110000 )
*out++ = UCS2_REPLACEMENT_CHAR;
else {
// surrogate, see unicode specification 3.7 for following math.
ucs4 -= PLANE1_BASE;
}
}
else
{
}
}
return p - start;
}
void write_terminator()
{
*mBuffer = buffer_type(0);
}
buffer_type* const mStart;
};
/**
* A character sink (see |copy_string| in nsAlgorithm.h) for computing
* the length of the UTF-16 string equivalent to a UTF-8 string.
*/
{
{
// ignore any further requests
if ( mErrorEncountered )
return N;
// algorithm assumes utf8 units won't
// be spread across fragments
const value_type* p = start;
{
if ( UTF8traits::isASCII(*p) )
p += 1;
else if ( UTF8traits::is2byte(*p) )
p += 2;
else if ( UTF8traits::is3byte(*p) )
p += 3;
else if ( UTF8traits::is4byte(*p) ) {
p += 4;
// Because a UTF-8 sequence of 4 bytes represents a codepoint
// greater than 0xFFFF, it will become a surrogate pair in the
// UTF-16 string, so add 1 more to mLength.
// This doesn't happen with is5byte and is6byte because they
// are illegal UTF-8 sequences (greater than 0x10FFFF) so get
// converted to a single replacement character.
//
// XXX: if the 4-byte sequence is an illegal non-shortest form,
// it also gets converted to a replacement character, so
// mLength will be off by one in this case.
++mLength;
}
else if ( UTF8traits::is5byte(*p) )
p += 5;
else if ( UTF8traits::is6byte(*p) )
p += 6;
else
{
break;
}
}
if ( p != end )
{
NS_ERROR("Not a UTF-8 string. This code should only be used for converting from known UTF-8 strings.");
mLength = 0;
return N;
}
return p - start;
}
};
/**
* A character sink (see |copy_string| in nsAlgorithm.h) for converting
* UTF-16 to UTF-8.
*/
{
// The error handling here is more lenient than that in
// |ConvertUTF8toUTF16|, but it's that way for backwards
// compatibility.
{
{
value_type c = *p;
if (! (c & 0xFF80)) // U+0000 - U+007F
{
*out++ = (char)c;
}
else if (! (c & 0xF800)) // U+0100 - U+07FF
{
}
else if (0xD800 != (0xF800 & c)) // U+0800 - U+D7FF,U+E000 - U+FFFF
{
}
else if (0xD800 == (0xFC00 & c)) // U+D800 - U+DBFF
{
// D800- DBFF - High Surrogate
// N = (H- D800) *400 + 10000 + ...
++p;
if (p == end)
{
NS_ERROR("Surrogate pair split between fragments");
return N;
}
c = *p;
if (0xDC00 == (0xFC00 & c))
{
// DC00- DFFF - Low Surrogate
// N += ( L - DC00 )
ucs4 |= (0x03FF & c);
// 0001 0000-001F FFFF
}
else
{
NS_ERROR("got a High Surrogate but no low surrogate");
// output nothing.
}
}
else // U+DC00 - U+DFFF
{
// DC00- DFFF - Low Surrogate
NS_ERROR("got a low Surrogate but no high surrogate");
// output nothing.
}
}
return N;
}
void write_terminator()
{
*mBuffer = buffer_type(0);
}
buffer_type* const mStart;
};
/**
* A character sink (see |copy_string| in nsAlgorithm.h) for computing
* the number of bytes a UTF-16 would occupy in UTF-8.
*/
{
: mSize(0) { }
{
// Assume UCS2 surrogate pairs won't be spread across fragments.
{
value_type c = *p;
if (! (c & 0xFF80)) // U+0000 - U+007F
mSize += 1;
else if (! (c & 0xF800)) // U+0100 - U+07FF
mSize += 2;
else if (0xD800 != (0xF800 & c)) // U+0800 - U+D7FF,U+E000 - U+FFFF
mSize += 3;
else if (0xD800 == (0xFC00 & c)) // U+D800 - U+DBFF
{
++p;
if (p == end)
{
NS_ERROR("Surrogate pair split between fragments");
return N;
}
c = *p;
if (0xDC00 == (0xFC00 & c))
mSize += 4;
else
NS_ERROR("got a high Surrogate but no low surrogate");
}
else // U+DC00 - U+DFFF
NS_ERROR("got a low Surrogate but no high surrogate");
}
return N;
}
};
/**
* A character sink that performs a |reinterpret_cast| style conversion
* between character types.
*/
{
typedef FromCharT value_type;
typedef FromCharT input_type;
typedef ToCharT output_type;
{
while ( aSource < done_writing )
*mDestination++ = (output_type)(unsigned_input_type)(*aSource++); // use old-style cast to mimic old |ns[C]String| behavior
return aSourceLength;
}
void
{
*mDestination = output_type(0);
}
};
#endif /* !defined(nsUTF8Utils_h_) */