#include #include #include #include #include #include #include #include "hx/Hash.h" #include #include using namespace hx; #if defined(BLACKBERRY) using namespace std; #endif // -------- String ---------------------------------------- #ifdef HX_WINDOWS #ifndef _MSC_VER #define _MSC_VER 1 #endif // vc 7... #if _MSC_VER < 1400 #define SPRINTF _snprintf #else // vc8+ #define SPRINTF _snprintf_s #endif #else // not windows .. #define SPRINTF snprintf #endif #ifdef HX_SMART_STRINGS #include "hx/Unicase.h" #endif namespace hx { char HX_DOUBLE_PATTERN[20] = "%.15g"; #define HX_INT_PATTERN "%d" #define HX_UINT_PATTERN "%ud" } void __hxcpp_set_float_format(String inFormat) { int last = inFormat.length < 19 ? inFormat.length : 19; memcpy(HX_DOUBLE_PATTERN, inFormat.utf8_str(), last*sizeof(char) ); HX_DOUBLE_PATTERN[last] = '\0'; } // --- GC helper hx::Class __StringClass; String String::emptyString = HX_("",00,00,00,00); static Dynamic sConstEmptyString; static String sConstStrings[256]; static Dynamic sConstDynamicStrings[256]; static String *sCharToString[1088] = { 0 }; typedef Hash StringSet; static StringSet *sPermanentStringSet = 0; static volatile int sPermanentStringSetMutex = 0; #ifdef HXCPP_COMBINE_STRINGS static bool sIsIdent[256]; static bool InitIdent() { for(int i=0;i<256;i++) sIsIdent[i]= (i>='a' && i<='z') || (i>='A' && i<='Z') || (i>='0' && i<='9') || (i=='_'); return true; } #endif inline static bool IsUtf16Surrogate(int ch) { return ch>=0xd800 && ch<0xe000; } inline static bool IsUtf16LowSurrogate(int ch) { return ch>=0xdc00 && ch<0xe000; } inline static bool IsUtf16HighSurrogate(int ch) { return ch>=0xd800 && ch<0xdc00; } static int UTF8Bytes(int c) { if( c <= 0x7F ) return 1; else if( c <= 0x7FF ) return 2; else if( c <= 0xFFFF ) return 3; else return 4; } inline static int UTF16BytesCheck(int ch) { if (ch>=0x10000) { if (ch<0x110000) return 2; } return 1; } static void UTF8EncodeAdvance(char * &ioPtr,int c) { if( c <= 0x7F ) *ioPtr++ = (c); else if( c <= 0x7FF ) { *ioPtr++ = ( 0xC0 | (c >> 6) ); *ioPtr++ = ( 0x80 | (c & 63) ); } else if( c <= 0xFFFF ) { *ioPtr++ = ( 0xE0 | (c >> 12) ); *ioPtr++ = ( 0x80 | ((c >> 6) & 63) ); *ioPtr++ = ( 0x80 | (c & 63) ); } else { *ioPtr++ = ( 0xF0 | (c >> 18) ); *ioPtr++ = ( 0x80 | ((c >> 12) & 63) ); *ioPtr++ = ( 0x80 | ((c >> 6) & 63) ); *ioPtr++ = ( 0x80 | (c & 63) ); } } static unsigned char *sUtf8LenArray = 0; #ifndef HX_SMART_STRINGS static const unsigned char *getUtf8LenArray() { if (!sUtf8LenArray) { sUtf8LenArray = (unsigned char *)malloc(256); for(int i=0;i<256;i++) sUtf8LenArray[i] = i< 0x80 ? 1 : i<0xe0 ? 2 : i<0xf0 ? 3 : 4; } return sUtf8LenArray; } #endif static inline int DecodeAdvanceUTF8(const unsigned char * &ioPtr) { int c = *ioPtr++; if( c < 0x80 ) { return c; } else if( c < 0xE0 ) { return ((c & 0x3F) << 6) | ((*ioPtr++) & 0x7F); } else if( c < 0xF0 ) { int c2 = *ioPtr++; return ((c & 0x1F) << 12) | ((c2 & 0x7F) << 6) | ( (*ioPtr++) & 0x7F); } int c2 = *ioPtr++; int c3 = *ioPtr++; return ((c & 0x0F) << 18) | ((c2 & 0x7F) << 12) | ((c3 & 0x7F) << 6) | ((*ioPtr++) & 0x7F); } static inline int DecodeAdvanceUTF8(const unsigned char * &ioPtr,const unsigned char *end) { int c = *ioPtr++; if( c < 0x80 ) { return c; } else if( c < 0xE0 ) { return ((c & 0x3F) << 6) | (ioPtr < end ? (*ioPtr++) & 0x7F : 0); } else if( c < 0xF0 ) { int c2 = ioPtr=0x10000) { int over = (inChar-0x10000); if (over>=0x100000) { *ioStr++ = 0xfffd; } else { *ioStr++ = (over>>10) + 0xd800; *ioStr++ = (over&0x3ff) + 0xdc00; } } else if (IsUtf16Surrogate(inChar)) { *ioStr++ = 0xfffd; } else *ioStr++ = inChar; } template char *TConvertToUTF8(const T *inStr, int *ioLen, hx::IStringAlloc *inBuffer,bool) { int len = 0; int chars = 0; if (ioLen==0 || *ioLen==0) { while(inStr[len]) chars += UTF8Bytes(inStr[len++]); } else { len = *ioLen; for(int i=0;iallocBytes(chars+1) : (char *)NewGCPrivate(0,chars+1); char *ptr = buf; for(int i=0;i char *TConvertToUTF8(const char16_t *inStr, int *ioLen, hx::IStringAlloc *inBuffer,bool throwInvalid) { int len = 0; if (ioLen==0 || *ioLen==0) { const char16_t *s = inStr; while( Char16Advance(s,throwInvalid) ) { } len = s - inStr - 1; } else { len = *ioLen; } const char16_t *s = inStr; const char16_t *end = s + len; int chars = 0; while(sallocBytes(chars+1) : (char *)NewGCPrivate(0,chars+1); char *ptr = buf; s = inStr; while(s static const char *GCStringDup(const T *inStr,int inLen, int *outLen=0) { if (inStr==0 && inLen<=0) { if (outLen) outLen = 0; return String::emptyString.raw_ptr(); } int len = inLen; bool allAscii = true; if (len==-1) { len=0; while(inStr[len]) { if (sizeof(T)>1 && allAscii) allAscii = inStr[len] <= 127; len++; } } else if (sizeof(T)>1) { for(int i=0;i127) { allAscii = false; break; } } if (outLen) *outLen = len; if (len==1) return String::fromCharCode(inStr[0]).raw_ptr(); #ifdef HXCPP_COMBINE_STRINGS bool ident = len<20 && sIsIdent[inStr[0]] && (inStr[0]<'0' || inStr[0]>'9'); if (ident && len>3) for(int p=1; pstringSet) ctx->stringSet = new WeakStringSet(); unsigned int hash = 0; for(int i=0;istringSet->findEquivalentKey(found, hash, Finder(len, inStr))) return found.__s; char *result = hx::NewString(len + 4); memcpy(result,inStr,sizeof(char)*(len)); result[len] = '\0'; *((unsigned int *)(result + len + 1)) = hash; ((unsigned int *)(result))[-1] |= HX_GC_STRING_HASH; String asString(result, len); ctx->stringSet->TSet( asString, true ); return result; } #endif if (sizeof(T)==1 || allAscii) { char *result = hx::NewString( len ); if (sizeof(T)==1) memcpy(result,inStr,sizeof(char)*(len)); else for(int i=0;i1 && IsUtf16HighSurrogate(result[len-1])) result[len-1] = 0xFFFD; return (const char *)result; } template inline String TCopyString(const T *inString,int inLength) { if (!inString) return String(); #ifndef HX_SMART_STRINGS if (inLength<0) for(inLength=0; !inString[inLength]; inString++) { } if (sizeof(T)==1) { int len = 0; const char *res = GCStringDup((const char *)inString,inLength,&len); return String(res,len); } else { int length = inLength; const char *ptr = TConvertToUTF8(inString, &length, 0, true ); return String(ptr,length); } #else int c16len=0; bool hasWChar = false; const T *end = inLength>=0 ? inString + inLength : 0; if (end) { for(const T *s = inString; s127) hasWChar = true; c16len += UTF16BytesCheck(c); } } else for(const T *s = inString; *s; s++) { unsigned int c = *s; if (c>127) hasWChar = true; c16len += UTF16BytesCheck(c); } if (hasWChar) { char16_t *result = String::allocChar16Ptr(c16len); c16len = 0; for(const T *s = inString; ; s++) { if (end) { if (s>=end) break; } else { if (!*s) break; } unsigned int c = *s; if (c<0x10000) result[c16len++] = c; else { int over = (c-0x10000); result[c16len++] = (over>>10) + 0xd800; result[c16len++] = (over&0x3ff) + 0xdc00; } } return String(result,c16len); } else { char *s = hx::NewString(c16len); for(int i=0;i &inChars,int inFirst, int inLen) { int len = inChars->length; if (inFirst<0) inFirst = 0; if (inLen<0) inLen = len; if (inFirst+inLen>len) inLen = len-inFirst; if (inLen<=0) return String::emptyString; int *base = &inChars[0]; #ifdef HX_SMART_STRINGS bool hasBig = false; for(int i=0;i127) { hasBig = true; break; } if (hasBig) { char16_t *ptr = String::allocChar16Ptr(inLen); for(int i=0;i __hxcpp_utf8_string_to_char_array(String &inString) { #ifdef HX_SMART_STRINGS Array result = Array_obj::__new(inString.length); if (inString.isUTF16Encoded()) { const char16_t *ptr = inString.wc_str(); for(int i=0;i result = Array_obj::__new(0,inString.length); const unsigned char *src = (const unsigned char *)inString.__s; const unsigned char *end = src + inString.length; while(srcpush(DecodeAdvanceUTF8(src)); if (src!=end) hx::Throw(HX_CSTRING("Invalid UTF8")); #endif return result; } String __hxcpp_char_bytes_to_utf8_string(String &inBytes) { #ifdef HX_SMART_STRINGS // This does not really make much sense return inBytes; #else int len = inBytes.length; char *result = TConvertToUTF8((unsigned char *)inBytes.__s,&len,0,true); return String(result,len); #endif } String __hxcpp_utf8_string_to_char_bytes(String &inUTF8) { #ifdef HX_SMART_STRINGS // This does not really make much sense return inUTF8; #else const unsigned char *src = (unsigned char *)inUTF8.__s; const unsigned char *end = src + inUTF8.length; int char_count = 0; while(src 255 ) hx::Throw(HX_CSTRING("Utf8::decode invalid character")); } if (src!=end) hx::Throw(HX_CSTRING("Invalid UTF8")); char *result = hx::NewString(char_count); src = (unsigned char *)inUTF8.__s; char_count = 0; while(srcend) hx::Throw(HX_CSTRING("Invalid UTF8")); #endif } int _hx_utf8_char_code_at(String inString, int inIndex) { #ifdef HX_SMART_STRINGS if (!inString.raw_ptr() || inIndex>=inString.length) return 0; if (inString.isUTF16Encoded()) return inString.raw_wptr()[inIndex]; else return inString.raw_ptr()[inIndex]; #else const unsigned char *src = (const unsigned char *)inString.__s; const unsigned char *end = src + inString.length; const unsigned char *sLen = getUtf8LenArray(); for(int i=0;iend) hx::Throw(HX_CSTRING("Invalid UTF8")); } return DecodeAdvanceUTF8(src,end); #endif } int _hx_utf8_length(String inString) { #ifdef HX_SMART_STRINGS return inString.length; #else const unsigned char *src = (const unsigned char *)inString.__s; const unsigned char *end = src + inString.length; int len = 0; const unsigned char *sLen = getUtf8LenArray(); while(srcend) hx::Throw(HX_CSTRING("Invalid UTF8")); return len; #endif } bool _hx_utf8_is_valid(String inString) { #ifdef HX_SMART_STRINGS return true; #else const unsigned char *src = (const unsigned char *)inString.__s; const unsigned char *end = src + inString.length; const unsigned char *sLen = getUtf8LenArray(); while(srcend) hx::Throw(HX_CSTRING("Invalid UTF8")); } const unsigned char *start = src; for(int i=0;iend) hx::Throw(HX_CSTRING("Invalid UTF8")); } return String::create((const char *)start, src-start); #endif } String String::create(const wchar_t *inString,int inLength) { return TCopyString(inString,inLength); } String String::create(const char16_t *inString,int inLength) { return TCopyString(inString,inLength); } String String::create(const char *inString,int inLength) { if (!inString) return String(); #ifdef HX_SMART_STRINGS if (inLength<0) for(inLength=0; inString[inLength]; inLength++) { } const unsigned char *c = (const unsigned char *)inString; for(int i=0;i127) return _hx_utf8_to_utf16(c, inLength,false); } #endif int len = 0; const char *s = GCStringDup(inString,inLength,&len); return String(s,len); } String::String(const Dynamic &inRHS) { if (inRHS.GetPtr()) (*this)=const_cast(inRHS)->toString(); else { __s = 0; length = 0; } } void String::fromInt(int inIdx) { char buf[100]; SPRINTF(buf,100,HX_INT_PATTERN,inIdx); buf[99]='\0'; __s = GCStringDup(buf,-1,&length); } String::String(const int &inRHS) { fromInt(inRHS); } String::String(const unsigned int &inRHS) { char buf[100]; SPRINTF(buf,100,HX_UINT_PATTERN,inRHS); buf[99]='\0'; __s = GCStringDup(buf,-1,&length); } String::String(const cpp::CppInt32__ &inRHS) { char buf[100]; SPRINTF(buf,100,HX_INT_PATTERN,inRHS.mValue); __s = GCStringDup(buf,-1,&length); } String::String(const double &inRHS) { char buf[100]; SPRINTF(buf,100,HX_DOUBLE_PATTERN,inRHS); buf[99]='\0'; __s = GCStringDup(buf,-1,&length); } String::String(const cpp::Int64 &inRHS) { char buf[100]; SPRINTF(buf,100,"%lld", (long long int)inRHS); buf[99]='\0'; __s = GCStringDup(buf,-1,&length); } String::String(const cpp::UInt64 &inRHS) { char buf[100]; SPRINTF(buf,100,"%llu", (unsigned long long int)inRHS); buf[99]='\0'; __s = GCStringDup(buf,-1,&length); } String::String(const float &inRHS) { char buf[100]; SPRINTF(buf,100,HX_DOUBLE_PATTERN,inRHS); buf[99]='\0'; __s = GCStringDup(buf,-1,&length); } String::String(const bool &inRHS) { if (inRHS) { *this = HX_CSTRING("true"); } else { *this = HX_CSTRING("false"); } } void String::fromPointer(const void *p) { char buf[128]; SPRINTF(buf,128,"Native(%p)",p); __s = GCStringDup(buf,-1,&length); } #ifdef HX_SMART_STRINGS #define ADD_HASH(X) \ result = result*223 + (int)(X) #endif unsigned int String::calcSubHash(int start, int inLen) const { unsigned int result = 0; #ifdef HX_SMART_STRINGS if (isUTF16Encoded()) { const char16_t *w = __w + start; for(int i=0;i> 6)); ADD_HASH(0x80 | (c & 63)); } else if( c <= 0xFFFF ) { ADD_HASH(0xE0 | (c >> 12)); ADD_HASH(0x80 | ((c >> 6) & 63)); ADD_HASH(0x80 | (c & 63)); } else { ADD_HASH(0xF0 | (c >> 18)); ADD_HASH(0x80 | ((c >> 12) & 63)); ADD_HASH(0x80 | ((c >> 6) & 63) ); ADD_HASH(0x80 | (c & 63) ); } } } else #endif { const unsigned char *s = (const unsigned char *)__s + start; for(int i=0;i> 6)); ADD_HASH(0x80 | (c & 63)); } else if( c <= 0xFFFF ) { ADD_HASH(0xE0 | (c >> 12)); ADD_HASH(0x80 | ((c >> 6) & 63)); ADD_HASH(0x80 | (c & 63)); } else { ADD_HASH(0xF0 | (c >> 18)); ADD_HASH(0x80 | ((c >> 12) & 63)); ADD_HASH(0x80 | ((c >> 6) & 63) ); ADD_HASH(0x80 | (c & 63) ); } } } else #endif for(int i=0;i bytes(0,length); // utf8-encode __hxcpp_bytes_of_string(bytes,*this); int extra = 0; int utf8_chars = bytes->__length(); for(int i=0;i>4 ]; *ptr++ = hex[ b & 0x0f ]; } else *ptr++ = bytes[i]; } return String(result,l); } String String::toUpperCase() const { #ifdef HX_SMART_STRINGS if (isUTF16Encoded()) { char16_t *result = String::allocChar16Ptr(length); for(int i=0;i='0' && inChar<='9') return inChar-'0'; if (inChar>='a' && inChar<='f') return inChar-'a' + 10; if (inChar>='A' && inChar<='F') return inChar-'A' + 10; return 0; } String String::__URLDecode() const { // Create the decoded string; the decoded form might have fewer than // [length] characters, but it won't have more. If it has fewer than // [length], some memory will be wasted here, but on the assumption that // most URLs have only a few '%NN' encodings in them, don't bother // counting the number of characters in the resulting string first. char *decoded = NewString(length), *d = decoded; bool hasBig = false; #ifdef HX_SMART_STRINGS if (isUTF16Encoded()) { for (int i = 0; i < length; i++) { int c = __w[i]; if (c > 127) *d++ = '?'; else if (c == '+') *d++ = ' '; else if ((c == '%') && (i < (length - 2))) { int ch = ((hex(__w[i + 1]) << 4) | (hex(__w[i + 2]))); if (ch>127) hasBig = true; *d++ = ch; i += 2; } else *d++ = c; } } else #endif { for (int i = 0; i < length; i++) { int c = __s[i]; if (c > 127) *d++ = '?'; else if (c == '+') *d++ = ' '; else if ((c == '%') && (i < (length - 2))) { int ch = ((hex(__s[i + 1]) << 4) | (hex(__s[i + 2]))); #ifdef HX_SMART_STRINGS if (ch>127) hasBig = true; #endif *d++ = ch; i += 2; } else *d++ = c; } } #ifdef HX_SMART_STRINGS if (hasBig) return _hx_utf8_to_utf16((const unsigned char *)decoded, d-decoded,false); #endif return String( decoded, (d - decoded) ); } ::String &::String::dup() { const char *s = __s; __s = 0; *this = create(s,length); return *this; } const ::String &::String::makePermanent() const { if (!__s || (__s[HX_GC_CONST_ALLOC_MARK_OFFSET] & HX_GC_CONST_ALLOC_MARK_BIT) ) { // Already permanent } else if (!length) { const_cast(this)->__s = emptyString.__s; } else if (length==1) { const_cast(this)->__s = String::fromCharCode(cca(0)).__s; } else { unsigned int myHash = hash(); { while(_hx_atomic_compare_exchange(&sPermanentStringSetMutex, 0, 1) != 0) __hxcpp_gc_safe_point(); TNonGcStringSet *element = sPermanentStringSet->find(myHash , *this); sPermanentStringSetMutex = 0; if (element) { const_cast(this)->__s = element->key.__s; return *this; } } #ifdef HX_SMART_STRINGS if (isUTF16Encoded()) { char16_t *w = (char16_t *)InternalCreateConstBuffer(__s,(length+1)*2,true); ((unsigned int *)w)[-1] |= HX_GC_STRING_CHAR16_T; const_cast(this)->__w = w; fixHashPerm16(*this); } else #endif { char *s = (char *)InternalCreateConstBuffer(__s,length+1,true); const_cast(this)->__s = s; } while(_hx_atomic_compare_exchange(&sPermanentStringSetMutex, 0, 1) != 0) __hxcpp_gc_safe_point(); sPermanentStringSet->set(*this,null()); sPermanentStringSetMutex = 0; } return *this; } String String::createPermanent(const char *inUtf8, int length) { if (!inUtf8) return String(); if (length<0) length = strlen(inUtf8); if (!length) { return emptyString; } else if (length==1) { return String::fromCharCode( *(unsigned char *)inUtf8 ); } else { String temp = create(inUtf8,length); return temp.makePermanent(); } } template static int TIndexOf(int s, const T *str, int strLen, const T *sought, int soughtLen) { if (soughtLen==1) { T test = *sought; while(s__ToInt(); int l = inValue.length; if (l==0) { return s > length ? length : s; } #ifdef HX_SMART_STRINGS bool s016 = isUTF16Encoded(); bool s116 = inValue.isUTF16Encoded(); if (s016 || s116) { if (s016 && s116) return TIndexOf(s, __w, length, inValue.__w, inValue.length); while(s+l<=length) { if (s016 ? StrMatch(__w+s, inValue.__s, l) : StrMatch(inValue.__w, __s+s, l) ) return s; s++; } return -1; } #endif return TIndexOf(s, __s, length, inValue.__s, inValue.length); } template static int TLastIndexOf(int s, const T *str, int strLen, const T *sought, int soughtLen) { if (soughtLen==1) { T test = *sought; while(s>=0) { if (str[s]==test) return s; s--; } } else { while(s>=0) { if (!memcmp(str + s,sought,soughtLen*sizeof(T))) return s; --s; } } return -1; } int String::lastIndexOf(const String &inValue, Dynamic inStart) const { if (__s==0) return -1; int l = inValue.length; if (l>length) return -1; int s = inStart==null() ? length : inStart->__ToInt(); if (s+l>length) s = length-l; #ifdef HX_SMART_STRINGS bool s016 = isUTF16Encoded(); bool s116 = inValue.isUTF16Encoded(); if (s016 || s116) { if (s016 && s116) return TLastIndexOf(s, __w, length, inValue.__w, inValue.length); while(s>=0) { if (s016 ? StrMatch(__w+s, inValue.__s, l) : StrMatch(inValue.__w, __s+s, l) ) return s; s--; } return -1; } #endif return TLastIndexOf(s, __s, length, inValue.__s, inValue.length); } Dynamic String::charCodeAt(int inPos) const { if (inPos<0 || inPos>=length) return null(); #ifdef HX_SMART_STRINGS if (isUTF16Encoded()) { return (int)__w[inPos]; } #endif return (int)(((unsigned char *)__s)[inPos]); } String String::fromCharCode( int c ) { if (c<=255) { return sConstStrings[c]; } else { #ifdef HX_SMART_STRINGS if (IsUtf16Surrogate(c)||c>=0x110000) c = 0xFFFD; #endif int group = c>>10; if (group>=1088) hx::Throw(HX_CSTRING("Invalid char code")); if (!sCharToString[group]) { String *ptr = (String *)malloc( sizeof(String)*1024 ); memset(ptr, 0, sizeof(String)*1024 ); sCharToString[group] = ptr; } String *ptr = sCharToString[group]; int cid = c & ((1<<10)-1); if (!ptr[cid].__s) { #ifdef HX_SMART_STRINGS int l = UTF16BytesCheck(c); char16_t *p = (char16_t *)InternalCreateConstBuffer(0,(l+1)*2,true); ((unsigned int *)p)[-1] |= HX_GC_STRING_CHAR16_T; if (c>=0x10000) { int over = (c-0x10000); p[0] = (over>>10) + 0xd800; p[1] = (over&0x3ff) + 0xdc00; } else p[0] = c; ptr[cid].length = l; ptr[cid].__w = p; fixHashPerm16(ptr[cid]); #else char buf[5]; int utf8Len = UTF8Bytes(c); char *p = buf; UTF8EncodeAdvance(p,c); buf[utf8Len] = '\0'; const char *s = (char *)InternalCreateConstBuffer(buf,utf8Len+1,true); ptr[cid].length = utf8Len; ptr[cid].__s = s; #endif } return ptr[cid]; } } String String::charAt( int at ) const { if (at<0 || at>=length) return emptyString; #ifdef HX_SMART_STRINGS if (isUTF16Encoded()) return fromCharCode(__w[at]); #endif return fromCharCode(__s[at]); } void __hxcpp_bytes_of_string(Array &outBytes,const String &inString) { if (!inString.length) return; #ifdef HX_SMART_STRINGS if (inString.isUTF16Encoded()) { const char16_t *src = inString.raw_wptr(); const char16_t *end = src + inString.length; while(srcpush(c); else if( c <= 0x7FF ) { outBytes->push( 0xC0 | (c >> 6) ); outBytes->push( 0x80 | (c & 63) ); } else if( c <= 0xFFFF ) { outBytes->push( 0xE0 | (c >> 12) ); outBytes->push( 0x80 | ((c >> 6) & 63) ); outBytes->push( 0x80 | (c & 63) ); } else { outBytes->push( 0xF0 | (c >> 18) ); outBytes->push( 0x80 | ((c >> 12) & 63) ); outBytes->push( 0x80 | ((c >> 6) & 63) ); outBytes->push( 0x80 | (c & 63) ); } } } else #endif { outBytes->__SetSize(inString.length); memcpy(outBytes->GetBase(), inString.raw_ptr(),inString.length); } } #ifdef HX_SMART_STRINGS String _hx_utf8_to_utf16(const unsigned char *ptr, int inUtf8Len, bool addHash) { unsigned int hash = 0; if (addHash) for(int i=0;i &inBytes,String &outString,int pos,int len,bool inCopyPointer) { if (inCopyPointer) outString = String( (const char *)inBytes->GetBase(), len); else if (len==0) outString = String::emptyString; else { const unsigned char *p0 = (const unsigned char *)inBytes->GetBase(); #ifdef HX_SMART_STRINGS bool hasWChar = false; const unsigned char *p = p0 + pos; for(int i=0;i127) { hasWChar = true; break; } if (hasWChar) { outString = _hx_utf8_to_utf16(p0+pos,len,true); } else #endif outString = String( GCStringDup((const char *)p0+pos, len, 0), len); } } const char * String::utf8_str(hx::IStringAlloc *inBuffer,bool throwInvalid, int *byteLength) const { #ifdef HX_SMART_STRINGS if (isUTF16Encoded()) return TConvertToUTF8(__w,byteLength,inBuffer,throwInvalid); #endif if (byteLength != 0) { *byteLength = length; } return __s; } const char *String::ascii_substr(hx::IStringAlloc *inBuffer,int start, int length) const { #ifdef HX_SMART_STRINGS if (isUTF16Encoded()) { const char16_t *p0 = __w + start; const char16_t *p = p0; const char16_t *limit = p+length; while(p=127) break; p++; } int validLen = (int)(p-p0); char *result = (char *)inBuffer->allocBytes(validLen+1); for(int i=0;iallocBytes(length+1); memcpy(result,__s+start,length); result[length] = '\0'; return result; } #ifdef HX_SMART_STRINGS bool String::eq(const ::String &inRHS) const { if (length != inRHS.length) return false; bool s0IsWide = isUTF16Encoded(); if (s0IsWide != inRHS.isUTF16Encoded() ) return false; return !memcmp(__s, inRHS.__s, s0IsWide ? 2 * length : length ); } int String::compare(const ::String &inRHS) const { if (!__s) return inRHS.__s ? -1 : 0; if (!inRHS.__s) return 1; int cmp = 0; int minLen = length0) { bool s0IsWide = isUTF16Encoded(); bool s1IsWide = inRHS.isUTF16Encoded(); if (s0IsWide==s1IsWide) { if (!s0IsWide) { cmp = memcmp(__s,inRHS.__s,minLen); } else { for(int i=0;iallocBytes(2*(char16Count+1)) : (char16_t *)NewGCPrivate(0,2*(char16Count+1)); u = ptr; char16_t *o = str; while(uallocBytes(sizeof(wchar_t)*(length+1) ); } else { result = (wchar_t *)NewGCPrivate(0,sizeof(wchar_t)*(length+1) ); } if (isUTF16Encoded()) for(int i=0;iallocBytes(sizeof(wchar_t)*(idx+1) ); } else { result = (wchar_t *)NewGCPrivate(0,sizeof(wchar_t)*(idx+1) ); } ptr = (const unsigned char *)__s; idx = 0; while(ptr String::split(const String &inDelimiter) const { int len = inDelimiter.length; int pos = 0; int last = 0; if (len==0) { // Special case of splitting into characters - use efficient code... int chars = length; Array result(0,chars); int idx = 0; #ifdef HX_SMART_STRINGS if (isUTF16Encoded()) { const char16_t *p = __w; for(int i=0;i result(0,1); #if HX_SMART_STRINGS bool s0 = isUTF16Encoded(); bool s1 = inDelimiter.isUTF16Encoded(); if (s0 || s1) { if (s0 && s1) { while(pos+len <=length ) if (!memcmp(__w+pos,inDelimiter.__w,len*2)) { result->push( substr(last,pos-last) ); pos += len; last = pos; } else pos++; } else if (s0) while(pos+len <=length ) if (isSame(__w+pos,inDelimiter.__s,len)) { result->push( substr(last,pos-last) ); pos += len; last = pos; } else pos++; else while(pos+len <=length ) if (isSame(inDelimiter.__w,__s+pos,len)) { result->push( substr(last,pos-last) ); pos += len; last = pos; } else pos++; } else #endif { while(pos+len <=length ) if (!strncmp(__s+pos,inDelimiter.__s,len)) { result->push( substr(last,pos-last) ); pos += len; last = pos; } else pos++; } result->push( substr(last,null()) ); return result; } Dynamic CreateEmptyString() { return sConstEmptyString; } Dynamic CreateString(DynamicArray inArgs) { if (inArgs->__length()>0) return inArgs[0]->toString(); return String(); } String String::substr(int inFirst, Dynamic inLen) const { int len = inLen == null() ? length : inLen->__ToInt(); if (inFirst<0) inFirst += length; if (inFirst<0) inFirst = 0; if (len<0) { len += length; // This logic matches flash .... if (inFirst + len >=length) len = 0; } if (len<=0 || inFirst>=length) return String::emptyString; if ((len+inFirst > length) ) len = length - inFirst; if (len==0) return String::emptyString; #ifdef HX_SMART_STRINGS if (isUTF16Encoded()) { if (len==1) return String::fromCharCode(__w[inFirst]); return String( GCStringDup(__w+inFirst, len, 0), len ); } #endif if (len==1) return String::fromCharCode(__s[inFirst]); return String( GCStringDup(__s+inFirst, len, 0), len ); } String String::substring(int startIndex, Dynamic inEndIndex) const { int endIndex = inEndIndex == null() ? length : inEndIndex->__ToInt(); if ( endIndex < 0 ) { endIndex = 0; } else if ( endIndex > length ) { endIndex = length; } if ( startIndex < 0 ) { startIndex = 0; } else if ( startIndex > length ) { startIndex = length; } if ( startIndex > endIndex ) { int tmp = startIndex; startIndex = endIndex; endIndex = tmp; } return substr( startIndex, endIndex - startIndex ); } String String::operator+(const String &inRHS) const { if (!__s) return HX_CSTRING("null") + inRHS; if (!length) { if (!inRHS.__s) return HX_CSTRING("null"); return inRHS; } if (!inRHS.__s) return *this + HX_CSTRING("null"); if (!inRHS.length) return *this; int l = length + inRHS.length; #ifdef HX_SMART_STRINGS bool ws0 = isUTF16Encoded(); bool ws1 = inRHS.isUTF16Encoded(); if (ws0 || ws1) { char16_t *result = String::allocChar16Ptr(l); if (ws0) memcpy(result,__w,length*2); else for(int i=0;i0) { int l = length + inRHS.length; #ifdef HX_SMART_STRINGS bool ws0 = isUTF16Encoded(); bool ws1 = inRHS.isUTF16Encoded(); if (ws0 || ws1) { char16_t *result = String::allocChar16Ptr(l); if (ws0) memcpy(result,__w,length*2); else for(int i=0;i(mThis.raw_ptr()); } \ int __ArgCount() const { return ARG_C; } \ Dynamic __Run(const Array &inArgs) \ { \ return mThis.func(array_list); return Dynamic(); \ } \ Dynamic __run(dynamic_arg_list) \ { \ return mThis.func(arg_list); return Dynamic(); \ } \ void __Mark(hx::MarkContext *__inCtx) { HX_MARK_STRING(mThis.raw_ptr()); } \ STRING_VISIT_FUNC \ void __SetThis(Dynamic inThis) { mThis = inThis; } \ }; \ Dynamic String::func##_dyn() { return new __String_##func(*this); } #define DEFINE_STRING_FUNC0(func) DEFINE_STRING_FUNC(func,HX_ARR_LIST0,HX_DYNAMIC_ARG_LIST0,HX_ARG_LIST0,0) #define DEFINE_STRING_FUNC1(func) DEFINE_STRING_FUNC(func,HX_ARR_LIST1,HX_DYNAMIC_ARG_LIST1,HX_ARG_LIST1,1) #define DEFINE_STRING_FUNC2(func) DEFINE_STRING_FUNC(func,HX_ARR_LIST2,HX_DYNAMIC_ARG_LIST2,HX_ARG_LIST2,2) DEFINE_STRING_FUNC1(charAt); DEFINE_STRING_FUNC1(charCodeAt); DEFINE_STRING_FUNC2(indexOf); DEFINE_STRING_FUNC2(lastIndexOf); DEFINE_STRING_FUNC1(split); DEFINE_STRING_FUNC2(substr); DEFINE_STRING_FUNC2(substring); DEFINE_STRING_FUNC0(toLowerCase); DEFINE_STRING_FUNC0(toUpperCase); DEFINE_STRING_FUNC0(toString); hx::Val String::__Field(const String &inString, hx::PropertyAccess inCallProp) { if (HX_FIELD_EQ(inString,"length")) return length; if (HX_FIELD_EQ(inString,"charAt")) return charAt_dyn(); if (HX_FIELD_EQ(inString,"charCodeAt")) return charCodeAt_dyn(); if (HX_FIELD_EQ(inString,"indexOf")) return indexOf_dyn(); if (HX_FIELD_EQ(inString,"lastIndexOf")) return lastIndexOf_dyn(); if (HX_FIELD_EQ(inString,"split")) return split_dyn(); if (HX_FIELD_EQ(inString,"substr")) return substr_dyn(); if (HX_FIELD_EQ(inString,"substring")) return substring_dyn(); if (HX_FIELD_EQ(inString,"toLowerCase")) return toLowerCase_dyn(); if (HX_FIELD_EQ(inString,"toUpperCase")) return toUpperCase_dyn(); if (HX_FIELD_EQ(inString,"toString")) return toString_dyn(); return null(); } static String sStringStatics[] = { HX_CSTRING("fromCharCode"), String(null()) }; static String sStringFields[] = { HX_CSTRING("length"), HX_CSTRING("charAt"), HX_CSTRING("charCodeAt"), HX_CSTRING("indexOf"), HX_CSTRING("lastIndexOf"), HX_CSTRING("split"), HX_CSTRING("substr"), HX_CSTRING("substring"), HX_CSTRING("toLowerCase"), HX_CSTRING("toUpperCase"), HX_CSTRING("toString"), String(null()) }; STATIC_HX_DEFINE_DYNAMIC_FUNC1(String,fromCharCode,return ) namespace hx { #ifndef HX_WINDOWS inline double _wtof(const wchar_t *inStr) { #ifdef ANDROID char buf[101]; int i; for(i=0;i<100 && inStr[i];i++) buf[i] = inStr[i]; buf[i] = '\0'; return strtod(buf, 0); #else return wcstod(inStr,0); #endif } #ifdef HX_ANDROID int my_wtol(const wchar_t *inStr,wchar_t ** end, int inBase) { char buf[101]; int i; for(i=0;i<100 && inStr[i];i++) buf[i] = inStr[i]; buf[i] = '\0'; char *cend = buf; int result = strtol(buf,&cend,inBase); *end = (wchar_t *)inStr + (cend-buf); return result; } #define wcstol my_wtol #endif inline int _wtoi(const wchar_t *inStr) { wchar_t *end = 0; if (!inStr) return 0; long result = 0; if (inStr[0]=='0' && (inStr[1]=='x' || inStr[1]=='X')) result = wcstol(inStr,&end,16); else result = wcstol(inStr,&end,10); return result; } #endif class StringData : public hx::Object { public: HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdString }; inline void *operator new( size_t inSize, hx::NewObjectType inAlloc=hx::NewObjContainer) { return hx::Object::operator new(inSize,inAlloc); } StringData(String inValue) : mValue(inValue) { HX_OBJ_WB_GET(this,mValue.raw_ref()); }; hx::Class __GetClass() const { return __StringClass; } #if (HXCPP_API_LEVEL<331) bool __Is(hx::Object *inClass) const { return dynamic_cast< StringData *>(inClass); } #endif virtual int __GetType() const { return vtString; } String __ToString() const { return mValue; } String toString() { return mValue; } double __ToDouble() const { if (!mValue.raw_ptr()) return 0; #ifdef HX_ANDROID return strtod(mValue.utf8_str(),0); #else return atof(mValue.utf8_str()); #endif } int __length() const { return mValue.length; } void __Mark(hx::MarkContext *__inCtx) { HX_MARK_MEMBER(mValue); } #ifdef HXCPP_VISIT_ALLOCS void __Visit(hx::VisitContext *__inCtx) { HX_VISIT_MEMBER(mValue); } #endif int __ToInt() const { if (!mValue.raw_ptr()) return 0; return atoi(mValue.utf8_str()); } int __Compare(const hx::Object *inRHS) const { return mValue.compare( const_cast(inRHS)->toString() ); } hx::Val __Field(const String &inString, hx::PropertyAccess inCallProp) { return mValue.__Field(inString, inCallProp); } String mValue; }; hx::Class &GetStringClass() { return __StringClass; } } // end namespace hx hx::Object *String::__ToObject() const { if (!__s) return 0; if (length==0) { return sConstEmptyString.mPtr; } else if (length==1) { #ifdef HX_SMART_STRINGS int idx = isUTF16Encoded() ? __w[0] : ((unsigned char *)__s)[0]; #else int idx = ((unsigned char *)__s)[0]; #endif if (idx<=255) { if (sConstDynamicStrings[idx].mPtr) return sConstDynamicStrings[idx].mPtr; return sConstDynamicStrings[idx].mPtr = new (hx::NewObjConst)StringData(fromCharCode(idx)); } } bool isConst = __s[HX_GC_CONST_ALLOC_MARK_OFFSET] & HX_GC_CONST_ALLOC_MARK_BIT; NewObjectType type = isConst ? NewObjAlloc : NewObjContainer; return new (type) StringData(*this); } hx::Object * String::makePermanentObject() const { return new (hx::NewObjConst)StringData(makePermanent()); } void String::__boot() { #ifdef HXCPP_COMBINE_STRINGS InitIdent(); #endif sPermanentStringSet = new StringSet(); GCAddRoot((hx::Object **)&sPermanentStringSet); for(int i=0;i<256;i++) safeChars[i] = i>32 && i<127; unsigned char dodgy[] = { 36, 38, 43, 44, 47, 58, 59, 61, 63, 64, 34, 60, 62, 35, 37, 123, 125, 124, 92, 94, 126, 91, 93, 96 }; for(int i=0;i127) { char16_t buf[20]; buf[0] = c; buf[1] = '\0'; sConstStrings[c].length = 1; char16_t *w = (char16_t *)InternalCreateConstBuffer(buf,2*2,true); ((unsigned int *)w)[-1] |= HX_GC_STRING_CHAR16_T; sConstStrings[c].__w = w; fixHashPerm16(sConstStrings[c]); } else #endif { char buf[20]; int utf8Len = UTF8Bytes(c); char *p = buf; UTF8EncodeAdvance(p,c); buf[utf8Len] = '\0'; sConstStrings[c].__s = (char *)InternalCreateConstBuffer(buf,utf8Len+1,true); sConstStrings[c].length = utf8Len; } } sConstEmptyString.mPtr = new (hx::NewObjConst)StringData(emptyString); Static(__StringClass) = hx::_hx_RegisterClass(HX_CSTRING("String"),TCanCast,sStringStatics, sStringFields, &CreateEmptyString, &CreateString, 0, 0, 0 ); }