- fix <rdar://problem/
5383104> REGRESSION: XHR.responseText is null instead of empty string
in http/tests/xmlhttprequest/zero-length-response.html
The new code to handle out of memory conditions was turning a "" into a null string.
* kjs/ustring.h: Removed UCharReference, which has long been obsolete and unused.
Removed copyForWriting, which was only used for the upper/lowercasing code and for
UCharReference.
* kjs/ustring.cpp:
(KJS::allocChars): Removed special case that made this fail (return 0) when passed 0.
Instead assert that we're not passed 0. Also added an overflow check for two reasons:
1) for sizes that aren't checked this prevents us from allocating a buffer that's too
small, and 2) for sizes where we overflowed in the expandedSize function and returned
overflowIndicator, it guarantees we fail.
(KJS::reallocChars): Ditto.
(KJS::UString::expandedSize): Return a large number, overflowIndicator, rather than 0
for cases where we overflow.
(KJS::UString::spliceSubstringsWithSeparators): Added a special case for empty string so
we don't call allocChars with a length of 0.
(KJS::UString::operator=): Added special characters for both 0 and empty string so we
match the behavior of the constructor. This avoids calling allocChars with a length of 0
and making a null string rather than an empty string in that case, and also matches the
pattern used in the rest of the functions.
(KJS::UString::operator[]): Made the return value const so code that tries to use the
operator to modify the string will fail.
* kjs/string_object.cpp: (KJS::StringProtoFunc::callAsFunction): Rewrote uppercasing and
lowercasing functions so they don't need copyForWriting any more -- it wasn't really doing
any good for optimization purposes. Instead use a Vector and releaseBuffer.
* wtf/unicode/icu/UnicodeIcu.h: Eliminate one of the versions of toLower/toUpper -- we now
only need the version where both a source and destination buffer is passed in, not the one
that works in place.
* wtf/unicode/qt4/UnicodeQt4.h: Ditto.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@24919
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2007-08-07 Darin Adler <darin@apple.com>
+
+ Reviewed by Adele.
+
+ - fix <rdar://problem/5383104> REGRESSION: XHR.responseText is null instead of empty string
+ in http/tests/xmlhttprequest/zero-length-response.html
+
+ The new code to handle out of memory conditions was turning a "" into a null string.
+
+ * kjs/ustring.h: Removed UCharReference, which has long been obsolete and unused.
+ Removed copyForWriting, which was only used for the upper/lowercasing code and for
+ UCharReference.
+ * kjs/ustring.cpp:
+ (KJS::allocChars): Removed special case that made this fail (return 0) when passed 0.
+ Instead assert that we're not passed 0. Also added an overflow check for two reasons:
+ 1) for sizes that aren't checked this prevents us from allocating a buffer that's too
+ small, and 2) for sizes where we overflowed in the expandedSize function and returned
+ overflowIndicator, it guarantees we fail.
+ (KJS::reallocChars): Ditto.
+ (KJS::UString::expandedSize): Return a large number, overflowIndicator, rather than 0
+ for cases where we overflow.
+ (KJS::UString::spliceSubstringsWithSeparators): Added a special case for empty string so
+ we don't call allocChars with a length of 0.
+ (KJS::UString::operator=): Added special characters for both 0 and empty string so we
+ match the behavior of the constructor. This avoids calling allocChars with a length of 0
+ and making a null string rather than an empty string in that case, and also matches the
+ pattern used in the rest of the functions.
+ (KJS::UString::operator[]): Made the return value const so code that tries to use the
+ operator to modify the string will fail.
+
+ * kjs/string_object.cpp: (KJS::StringProtoFunc::callAsFunction): Rewrote uppercasing and
+ lowercasing functions so they don't need copyForWriting any more -- it wasn't really doing
+ any good for optimization purposes. Instead use a Vector and releaseBuffer.
+
+ * wtf/unicode/icu/UnicodeIcu.h: Eliminate one of the versions of toLower/toUpper -- we now
+ only need the version where both a source and destination buffer is passed in, not the one
+ that works in place.
+ * wtf/unicode/qt4/UnicodeQt4.h: Ditto.
+
2007-08-06 Sam Weinig <sam@webkit.org>
Reviewed by Oliver.
break;
case ToLowerCase:
case ToLocaleLowerCase: { // FIXME: See http://www.unicode.org/Public/UNIDATA/SpecialCasing.txt for locale-sensitive mappings that aren't implemented.
- u = s;
- u.copyForWriting();
- ::UChar* dataPtr = reinterpret_cast< ::UChar*>(u.rep()->data());
- ::UChar* destIfNeeded;
-
- int len = Unicode::toLower(dataPtr, u.size(), destIfNeeded);
- if (len >= 0)
- result = jsString(UString(reinterpret_cast<UChar*>(destIfNeeded ? destIfNeeded : dataPtr), len));
- else
- result = jsString(s);
-
- free(destIfNeeded);
- break;
+ StringImp* sVal = thisObj->inherits(&StringInstance::info)
+ ? static_cast<StringInstance*>(thisObj)->internalValue()
+ : static_cast<StringImp*>(jsString(s));
+ int ssize = s.size();
+ if (!ssize)
+ return sVal;
+ Vector< ::UChar> buffer(ssize);
+ bool error;
+ int length = Unicode::toLower(buffer.data(), ssize, reinterpret_cast<const ::UChar*>(s.data()), ssize, &error);
+ if (error) {
+ buffer.resize(length);
+ length = Unicode::toLower(buffer.data(), length, reinterpret_cast<const ::UChar*>(s.data()), ssize, &error);
+ if (error)
+ return sVal;
+ }
+ if (length == ssize && memcmp(buffer.data(), s.data(), length * sizeof(UChar)) == 0)
+ return sVal;
+ return jsString(UString(reinterpret_cast<UChar*>(buffer.releaseBuffer()), length, false));
}
case ToUpperCase:
case ToLocaleUpperCase: { // FIXME: See http://www.unicode.org/Public/UNIDATA/SpecialCasing.txt for locale-sensitive mappings that aren't implemented.
- u = s;
- u.copyForWriting();
- ::UChar* dataPtr = reinterpret_cast< ::UChar*>(u.rep()->data());
- ::UChar* destIfNeeded;
-
- int len = Unicode::toUpper(dataPtr, u.size(), destIfNeeded);
- if (len >= 0)
- result = jsString(UString(reinterpret_cast<UChar *>(destIfNeeded ? destIfNeeded : dataPtr), len));
- else
- result = jsString(s);
-
- free(destIfNeeded);
- break;
+ StringImp* sVal = thisObj->inherits(&StringInstance::info)
+ ? static_cast<StringInstance*>(thisObj)->internalValue()
+ : static_cast<StringImp*>(jsString(s));
+ int ssize = s.size();
+ if (!ssize)
+ return sVal;
+ Vector< ::UChar> buffer(ssize);
+ bool error;
+ int length = Unicode::toUpper(buffer.data(), ssize, reinterpret_cast<const ::UChar*>(s.data()), ssize, &error);
+ if (error) {
+ buffer.resize(length);
+ length = Unicode::toUpper(buffer.data(), length, reinterpret_cast<const ::UChar*>(s.data()), ssize, &error);
+ if (error)
+ return sVal;
+ }
+ if (length == ssize && memcmp(buffer.data(), s.data(), length * sizeof(UChar)) == 0)
+ return sVal;
+ return jsString(UString(reinterpret_cast<UChar*>(buffer.releaseBuffer()), length, false));
}
case LocaleCompare:
if (args.size() < 1)
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2004 Apple Computer, Inc.
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
* Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
*
* This library is free software; you can redistribute it and/or
extern const double NaN;
extern const double Inf;
+static const size_t overflowIndicator = std::numeric_limits<size_t>::max();
+static const size_t maxUChars = std::numeric_limits<size_t>::max() / sizeof(UChar);
+
static inline UChar* allocChars(size_t length)
{
- if (!length)
+ ASSERT(length);
+ if (length > maxUChars)
return 0;
return static_cast<UChar*>(fastMalloc(sizeof(UChar) * length));
}
-static inline UChar* reallocChars(void* buffer, size_t length)
+static inline UChar* reallocChars(UChar* buffer, size_t length)
{
- if (!length)
+ ASSERT(length);
+ if (length > maxUChars)
return 0;
return static_cast<UChar*>(fastRealloc(buffer, sizeof(UChar) * length));
}
static char *statBuffer = 0;
static int statBufferSize = 0;
-UCharReference& UCharReference::operator=(UChar c)
-{
- str->copyForWriting();
- if (offset < str->rep()->len)
- *(str->rep()->data() + offset) = c;
- /* TODO: lengthen string ? */
- return *this;
-}
-
-UChar& UCharReference::ref() const
-{
- ASSERT(JSLock::lockCount() > 0);
-
- if (offset < str->rep()->len)
- return *(str->rep()->data() + offset);
- else {
- static UChar callerBetterNotModifyThis('\0');
- return callerBetterNotModifyThis;
- }
-}
-
PassRefPtr<UString::Rep> UString::Rep::createCopying(const UChar *d, int l)
{
ASSERT(JSLock::lockCount() > 0);
// put these early so they can be inlined
inline size_t UString::expandedSize(size_t size, size_t otherSize) const
{
- // Do the size calculation in two parts, being careful to avoid overflow
- static const size_t maximumAllowableSize = std::numeric_limits<size_t>::max() / sizeof(UChar);
- if (size > maximumAllowableSize)
- return 0;
+ // Do the size calculation in two parts, returning overflowIndicator if
+ // we overflow the maximum value that we can handle.
+
+ if (size > maxUChars)
+ return overflowIndicator;
size_t expandedSize = ((size + 10) / 10 * 11) + 1;
- if (maximumAllowableSize - expandedSize < otherSize)
- return 0;
+ if (maxUChars - expandedSize < otherSize)
+ return overflowIndicator;
return expandedSize + otherSize;
}
for (int i = 0; i < separatorCount; i++)
totalLength += separators[i].size();
+ if (totalLength == 0)
+ return "";
+
UChar* buffer = allocChars(totalLength);
if (!buffer)
return null();
UString &UString::operator=(const char *c)
{
- int l = c ? static_cast<int>(strlen(c)) : 0;
+ if (!c) {
+ m_rep = &Rep::null;
+ return *this;
+ }
+
+ int l = static_cast<int>(strlen(c));
+ if (!l) {
+ m_rep = &Rep::empty;
+ return *this;
+ }
+
UChar *d;
if (m_rep->rc == 1 && l <= m_rep->capacity && m_rep->baseIsSelf() && m_rep->offset == 0 && m_rep->preCapacity == 0) {
d = m_rep->buf;
return true;
}
-UChar UString::operator[](int pos) const
+const UChar UString::operator[](int pos) const
{
if (pos >= size())
return '\0';
return data()[pos];
}
-UCharReference UString::operator[](int pos)
-{
- /* TODO: boundary check */
- return UCharReference(this, pos);
-}
-
double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const
{
double d;
return UString(Rep::create(m_rep, pos, len));
}
-void UString::copyForWriting()
-{
- if (m_rep->rc > 1 || !m_rep->baseIsSelf()) {
- int l = size();
- UChar *n = allocChars(l);
- if (!n)
- m_rep = &Rep::null;
- else {
- memcpy(n, data(), l * sizeof(UChar));
- m_rep = Rep::create(n, l);
- }
- }
-}
-
bool operator==(const UString& s1, const UString& s2)
{
if (s1.m_rep->len != s2.m_rep->len)
namespace KJS {
- class UCharReference;
class UString;
/**
UChar(char u);
UChar(unsigned char u);
UChar(unsigned short u);
- UChar(const UCharReference &c);
/**
* @return The higher byte of the character.
*/
inline UChar::UChar(unsigned char u) : uc(u) { }
inline UChar::UChar(unsigned short u) : uc(u) { }
- /**
- * @short Dynamic reference to a string character.
- *
- * UCharReference is the dynamic counterpart of UChar. It's used when
- * characters retrieved via index from a UString are used in an
- * assignment expression (and therefore can't be treated as being const):
- * \code
- * UString s("hello world");
- * s[0] = 'H';
- * \endcode
- *
- * If that sounds confusing your best bet is to simply forget about the
- * existence of this class and treat is as being identical to UChar.
- */
- class UCharReference {
- friend class UString;
- UCharReference(UString *s, unsigned int off) : str(s), offset(off) { }
- public:
- /**
- * Set the referenced character to c.
- */
- UCharReference& operator=(UChar c);
- /**
- * Same operator as above except the argument that it takes.
- */
- UCharReference& operator=(char c) { return operator=(UChar(c)); }
- /**
- * @return Unicode value.
- */
- unsigned short unicode() const { return ref().uc; }
- /**
- * @return Lower byte.
- */
- unsigned char low() const { return static_cast<unsigned char>(ref().uc); }
- /**
- * @return Higher byte.
- */
- unsigned char high() const { return static_cast<unsigned char>(ref().uc >> 8); }
-
- private:
- // not implemented, can only be constructed from UString
- UCharReference();
-
- UChar& ref() const;
- UString *str;
- int offset;
- };
-
- inline UChar::UChar(const UCharReference &c) : uc(c.unicode()) { }
-
/**
* @short 8 bit char based string class
*/
/**
* Const character at specified position.
*/
- UChar operator[](int pos) const;
- /**
- * Writable reference to character at specified position.
- */
- UCharReference operator[](int pos);
+ const UChar operator[](int pos) const;
/**
* Attempts an conversion to a number. Apart from floating point numbers,
Rep* rep() const { return m_rep.get(); }
UString(PassRefPtr<Rep> r) : m_rep(r) { ASSERT(m_rep); }
- void copyForWriting();
-
size_t cost() const;
private:
return realLength;
}
- inline int toLower(UChar* str, int strLength, UChar*& destIfNeeded)
- {
- UErrorCode err = U_ZERO_ERROR;
- int resultLength;
- destIfNeeded = 0;
-
- resultLength = u_strToLower(0, 0, str, strLength, "", &err);
-
- if (resultLength <= strLength) {
- err = U_ZERO_ERROR;
- u_strToLower(str, resultLength, str, strLength, "", &err);
- } else {
- err = U_ZERO_ERROR;
- destIfNeeded = static_cast<UChar*>(malloc(resultLength * sizeof(UChar)));
- u_strToLower(destIfNeeded, resultLength, str, strLength, "", &err);
- }
-
- return U_FAILURE(err) ? -1 : resultLength;
- }
-
inline int toLower(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error)
{
UErrorCode status = U_ZERO_ERROR;
return u_toupper(c);
}
- inline int toUpper(UChar* str, int strLength, UChar*& destIfNeeded)
- {
- UErrorCode err = U_ZERO_ERROR;
- int resultLength;
- destIfNeeded = 0;
-
- resultLength = u_strToUpper(0, 0, str, strLength, "", &err);
-
- if (resultLength <= strLength) {
- err = U_ZERO_ERROR;
- u_strToUpper(str, resultLength, str, strLength, "", &err);
- } else {
- err = U_ZERO_ERROR;
- destIfNeeded = (UChar*)malloc(resultLength * sizeof(UChar));
- u_strToUpper(destIfNeeded, resultLength, str, strLength, "", &err);
- }
-
- return U_FAILURE(err) ? -1 : resultLength;
- }
-
inline int toUpper(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error)
{
UErrorCode status = U_ZERO_ERROR;
#if QT_VERSION >= 0x040300
// FIXME: handle surrogates correctly in all methods
- inline int toLower(UChar* str, int strLength, UChar*& destIfNeeded)
- {
- destIfNeeded = 0;
-
- const UChar *e = str + strLength;
- UChar *s = str;
- while (s < e) {
- const QUnicodeTables::Properties *prop = QUnicodeTables::properties(*s);
- if (prop->lowerCaseSpecial || (((*s) & 0xf800) == 0xd800)) {
- QString qstring = QString(reinterpret_cast<QChar *>(str), strLength).toLower();
- strLength = qstring.length();
- destIfNeeded = static_cast<UChar*>(malloc(strLength * sizeof(UChar)));
- memcpy(destIfNeeded, qstring.constData(), strLength * sizeof(UChar));
- return strLength;
- }
- *s = *s + prop->lowerCaseDiff;
- ++s;
- }
-
- return strLength;
- }
-
inline UChar32 toLower(UChar32 ch)
{
return QChar::toLower(ch);
return (r - result) + needed;
}
- inline int toUpper(UChar* str, int strLength, UChar*& destIfNeeded)
- {
- destIfNeeded = 0;
-
- const UChar *e = str + strLength;
- UChar *s = str;
- while (s < e) {
- const QUnicodeTables::Properties *prop = QUnicodeTables::properties(*s);
- if (prop->upperCaseSpecial || (((*s) & 0xf800) == 0xd800)) {
- QString qstring = QString(reinterpret_cast<QChar *>(str), strLength).toUpper();
- strLength = qstring.length();
- destIfNeeded = static_cast<UChar*>(malloc(strLength * sizeof(UChar)));
- memcpy(destIfNeeded, qstring.constData(), strLength * sizeof(UChar));
- return strLength;
- }
- *s = *s + prop->upperCaseDiff;
- ++s;
- }
-
- return strLength;
- }
-
inline UChar32 toUpper(UChar32 ch)
{
return QChar::toUpper(ch);
#else
- inline int toLower(UChar* str, int strLength, UChar*& destIfNeeded)
- {
- destIfNeeded = 0;
-
- for (int i = 0; i < strLength; ++i)
- str[i] = QChar(str[i]).toLower().unicode();
-
- return strLength;
- }
-
inline UChar32 toLower(UChar32 ch)
{
if (ch > 0xffff)
return srcLength;
}
- inline int toUpper(UChar* str, int strLength, UChar*& destIfNeeded)
- {
- destIfNeeded = 0;
-
- for (int i = 0; i < strLength; ++i)
- str[i] = QChar(str[i]).toUpper().unicode();
-
- return strLength;
- }
-
inline UChar32 toUpper(UChar32 ch)
{
if (ch > 0xffff)