blob: 127e407cafbf31bcdc43db997cf39d9ac3c07384 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
// This file comes from the portion of the UX Write editor that
// works on both Apple platforms (that is, it can run on either
// OS X or iOS). It's in the repository for illustrative purposes
// only, to assist with the creation of the framework for the
// Corinthia editor UI. The code does not compile independently in
// its present form.
#import "EDUtil.h"
#import <FileClient/FCError.h>
#include <iconv.h>
int debugIndent = 0;
void debug(NSString *format, ...)
{
for (int i = 0; i < debugIndent; i++)
printf(" ");
va_list ap;
va_start(ap,format);
NSString *message = [[NSString alloc] initWithFormat: format arguments: ap];
va_end(ap);
printf("%s",message.UTF8String);
}
DFHashTable *HashTableFromNSDictionary(NSDictionary *dict)
{
if (dict == NULL)
return NULL;
DFHashTable *hashTable = DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
for (NSString *key in dict.allKeys) {
NSString *value = [dict objectForKey: key];
assert([value isKindOfClass: [NSString class]]);
DFHashTableAdd(hashTable,key.UTF8String,value.UTF8String);
}
return hashTable;
}
NSDictionary *NSDictionaryFromHashTable(DFHashTable *hashTable)
{
if (hashTable == NULL)
return NULL;
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity: 0];
const char **keys = DFHashTableCopyKeys(hashTable);
for (int i = 0; keys[i]; i++) {
const char *key = keys[i];
const char *value = DFHashTableLookup(hashTable,key);
[dict setObject: NSStringFromC(value) forKey: NSStringFromC(key)];
}
free(keys);
return dict;
}
NSDictionary *NSDictionaryFromNestedHashTable(DFHashTable *outerHash)
{
NSMutableDictionary *outerDict = [NSMutableDictionary dictionaryWithCapacity: 0];
const char **allOuterKeys = DFHashTableCopyKeys(outerHash);
for (int outerIndex = 0; allOuterKeys[outerIndex]; outerIndex++) {
const char *outerKey = allOuterKeys[outerIndex];
DFHashTable *innerHash = DFHashTableLookup(outerHash,outerKey);
assert(innerHash != NULL);
NSDictionary *innerDict = NSDictionaryFromHashTable(innerHash);
[outerDict setObject: innerDict forKey: NSStringFromC(outerKey)];
}
free(allOuterKeys);
return outerDict;
}
#define UTF16IsLeadSurrogate(_c) (((_c) >= 0xD800) && ((_c) <= 0xDBFF))
#define UTF16IsTrailSurrogate(_c) (((_c) >= 0xDC00) && ((_c) <= 0xDFFF))
typedef struct DFUTF16Buffer DFUTF16Buffer;
struct DFUTF16Buffer {
size_t alloc;
size_t len;
char *data;
};
static void DFUTF16BufferInit(DFUTF16Buffer *buf, size_t alloc)
{
buf->alloc = alloc;
buf->len = 0;
buf->data = (char *)malloc(buf->alloc*sizeof(char));
}
static void DFUTF16BufferDestroy(DFUTF16Buffer *buf)
{
free(buf->data);
}
static void DFUTF16BufferExpand(DFUTF16Buffer *buf)
{
buf->alloc = (buf->alloc == 0) ? 1 : buf->alloc*2;
buf->data = (char *)realloc(buf->data,buf->alloc*sizeof(char));
}
void DFCharEncodingConvert(iconv_t ic, void *data, size_t len, DFUTF16Buffer *output)
{
iconv(ic,NULL,NULL,NULL,NULL); // Reset converter state
char *inbuf = (char *)data;
size_t inbytesleft = len;
output->len = 0;
while (inbytesleft > 0) {
const char *oldInbuf = inbuf;
char *outbuf = &output->data[output->len];
size_t outbytesleft = output->alloc - output->len;
size_t r = iconv(ic,&inbuf,&inbytesleft,&outbuf,&outbytesleft);
if (r == ((size_t)-1)) {
if ((errno == EILSEQ) || (errno == EINVAL)) {
// Invalid or incomplete multibyte sequence; skip it
inbuf++;
inbytesleft--;
iconv(ic,NULL,NULL,NULL,NULL); // Reset converter state
// We still want the output that was generated
output->len = outbuf - output->data;
assert(output->len <= output->alloc);
continue;
}
}
if (oldInbuf == inbuf) {
DFUTF16BufferExpand(output);
}
else {
output->len = outbuf - output->data;
assert(output->len <= output->alloc);
}
}
}
int DFCharEncodingFixChars(uint16_t *chars, NSUInteger len)
{
int changed = 0;
NSUInteger i = 0;
while (i < len) {
if (UTF16IsLeadSurrogate(chars[i])) {
if ((i+1 < len) && UTF16IsTrailSurrogate(chars[i+1])) {
// VALID: Surrogate pair
i += 2;
}
else {
// INVALID: Missing trail surrogate
chars[i] = '?';
changed = 1;
i += 1;
}
}
else if (UTF16IsTrailSurrogate(chars[i])) {
// INVALID: Unexpected trail surrogate
chars[i] = '?';
changed = 1;
i += 1;
}
else {
// VALID: Single character
i += 1;
}
}
return changed;
}
NSString *DFCharEncodingFixNSString(NSString *str)
{
NSUInteger len = str.length;
uint16_t *chars = (uint16_t *)malloc(len*sizeof(uint16_t));
[str getCharacters: chars range: NSMakeRange(0,len)];
if (DFCharEncodingFixChars(chars,len))
str = [NSString stringWithCharacters: chars length: len];
free(chars);
return str;
}
static void printHex(const void *data, size_t len)
{
const char *chars = (const char *)data;
for (size_t i = 0; i < len; i++) {
printf("%02X ",(unsigned char)chars[i]);
}
printf("\n");
}
static void printChars(const void *data, size_t len)
{
const char *chars = (const char *)data;
for (size_t i = 0; i < len; i++) {
if ((chars[i] >= 32) && (chars[i] <= 127))
printf("%c ",chars[i]);
else
printf(". ");
}
printf("\n");
}
void DFCharEncodingTest(void)
{
iconv_t *UTF8toUCS2 = iconv_open("UCS-2-INTERNAL","UTF-8");
assert(UTF8toUCS2 != ((iconv_t)-1));
printf("u8tou16 = %p\n",UTF8toUCS2);
iconv_t *UCS2toUTF8 = iconv_open("UTF-8","UCS-2-INTERNAL");
assert(UCS2toUTF8 != ((iconv_t)-1));
printf("UCS2toUTF8 = %p\n",UCS2toUTF8);
char *input = "Hello 多语种多多网站";
size_t inputLen = strlen(input);
printf("%s\n",input);
printHex(input,inputLen);
printChars(input,inputLen);
printf("----\n");
NSString *str = [NSString stringWithCString: input encoding: NSUTF8StringEncoding];
uint16_t *chars = (uint16_t *)calloc(1,str.length*sizeof(uint16_t));
[str getCharacters: chars range: NSMakeRange(0,str.length)];
printHex(chars,str.length*sizeof(uint16_t));
printChars(chars,str.length*sizeof(uint16_t));
free(chars);
printf("----\n");
DFUTF16Buffer ucs2;
DFUTF16BufferInit(&ucs2,0);
DFCharEncodingConvert(UTF8toUCS2,input,inputLen,&ucs2);
printHex(ucs2.data,ucs2.len);
printChars(ucs2.data,ucs2.len);
printf("----\n");
DFUTF16Buffer utf8;
DFUTF16BufferInit(&utf8,0);
DFCharEncodingConvert(UCS2toUTF8,ucs2.data,ucs2.len,&utf8);
printHex(utf8.data,utf8.len);
printChars(utf8.data,utf8.len);
char *temp = (char*)malloc(utf8.len+1);
memcpy(temp,utf8.data,utf8.len);
temp[utf8.len] = '\0';
printf("%s\n",temp);
free(temp);
DFUTF16BufferDestroy(&ucs2);
DFUTF16BufferDestroy(&utf8);
}
NSString *DFFixStringEncoding(NSString *str)
{
return DFCharEncodingFixNSString(str);
}
NSString *NSStringFromC(const char *cstr)
{
if (cstr == NULL)
return NULL;
else
return [NSString stringWithUTF8String: cstr];
}
void NSErrorSetFromDFError(NSError **nserror, DFError *dferror)
{
if ((nserror == NULL) || (dferror == NULL))
return;
[NSError set: nserror format: @"%@", NSStringFromC(DFErrorMessage(&dferror))];
}
void DFErrorReleaseToNSError(DFError *dferror, NSError **nserror)
{
NSErrorSetFromDFError(nserror,dferror);
}
void DFErrorSetFromNSError(DFError **dferror, NSError *nserror)
{
if ((nserror == NULL) || (dferror == NULL))
return;
DFErrorFormat(dferror,"%s",FCErrorDescription(nserror).UTF8String);
}
BOOL EDStringEquals(NSString *a, NSString *b)
{
if ((a == NULL) && (b == NULL))
return YES;
else if ((a != NULL) && (b != NULL))
return [a isEqualToString: b];
else
return NO;
}
NSString *EDEncodeFontFamily(NSString *input)
{
char *cresult = CSSEncodeFontFamily(input.UTF8String);
NSString *nsresult = NSStringFromC(cresult);
free(cresult);
return nsresult;
}
NSString *EDDecodeFontFamily(NSString *input)
{
char *cresult = CSSDecodeFontFamily(input.UTF8String);
NSString *nsresult = NSStringFromC(cresult);
free(cresult);
return nsresult;
}