diff options
author | nyamatongwe <unknown> | 2011-06-04 21:46:49 +1000 |
---|---|---|
committer | nyamatongwe <unknown> | 2011-06-04 21:46:49 +1000 |
commit | c53e82e6002f1edce443260d48e45688fbbca85c (patch) | |
tree | 60de4594da696d4ac2ba1a1d27fbb336d5d07269 | |
parent | 1e8e06f21d6b2b74e0db767890058a48d9cc81b1 (diff) | |
download | scintilla-mirror-c53e82e6002f1edce443260d48e45688fbbca85c.tar.gz |
Added encoding-sensitive case folding.
-rw-r--r-- | cocoa/ScintillaCocoa.h | 1 | ||||
-rw-r--r-- | cocoa/ScintillaCocoa.mm | 153 |
2 files changed, 147 insertions, 7 deletions
diff --git a/cocoa/ScintillaCocoa.h b/cocoa/ScintillaCocoa.h index a5d6575f4..639a714cc 100644 --- a/cocoa/ScintillaCocoa.h +++ b/cocoa/ScintillaCocoa.h @@ -122,6 +122,7 @@ protected: virtual void Initialise(); virtual void Finalise(); + virtual CaseFolder *CaseFolderForEncoding(); virtual std::string CaseMapString(const std::string &s, int caseMapping); public: ScintillaCocoa(NSView* view); diff --git a/cocoa/ScintillaCocoa.mm b/cocoa/ScintillaCocoa.mm index 1bc062ced..9321666d8 100644 --- a/cocoa/ScintillaCocoa.mm +++ b/cocoa/ScintillaCocoa.mm @@ -256,25 +256,164 @@ void ScintillaCocoa::Finalise() //-------------------------------------------------------------------------------------------------- /** + * Convert a core foundation string into an array of bytes in a particular encoding + */ + +static char *EncodedBytes(CFStringRef cfsRef, CFStringEncoding encoding) { + CFRange rangeAll = {0, CFStringGetLength(cfsRef)}; + CFIndex usedLen = 0; + CFStringGetBytes(cfsRef, rangeAll, encoding, '?', + false, NULL, 0, &usedLen); + + char *buffer = new char[usedLen+1]; + CFStringGetBytes(cfsRef, rangeAll, encoding, '?', + false, (UInt8 *)buffer,usedLen, NULL); + buffer[usedLen] = '\0'; + return buffer; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Case folders. + */ + +class CaseFolderUTF8 : public CaseFolderTable { +public: + CaseFolderUTF8() { + StandardASCII(); + } + virtual size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) { + if ((lenMixed == 1) && (sizeFolded > 0)) { + folded[0] = mapping[static_cast<unsigned char>(mixed[0])]; + return 1; + } else { + CFStringRef cfsVal = CFStringCreateWithBytes(kCFAllocatorDefault, + reinterpret_cast<const UInt8 *>(mixed), + lenMixed, kCFStringEncodingUTF8, false); + + NSString *sMapped = [(NSString *)cfsVal stringByFoldingWithOptions:NSCaseInsensitiveSearch + locale:[NSLocale currentLocale]]; + + const char *cpMapped = [sMapped UTF8String]; + size_t lenMapped = strlen(cpMapped); + if (lenMapped < sizeFolded) { + memcpy(folded, cpMapped, lenMapped); + } else { + lenMapped = 0; + } + CFRelease(cfsVal); + return lenMapped; + } + } +}; + +class CaseFolderDBCS : public CaseFolderTable { + CFStringEncoding encoding; +public: + CaseFolderDBCS(CFStringEncoding encoding_) : encoding(encoding_) { + StandardASCII(); + } + virtual size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) { + if ((lenMixed == 1) && (sizeFolded > 0)) { + folded[0] = mapping[static_cast<unsigned char>(mixed[0])]; + return 1; + } else { + CFStringRef cfsVal = CFStringCreateWithBytes(kCFAllocatorDefault, + reinterpret_cast<const UInt8 *>(mixed), + lenMixed, encoding, false); + + NSString *sMapped = [(NSString *)cfsVal stringByFoldingWithOptions:NSCaseInsensitiveSearch + locale:[NSLocale currentLocale]]; + + char *encoded = EncodedBytes((CFStringRef)sMapped, encoding); + + size_t lenMapped = strlen(encoded); + if (lenMapped < sizeFolded) { + memcpy(folded, encoded, lenMapped); + } else { + folded[0] = '\0'; + lenMapped = 1; + } + delete []encoded; + CFRelease(cfsVal); + return lenMapped; + } + // Something failed so return a single NUL byte + folded[0] = '\0'; + return 1; + } +}; + +CaseFolder *ScintillaCocoa::CaseFolderForEncoding() { + if (pdoc->dbcsCodePage == SC_CP_UTF8) { + return new CaseFolderUTF8(); + } else { + CFStringEncoding encoding = EncodingFromCharacterSet(IsUnicodeMode(), + vs.styles[STYLE_DEFAULT].characterSet); + if (pdoc->dbcsCodePage == 0) { + CaseFolderTable *pcf = new CaseFolderTable(); + pcf->StandardASCII(); + // Only for single byte encodings + for (int i=0x80; i<0x100; i++) { + char sCharacter[2] = "A"; + sCharacter[0] = i; + CFStringRef cfsVal = CFStringCreateWithBytes(kCFAllocatorDefault, + reinterpret_cast<const UInt8 *>(sCharacter), + 1, encoding, false); + + NSString *sMapped = [(NSString *)cfsVal stringByFoldingWithOptions:NSCaseInsensitiveSearch + locale:[NSLocale currentLocale]]; + + char *encoded = EncodedBytes((CFStringRef)sMapped, encoding); + + if (strlen(encoded) == 1) { + pcf->SetTranslation(sCharacter[0], encoded[0]); + } + + delete []encoded; + CFRelease(cfsVal); + } + return pcf; + } else { + return new CaseFolderDBCS(encoding); + } + return 0; + } +} + + +//-------------------------------------------------------------------------------------------------- + +/** * Case-fold the given string depending on the specified case mapping type. - * Note: ScintillaCocoa exclusively works with Unicode. We don't even think about adding support for - * obsolete code page stuff. */ std::string ScintillaCocoa::CaseMapString(const std::string &s, int caseMapping) { - NSString* textToConvert = [NSString stringWithUTF8String: s.c_str()]; - std::string result; + CFStringEncoding encoding = EncodingFromCharacterSet(IsUnicodeMode(), + vs.styles[STYLE_DEFAULT].characterSet); + CFStringRef cfsVal = CFStringCreateWithBytes(kCFAllocatorDefault, + reinterpret_cast<const UInt8 *>(s.c_str()), + s.length(), encoding, false); + + NSString *sMapped; switch (caseMapping) { case cmUpper: - result = [[textToConvert uppercaseString] UTF8String]; + sMapped = [(NSString *)cfsVal uppercaseString]; break; case cmLower: - result = [[textToConvert lowercaseString] UTF8String]; + sMapped = [(NSString *)cfsVal lowercaseString]; break; default: - result = s; + sMapped = [(NSString *)cfsVal copy]; } + + // Back to encoding + char *encoded = EncodedBytes((CFStringRef)sMapped, encoding); + std::string result(encoded); + delete []encoded; + CFRelease(cfsVal); return result; } |