📄 kwqstring.cpp
字号:
/*
* Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
* Portions Copyright (c) 2005 Nokia Corporation, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdarg.h>
#ifndef KHTML_NO_SCRIPTING
#include <kjs/dtoa.h>
#endif
#include "KWQLogging.h"
#include "KWQString.h"
#include "KWQRegExp.h"
#include "KWQTextCodec.h"
#include "CHARCONV.H"
#define CHECK_FOR_HANDLE_LEAKS 0
// Why can't I find this in a header anywhere? It's too bad we have
// to wire knowledge of allocation sizes, but it makes a huge diffence.
//extern "C" int malloc_good_size(int size);
#define malloc_good_size(size) size
#define ALLOC_QCHAR_GOOD_SIZE(X) (malloc_good_size(X*sizeof(QChar))/sizeof(QChar))
#define ALLOC_CHAR_GOOD_SIZE(X) (malloc_good_size(X))
#ifndef __OOM__
#define ALLOC_CHAR( N ) (char*) malloc(N)
#define REALLOC_CHAR( P, N ) (char *) realloc(P,N)
#define ALLOC_QCHAR( N ) (QChar*) malloc(sizeof(QChar)*( N ))
#define REALLOC_QCHAR( P, N ) (QChar *) realloc(P,sizeof(QChar)*( N ))
#define DELETE_CHAR( P ) free(P)
#define DELETE_QCHAR( P ) free( P )
#else
#define ALLOC_CHAR( N ) (char*) MemoryManager::Alloc(N)
#define REALLOC_CHAR( P, N ) (char *) MemoryManager::ReAlloc(P,N)
#define ALLOC_QCHAR( N ) (QChar*) MemoryManager::Alloc(sizeof(QChar)*( N ))
#define REALLOC_QCHAR( P, N ) (QChar *) MemoryManager::ReAlloc(P,sizeof(QChar)*( N ))
#define DELETE_CHAR( P ) MemoryManager::Free( P )
#define DELETE_QCHAR( P ) MemoryManager::Free( P )
#endif
static inline KWQStringData **allocateHandle()
{
//apple code has macos specific allocator here
#ifndef __OOM__
return static_cast<KWQStringData **>(malloc(sizeof(KWQStringData *)));
#else
return static_cast<KWQStringData **>(MemoryManager::Alloc(sizeof(KWQStringData *)));
#endif
}
static void freeHandle(KWQStringData **_free)
{
#ifndef __OOM__
free(_free);
#else
MemoryManager::Free( _free );
#endif
}
#define IS_ASCII_QCHAR(c) ((c).unicode() > 0 && (c).unicode() <= 0xff)
//static const int caseDelta = ('a' - 'A');
const char * const QString::null = 0;
KWQStringData *QString::shared_null = 0;
KWQStringData **QString::shared_null_handle = 0;
// -------------------------------------------------------------------------
// Utility functions
// -------------------------------------------------------------------------
static inline int ucstrcmp( const QString &as, const QString &bs )
{
const QChar *a = as.unicode();
const QChar *b = bs.unicode();
if ( a == b )
return 0;
if ( a == 0 )
return 1;
if ( b == 0 )
return -1;
int l = kMin(as.length(), bs.length());
while ( l-- && *a == *b )
a++,b++;
if ( l == -1 )
return ( as.length() - bs.length() );
return a->unicode() - b->unicode();
}
static bool equal(const QChar *a, const char *b, int l)
{
ASSERT(l >= 0);
while (l--) {
if (*a != *b)
return false;
a++; b++;
}
return true;
}
// Not a "true" case insensitive compare; only insensitive for plain ASCII.
static bool equalCaseInsensitive(const char *a, const char *b, int l)
{
ASSERT(l >= 0);
while (l--) {
if (tolower(*a) != tolower(*b))
return false;
a++; b++;
}
return true;
}
static bool equalCaseInsensitive(const QChar *a, const char *b, int l)
{
ASSERT(l >= 0);
while (l--) {
if (tolower(a->unicode()) != tolower(*b))
return false;
a++; b++;
}
return true;
}
static bool equalCaseInsensitive(const QChar *a, const QChar *b, int l)
{
ASSERT(l >= 0);
while (l--) {
if (tolower(a->unicode()) != tolower(b->unicode()))
return false;
a++; b++;
}
return true;
}
static inline bool equalCaseInsensitive(char c1, char c2)
{
return tolower(c1) == tolower(c2);
}
static inline bool equalCaseInsensitive(QChar c1, char c2)
{
return tolower(c1.unicode()) == tolower(static_cast<unsigned char>(c2));
}
static bool ok_in_base(QChar c, int base)
{
int uc = c.unicode();
if (isdigit(uc))
return uc - '0' < base;
if (isalpha(uc)) {
if (base > 36)
base = 36;
return (uc >= 'a' && uc < 'a' + base - 10)
|| (uc >= 'A' && uc < 'A' + base - 10);
}
return false;
}
// -------------------------------------------------------------------------
// KWQStringData
// -------------------------------------------------------------------------
// FIXME, make constructor explicity take a 'copy' flag.
// This can be used to hand off ownership of allocated data when detaching and
// deleting QStrings.
KWQStringData::KWQStringData() :
refCount(1), _length(0), _unicode(0), _ascii(0), _maxUnicode(QS_INTERNAL_BUFFER_UCHARS), _isUnicodeValid(0), _isHeapAllocated(0), _maxAscii(QS_INTERNAL_BUFFER_CHARS), _isAsciiValid(1)
{
#ifdef QSTRING_DEBUG_ALLOCATIONS
stringDataInstances++;
#endif
_ascii = _internalBuffer;
_internalBuffer[0] = 0;
}
void KWQStringData::initialize()
{
refCount = 1;
_length = 0;
_unicode = 0;
_ascii = _internalBuffer;
_maxUnicode = QS_INTERNAL_BUFFER_UCHARS;
_isUnicodeValid = 0;
_maxAscii = QS_INTERNAL_BUFFER_CHARS;
_isAsciiValid = 1;
_internalBuffer[0] = 0;
_isHeapAllocated = 0;
}
// Don't copy data.
KWQStringData::KWQStringData(QChar *u, uint l, uint m) :
refCount(1), _length(l), _unicode(u), _ascii(0), _maxUnicode(m), _isUnicodeValid(1), _isHeapAllocated(0), _maxAscii(QS_INTERNAL_BUFFER_CHARS), _isAsciiValid(0)
{
ASSERT(m >= l);
#ifdef QSTRING_DEBUG_ALLOCATIONS
stringDataInstances++;
#endif
}
// Don't copy data.
void KWQStringData::initialize(QChar *u, uint l, uint m)
{
ASSERT(m >= l);
refCount = 1;
_length = l;
_unicode = u;
_ascii = 0;
_maxUnicode = m;
_isUnicodeValid = 1;
_maxAscii = 0;
_isAsciiValid = 0;
_isHeapAllocated = 0;
}
// Copy data
KWQStringData::KWQStringData(const QChar *u, uint l)
{
#ifdef QSTRING_DEBUG_ALLOCATIONS
stringDataInstances++;
#endif
initialize (u, l);
}
#ifdef QSTRING_DEBUG_ALLOCATIONS
void* KWQStringData::operator new(size_t s)
{
stringDataHeapInstances++;
return malloc(s);
}
void KWQStringData::operator delete(void*p)
{
return free(p);
}
#endif
// Copy data
void KWQStringData::initialize(const QChar *u, uint l)
{
refCount = 1;
_length = l;
_ascii = 0;
_isUnicodeValid = 1;
_maxAscii = 0;
_isAsciiValid = 0;
_isHeapAllocated = 0;
if (l > QS_INTERNAL_BUFFER_UCHARS) {
_maxUnicode = ALLOC_QCHAR_GOOD_SIZE(l);
_unicode = ALLOC_QCHAR(_maxUnicode);
if( !_unicode )
{
_maxUnicode = 0;
return;
}
memcpy(_unicode, u, l*sizeof(QChar));
} else {
_maxUnicode = QS_INTERNAL_BUFFER_UCHARS;
_unicode = (QChar *)_internalBuffer;
if (l)
memcpy(_internalBuffer, u, l*sizeof(QChar));
}
}
// Copy data
KWQStringData::KWQStringData(const char *a, uint l)
{
#ifdef QSTRING_DEBUG_ALLOCATIONS
stringDataInstances++;
#endif
initialize(a, l);
}
// Copy data
void KWQStringData::initialize(const char *a, uint l)
{
refCount = 1;
_length = l;
_unicode = 0;
_isUnicodeValid = 0;
_maxUnicode = 0;
_isAsciiValid = 1;
_isHeapAllocated = 0;
if (l > QS_INTERNAL_BUFFER_CHARS) {
_maxAscii = ALLOC_CHAR_GOOD_SIZE(l+1);
_ascii = ALLOC_CHAR(_maxAscii);
if (a)
memcpy(_ascii, a, l);
_ascii[l] = 0;
} else {
_maxAscii = QS_INTERNAL_BUFFER_CHARS;
_ascii = _internalBuffer;
if (a)
memcpy(_internalBuffer, a, l);
_internalBuffer[l] = 0;
}
}
KWQStringData::KWQStringData(KWQStringData &o)
: refCount(1)
, _length(o._length)
, _unicode(o._unicode)
, _ascii(o._ascii)
, _maxUnicode(o._maxUnicode)
, _isUnicodeValid(o._isUnicodeValid)
, _isHeapAllocated(0)
, _maxAscii(o._maxAscii)
, _isAsciiValid(o._isAsciiValid)
{
// Handle the case where either the Unicode or 8-bit pointer was
// pointing to the internal buffer. We need to point at the
// internal buffer in the new object, and copy the characters.
if (_unicode == reinterpret_cast<QChar *>(o._internalBuffer)) {
if (_isUnicodeValid) {
ASSERT(!_isAsciiValid || _ascii != o._internalBuffer);
ASSERT(_length <= QS_INTERNAL_BUFFER_UCHARS);
memcpy(_internalBuffer, o._internalBuffer, _length * sizeof(QChar));
_unicode = reinterpret_cast<QChar *>(_internalBuffer);
} else {
_unicode = 0;
}
}
if (_ascii == o._internalBuffer) {
if (_isAsciiValid) {
ASSERT(_length <= QS_INTERNAL_BUFFER_CHARS);
memcpy(_internalBuffer, o._internalBuffer, _length);
_internalBuffer[_length] = 0;
_ascii = _internalBuffer;
} else {
_ascii = 0;
}
}
// Clean up the other KWQStringData just enough so that it can be destroyed
// cleanly. It's not in a good enough state to use, but that's OK. It just
// needs to be in a state where ~KWQStringData won't do anything harmful,
// and setting these to 0 will do that (preventing any double-free problems).
o._unicode = 0;
o._ascii = 0;
}
KWQStringData *QString::makeSharedNull()
{
if (!shared_null) {
shared_null = new KWQStringData;
shared_null->ref();
shared_null->_maxAscii = 0;
shared_null->_maxUnicode = 0;
shared_null->_unicode = (QChar *)&shared_null->_internalBuffer[0];
shared_null->_isUnicodeValid = 1;
}
return shared_null;
}
KWQStringData **QString::makeSharedNullHandle()
{
if (!shared_null_handle) {
shared_null_handle = allocateHandle();
*shared_null_handle = makeSharedNull();
}
return shared_null_handle;
}
KWQStringData::~KWQStringData()
{
ASSERT(refCount == 0);
if (_unicode && !isUnicodeInternal())
DELETE_QCHAR(_unicode);
if (_ascii && !isAsciiInternal())
DELETE_CHAR(_ascii);
}
bool KWQStringData::increaseAsciiSize(uint size)
{
ASSERT(this != QString::shared_null);
uint newSize = (uint)ALLOC_CHAR_GOOD_SIZE((size * 3 + 1) / 2);
if (!_isAsciiValid)
makeAscii();
ASSERT(_isAsciiValid);
if (isAsciiInternal()) {
char *newAscii = ALLOC_CHAR(newSize);
if( !newAscii ) return false;
if (_length)
memcpy(newAscii, _ascii, _length);
_ascii = newAscii;
} else {
char* ap = _ascii;
_ascii = REALLOC_CHAR( _ascii, newSize );
if( !_ascii )
{
// memory manager won't delete the original pointer if realloc failed
_ascii = ap;
return false;
}
}
_maxAscii = newSize;
_isAsciiValid = 1;
_isUnicodeValid = 0;
return true;
}
bool KWQStringData::increaseUnicodeSize(uint size)
{
ASSERT(size > _length);
ASSERT(this != QString::shared_null);
uint newSize = (uint)ALLOC_QCHAR_GOOD_SIZE((size * 3 + 1) / 2);
if (!_isUnicodeValid)
makeUnicode();
ASSERT(_isUnicodeValid);
if (isUnicodeInternal()) {
QChar *newUni = ALLOC_QCHAR(newSize);
if( !newUni ) return false;
if (_length)
memcpy(newUni, _unicode, _length*sizeof(QChar));
_unicode = newUni;
} else {
QChar* up = _unicode;
_unicode = REALLOC_QCHAR( _unicode, newSize );
if( !_unicode ) {
_unicode = up;
return false;
}
}
_maxUnicode = newSize;
_isUnicodeValid = 1;
_isAsciiValid = 0;
return true;
}
char *KWQStringData::makeAscii()
{
ASSERT(this != QString::shared_null);
if (_isUnicodeValid){
QChar copyBuf[QS_INTERNAL_BUFFER_CHARS];
QChar *str;
if (_ascii && !isAsciiInternal())
DELETE_QCHAR(_ascii);
if (_length < QS_INTERNAL_BUFFER_CHARS){
if (isUnicodeInternal()) {
uint i = _length;
QChar *tp = ©Buf[0], *fp = _unicode;
while (i--)
*tp++ = *fp++;
str = ©Buf[0];
_isUnicodeValid = 0;
}
else
str = _unicode;
_ascii = _internalBuffer;
_maxAscii = QS_INTERNAL_BUFFER_CHARS;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -