#include #include #include #include #include #include #include #include "ConvertUTF.h" #include "smutil.h" const bool mux_isdigit[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; const bool mux_isspace[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; #define mux_isdigit(x) (mux_isdigit[(unsigned char)(x)]) #define mux_isspace(x) (mux_isspace[(unsigned char)(x)]) const char TableATOI[16][10] = { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}, { 20, 21, 22, 23, 24, 25, 26, 27, 28, 29}, { 30, 31, 32, 33, 34, 35, 36, 37, 38, 39}, { 40, 41, 42, 43, 44, 45, 46, 47, 48, 49}, { 50, 51, 52, 53, 54, 55, 56, 57, 58, 59}, { 60, 61, 62, 63, 64, 65, 66, 67, 68, 69}, { 70, 71, 72, 73, 74, 75, 76, 77, 78, 79}, { 80, 81, 82, 83, 84, 85, 86, 87, 88, 89}, { 90, 91, 92, 93, 94, 95, 96, 97, 98, 99} }; long mux_atol(const char *pString) { long sum = 0; int LeadingCharacter = 0; // Convert ASCII digits // unsigned int c1; unsigned int c0 = pString[0]; if (!mux_isdigit(c0)) { while (mux_isspace(pString[0])) { pString++; } LeadingCharacter = pString[0]; if ( LeadingCharacter == '-' || LeadingCharacter == '+') { pString++; } c0 = pString[0]; if (!mux_isdigit(c0)) { return 0; } } do { c1 = pString[1]; if (mux_isdigit(c1)) { sum = 100 * sum + TableATOI[c0-'0'][c1-'0']; pString += 2; } else { sum = 10 * sum + (c0-'0'); break; } } while (mux_isdigit(c0 = pString[0])); // Interpret sign // if (LeadingCharacter == '-') { sum = -sum; } return sum; } // Korean Hangul Constants. // const UTF32 SBase = 0xAC00; const UTF32 LBase = 0x1100; const UTF32 VBase = 0x1161; const UTF32 TBase = 0x11A7; const UTF32 SCount = 11172; const int LCount = 19; const int VCount = 21; const int TCount = 28; const int NCount = VCount * TCount; const size_t codepoints = 1114109; #define CATEGORY_LETTER 0x0001000 #define SUBCATEGORY_UPPER 0x0000001 // Lu #define SUBCATEGORY_LOWER 0x0000002 // Ll #define SUBCATEGORY_TITLE 0x0000004 // Lt #define SUBCATEGORY_LET_MODIFIER 0x0000008 // Lm #define SUBCATEGORY_LET_OTHER 0x0000010 // Lo #define CATEGORY_MARK 0x0002000 #define SUBCATEGORY_NONSPACING 0x0000001 // Mn #define SUBCATEGORY_SPACING_COMBINING 0x0000002 // Mc #define SUBCATEGORY_SPACING_ENCLOSING 0x0000004 // Me #define CATEGORY_NUMBER 0x0004000 #define SUBCATEGORY_DECIMAL_DIGIT 0x0000001 // Nd #define SUBCATEGORY_LETTER 0x0000002 // Nl #define SUBCATEGORY_NUM_OTHER 0x0000004 // No #define CATEGORY_PUNCTUATION 0x0008000 #define SUBCATEGORY_CONNECTOR 0x0000001 // Pc #define SUBCATEGORY_DASH 0x0000002 // Pd #define SUBCATEGORY_OPEN 0x0000004 // Ps #define SUBCATEGORY_CLOSE 0x0000008 // Pe #define SUBCATEGORY_INITIAL_QUOTE 0x0000010 // Pi #define SUBCATEGORY_FINAL_QUOTE 0x0000020 // Pf #define SUBCATEGORY_PUNC_OTHER 0x0000040 // Po #define CATEGORY_SYMBOL 0x0010000 #define SUBCATEGORY_MATH 0x0000001 // Sm #define SUBCATEGORY_CURRENCY 0x0000002 // Sc #define SUBCATEGORY_SYM_MODIFIER 0x0000004 // Sk #define SUBCATEGORY_SYM_OTHER 0x0000008 // So #define CATEGORY_SEPARATOR 0x0020000 #define SUBCATEGORY_SPACE 0x0000001 // Zs #define SUBCATEGORY_LINE 0x0000002 // Zl #define SUBCATEGORY_PARAGRAPH 0x0000004 // Zp #define CATEGORY_OTHER 0x0040000 #define SUBCATEGORY_CONTROL 0x0000001 // Cc #define SUBCATEGORY_FORMAT 0x0000002 // Cf #define SUBCATEGORY_SURROGATE 0x0000004 // Cs #define SUBCATEGORY_PRIVATE_USE 0x0000008 // Co #define SUBCATEGORY_NOT_ASSIGNED 0x0000010 // Cn static struct { int cat; const char *catlet; } CategoryTable[] = { { CATEGORY_LETTER|SUBCATEGORY_UPPER, "Lu" }, { CATEGORY_LETTER|SUBCATEGORY_LOWER, "Ll" }, { CATEGORY_LETTER|SUBCATEGORY_TITLE, "Lt" }, { CATEGORY_LETTER|SUBCATEGORY_LET_MODIFIER, "Lm" }, { CATEGORY_LETTER|SUBCATEGORY_LET_OTHER, "Lo" }, { CATEGORY_MARK|SUBCATEGORY_NONSPACING, "Mn" }, { CATEGORY_MARK|SUBCATEGORY_SPACING_COMBINING, "Mc" }, { CATEGORY_MARK|SUBCATEGORY_SPACING_ENCLOSING, "Me" }, { CATEGORY_NUMBER|SUBCATEGORY_DECIMAL_DIGIT, "Nd" }, { CATEGORY_NUMBER|SUBCATEGORY_LETTER, "Nl" }, { CATEGORY_NUMBER|SUBCATEGORY_NUM_OTHER, "No" }, { CATEGORY_PUNCTUATION|SUBCATEGORY_CONNECTOR, "Pc" }, { CATEGORY_PUNCTUATION|SUBCATEGORY_DASH, "Pd" }, { CATEGORY_PUNCTUATION|SUBCATEGORY_OPEN, "Ps" }, { CATEGORY_PUNCTUATION|SUBCATEGORY_CLOSE, "Pe" }, { CATEGORY_PUNCTUATION|SUBCATEGORY_INITIAL_QUOTE, "Pi" }, { CATEGORY_PUNCTUATION|SUBCATEGORY_FINAL_QUOTE, "Pf" }, { CATEGORY_PUNCTUATION|SUBCATEGORY_PUNC_OTHER, "Po" }, { CATEGORY_SYMBOL|SUBCATEGORY_MATH, "Sm" }, { CATEGORY_SYMBOL|SUBCATEGORY_CURRENCY, "Sc" }, { CATEGORY_SYMBOL|SUBCATEGORY_SYM_MODIFIER, "Sk" }, { CATEGORY_SYMBOL|SUBCATEGORY_SYM_OTHER, "So" }, { CATEGORY_SEPARATOR|SUBCATEGORY_SPACE, "Zs" }, { CATEGORY_SEPARATOR|SUBCATEGORY_LINE, "Zl" }, { CATEGORY_SEPARATOR|SUBCATEGORY_PARAGRAPH, "Zp" }, { CATEGORY_OTHER|SUBCATEGORY_CONTROL, "Cc" }, { CATEGORY_OTHER|SUBCATEGORY_FORMAT, "Cf" }, { CATEGORY_OTHER|SUBCATEGORY_SURROGATE, "Cs" }, { CATEGORY_OTHER|SUBCATEGORY_PRIVATE_USE, "Co" }, { 0, NULL } }; #define BIDI_LEFT_TO_RIGHT 1 #define BIDI_LEFT_TO_RIGHT_EMBEDDING 2 #define BIDI_LEFT_TO_RIGHT_OVERRIDE 3 #define BIDI_RIGHT_TO_LEFT 4 #define BIDI_RIGHT_TO_LEFT_ARABIC 5 #define BIDI_RIGHT_TO_LEFT_EMBEDDING 6 #define BIDI_RIGHT_TO_LEFT_OVERRIDE 7 #define BIDI_POP_DIRECTIONAL_FORMAT 8 #define BIDI_EUROPEAN_NUMBER 9 #define BIDI_EUROPEAN_NUMBER_SEPARATOR 10 #define BIDI_EUROPEAN_NUMBER_TERMINATOR 11 #define BIDI_ARABIC_NUMBER 12 #define BIDI_COMMON_NUMBER_SEPARATOR 13 #define BIDI_NON_SPACING_MARK 14 #define BIDI_BOUNDARY_NEUTRAL 15 #define BIDI_PARAGRAPH_SEPARATOR 16 #define BIDI_SEGMENT_SEPARATOR 17 #define BIDI_WHITESPACE 18 #define BIDI_OTHER_NEUTRALS 19 static struct { int BiDi; const char *BiDiLet; } BiDiTable[] = { { BIDI_LEFT_TO_RIGHT, "L" }, { BIDI_LEFT_TO_RIGHT_EMBEDDING, "LRE" }, { BIDI_LEFT_TO_RIGHT_OVERRIDE, "LRO" }, { BIDI_RIGHT_TO_LEFT, "R" }, { BIDI_RIGHT_TO_LEFT_ARABIC, "AL" }, { BIDI_RIGHT_TO_LEFT_EMBEDDING, "RLE" }, { BIDI_RIGHT_TO_LEFT_OVERRIDE, "RLO" }, { BIDI_POP_DIRECTIONAL_FORMAT, "PDF" }, { BIDI_EUROPEAN_NUMBER, "EN" }, { BIDI_EUROPEAN_NUMBER_SEPARATOR, "ES" }, { BIDI_EUROPEAN_NUMBER_TERMINATOR, "ET" }, { BIDI_ARABIC_NUMBER, "AN" }, { BIDI_COMMON_NUMBER_SEPARATOR, "CS" }, { BIDI_NON_SPACING_MARK, "NSM" }, { BIDI_BOUNDARY_NEUTRAL, "BN" }, { BIDI_PARAGRAPH_SEPARATOR, "B" }, { BIDI_SEGMENT_SEPARATOR, "S" }, { BIDI_WHITESPACE, "WS" }, { BIDI_OTHER_NEUTRALS, "ON" }, { 0, NULL } }; #define DECOMP_TYPE_NONE 0 #define DECOMP_TYPE_FONT 1 #define DECOMP_TYPE_NOBREAK 2 #define DECOMP_TYPE_INITIAL 3 #define DECOMP_TYPE_MEDIAL 4 #define DECOMP_TYPE_FINAL 5 #define DECOMP_TYPE_ISOLATED 6 #define DECOMP_TYPE_CIRCLE 7 #define DECOMP_TYPE_SUPER 8 #define DECOMP_TYPE_SUB 9 #define DECOMP_TYPE_VERTICAL 10 #define DECOMP_TYPE_WIDE 11 #define DECOMP_TYPE_NARROW 12 #define DECOMP_TYPE_SMALL 13 #define DECOMP_TYPE_SQUARE 14 #define DECOMP_TYPE_FRACTION 15 #define DECOMP_TYPE_COMPAT 16 #define DECOMP_TYPE_ALL 17 static struct { int DecompType; const char *DecompTypeLet; } DecompTypeTable[] = { { DECOMP_TYPE_FONT, "font" }, { DECOMP_TYPE_NOBREAK, "noBreak" }, { DECOMP_TYPE_INITIAL, "initial" }, { DECOMP_TYPE_MEDIAL, "medial" }, { DECOMP_TYPE_FINAL, "final" }, { DECOMP_TYPE_ISOLATED, "isolated" }, { DECOMP_TYPE_CIRCLE, "circle" }, { DECOMP_TYPE_SUPER, "super" }, { DECOMP_TYPE_SUB, "sub" }, { DECOMP_TYPE_VERTICAL, "vertical" }, { DECOMP_TYPE_WIDE, "wide" }, { DECOMP_TYPE_NARROW, "narrow" }, { DECOMP_TYPE_SMALL, "small" }, { DECOMP_TYPE_SQUARE, "square" }, { DECOMP_TYPE_FRACTION, "fraction" }, { DECOMP_TYPE_COMPAT, "compat" }, { 0, NULL } }; #define MAPPING_ASCII 0 #define MAPPING_ISO_8859_1 1 #define MAPPING_ISO_8859_2 2 #define NUM_MAPPINGS 3 static struct { const char *pName; const char *pFilename; const char *pOutput; int Type; } MappingTypeTable[] = { { "ASCII", "cl_ascii.txt", "tr_utf8_ascii_out.txt", MAPPING_ASCII }, { "ISO-8859-1", "cl_8859_1.txt", "tr_utf8_latin1_out.txt", MAPPING_ISO_8859_1 }, { "ISO-8859-2", "cl_8859_2.txt", "tr_utf8_latin2_out.txt", MAPPING_ISO_8859_2 }, { NULL, 0 } }; class CodePoint { public: CodePoint(); ~CodePoint(); bool IsDefined(void) { return m_bDefined; }; void SetDescription(const char *pDescription); char *GetDescription(void) { return m_pDescription; }; void SetCategory(int category) { m_category = category; }; int GetCategory(void) { return m_category; }; const char *GetCategoryName(void); void SetCombiningClass(int cc) { m_class = cc; }; int GetCombiningClass(void) { return m_class; }; void SetBiDi(int bidi) { m_bidi = bidi; }; int GetBiDi(void) { return m_bidi; }; const char *GetBiDiName(void); void SetDecompositionType(int dt) { m_DecompType = dt; }; int GetDecompositionType(void) { return m_DecompType; }; const char *GetDecompositionTypeName(void); void SetDecompositionMapping(int nPoints, UTF32 pts[]); int GetDecompositionMapping(UTF32 pts[]); void SetDecimalDigitValue(int n); bool GetDecimalDigitValue(int *pn); void SetDigitValue(int n); bool GetDigitValue(int *pn); void SetNumericValue(const char *p); bool GetNumericValue(char **p); void SetBidiMirrored(bool b) { m_bBidiMirrored = b; }; bool GetBidiMirrored(void) { return m_bBidiMirrored; }; void SetUnicode1Name(const char *p); char *GetUnicode1Name(void) { return m_pUnicode1Name; }; void SetISOComment(const char *p); char *GetISOComment(void) { return m_pISOComment; }; void SetSimpleUppercaseMapping(UTF32 ptUpper) { m_SimpleUppercaseMapping = ptUpper; }; void SetSimpleLowercaseMapping(UTF32 ptLower) { m_SimpleLowercaseMapping = ptLower; }; void SetSimpleTitlecaseMapping(UTF32 ptTitle) { m_SimpleTitlecaseMapping = ptTitle; }; UTF32 GetSimpleUppercaseMapping(void) { return m_SimpleUppercaseMapping; }; UTF32 GetSimpleLowercaseMapping(void) { return m_SimpleLowercaseMapping; }; UTF32 GetSimpleTitlecaseMapping(void) { return m_SimpleTitlecaseMapping; }; void SetProhibited(void) { m_bProhibited = true; }; bool IsProhibited(void) { return m_bProhibited; }; void SetMapping(int m, unsigned char ch) { m_mappings[m].ch = ch; m_mappings[m].bIs = true; }; bool IsMapping(int m, unsigned char &ch) { ch = m_mappings[m].ch; return m_mappings[m].bIs; }; private: bool m_bDefined; char *m_pDescription; int m_category; int m_class; int m_bidi; int m_DecompType; int m_nDecompMapping; UTF32 m_aDecompMapping[30]; int m_nDecimalDigitValue; bool m_bHaveDecimalDigitValue; int m_nDigitValue; bool m_bHaveDigitValue; char *m_pNumericValue; bool m_bHaveNumericValue; bool m_bBidiMirrored; char *m_pUnicode1Name; char *m_pISOComment; UTF32 m_SimpleUppercaseMapping; UTF32 m_SimpleLowercaseMapping; UTF32 m_SimpleTitlecaseMapping; bool m_bProhibited; struct { bool bIs; unsigned char ch; } m_mappings[NUM_MAPPINGS]; }; void CodePoint::SetDecimalDigitValue(int n) { m_nDecimalDigitValue = n; m_bHaveDecimalDigitValue = true; } bool CodePoint::GetDecimalDigitValue(int *pn) { *pn = m_nDecimalDigitValue; return m_bHaveDecimalDigitValue; } void CodePoint::SetDigitValue(int n) { m_nDigitValue = n; m_bHaveDigitValue = true; } bool CodePoint::GetDigitValue(int *pn) { *pn = m_nDigitValue; return m_bHaveDigitValue; } void CodePoint::SetNumericValue(const char *p) { size_t n = strlen(p); m_pNumericValue = new char[n+1]; memcpy(m_pNumericValue, p, n+1); m_bHaveNumericValue = true; } bool CodePoint::GetNumericValue(char **p) { *p = m_pNumericValue; return m_bHaveNumericValue; } int CodePoint::GetDecompositionMapping(UTF32 pts[]) { for (int i = 0; i < m_nDecompMapping; i++) { pts[i] = m_aDecompMapping[i]; } return m_nDecompMapping; } void CodePoint::SetDecompositionMapping(int nPoints, UTF32 pts[]) { m_nDecompMapping = nPoints; for (int i = 0; i < nPoints; i++) { m_aDecompMapping[i] = pts[i]; } } CodePoint::CodePoint() { m_bDefined = false; m_pDescription = NULL; m_category = CATEGORY_OTHER|SUBCATEGORY_NOT_ASSIGNED; m_class = 0; m_bidi = BIDI_LEFT_TO_RIGHT; // BUG: The default is not the same for all code point values. m_DecompType = DECOMP_TYPE_NONE; m_nDecompMapping = 0; m_nDecimalDigitValue = 0; m_bHaveDecimalDigitValue = false; m_nDigitValue = 0; m_bHaveDigitValue = false; m_pNumericValue = NULL; m_bHaveNumericValue = false; m_bBidiMirrored = false; m_pUnicode1Name = NULL; m_pISOComment = NULL; m_SimpleUppercaseMapping = UNI_EOF; m_SimpleLowercaseMapping = UNI_EOF; m_SimpleTitlecaseMapping = UNI_EOF; m_bProhibited = false; for (int i = 0; i < NUM_MAPPINGS; i++) { m_mappings[i].bIs = false; } } CodePoint::~CodePoint() { if (NULL != m_pDescription) { delete [] m_pDescription; m_pDescription = NULL; } m_bDefined = false; } void CodePoint::SetDescription(const char *pDescription) { if (NULL != m_pDescription) { delete [] m_pDescription; m_pDescription = NULL; } size_t n = strlen(pDescription); m_pDescription = new char[n+1]; memcpy(m_pDescription, pDescription, n+1); m_bDefined = true; } void CodePoint::SetUnicode1Name(const char *p) { if (NULL != m_pUnicode1Name) { delete [] m_pUnicode1Name; m_pUnicode1Name = NULL; } size_t n = strlen(p); m_pUnicode1Name = new char[n+1]; memcpy(m_pUnicode1Name, p, n+1); } void CodePoint::SetISOComment(const char *p) { if (NULL != m_pISOComment) { delete [] m_pISOComment; m_pISOComment = NULL; } size_t n = strlen(p); m_pISOComment = new char[n+1]; memcpy(m_pISOComment, p, n+1); } class UniData { public: UniData() {}; ~UniData() {}; void LoadUnicodeDataFile(void); void LoadUnicodeDataLine(UTF32 codepoint, int nFields, char *aFields[]); void LoadUnicodeHanFile(void); void LoadMappings(void); void Prohibit(void); void SaveMasterFile(void); void SaveTranslateToUpper(void); void SaveTranslateToLower(void); void SaveTranslateToTitle(void); void SaveTranslateDecimalValue(void); void SaveMappings(); void SaveClassifyPrivateUse(void); void SaveDecompositions(void); void SaveClassifyPrintable(void); void SaveCombiningClass(void); void GetDecomposition(UTF32 pt, int dt, int &nPoints, UTF32 pts[]); private: CodePoint cp[codepoints+1]; }; UniData *g_UniData = NULL; void UniData::GetDecomposition(UTF32 pt, int dt, int &nPoints, UTF32 pts[]) { if (!cp[pt].IsDefined()) { exit(1); } if ( DECOMP_TYPE_NONE != cp[pt].GetDecompositionType() && DECOMP_TYPE_ALL != dt && dt != cp[pt].GetDecompositionType()) { pts[nPoints++] = pt; return; } UTF32 pts2[50]; int n = cp[pt].GetDecompositionMapping(pts2); if (n == 1 && pts2[0] == pt) { pts[nPoints++] = pt; return; } for (UTF32 i = 0; i < n; i++) { GetDecomposition(pts2[i], dt, nPoints, pts); } } int main(int argc, char *argv[]) { if (1 != argc) { printf("Usage: buildFiles uses UnicodeData.txt\n"); return 0; } g_UniData = new UniData; g_UniData->LoadUnicodeDataFile(); g_UniData->LoadUnicodeHanFile(); g_UniData->LoadMappings(); g_UniData->Prohibit(); g_UniData->SaveMasterFile(); g_UniData->SaveTranslateToUpper(); g_UniData->SaveTranslateToLower(); g_UniData->SaveTranslateToTitle(); g_UniData->SaveTranslateDecimalValue(); g_UniData->SaveMappings(); g_UniData->SaveClassifyPrivateUse(); g_UniData->SaveDecompositions(); g_UniData->SaveClassifyPrintable(); g_UniData->SaveCombiningClass(); return 0; } void UniData::LoadUnicodeDataFile(void) { FILE *fp = fopen("UnicodeData.txt", "r"); if (NULL != fp) { char buffer1[1024]; char buffer2[1024]; while (NULL != ReadLine(fp, buffer1, sizeof(buffer1))) { bool bRange = false; bool bRangeValid = false; int nFields1, nFields2; char *aFields1[15], *aFields2[15]; ParseFields(buffer1, 15, nFields1, aFields1); if ( 2 <= nFields1 && aFields1[1][0] == '<') { size_t n1 = strlen(aFields1[1]); if ( 9 <= n1 && strcmp(&aFields1[1][n1-8], ", First>") == 0) { bRange = true; if (NULL != ReadLine(fp, buffer2, sizeof(buffer2))) { ParseFields(buffer2, 15, nFields2, aFields2); if ( 2 <= nFields2 && aFields2[1][0] == '<') { size_t n2 = strlen(aFields2[1]); if ( 8 <= n2 && strcmp(&aFields2[1][n2-7], ", Last>") == 0) { aFields1[1][n1-8] = '\0'; aFields1[1]++; aFields2[1][n2-7] = '\0'; aFields2[1]++; bRangeValid = true; } } } } } if (!bRange) { // Single Code Point. // UTF32 pt = DecodeCodePoint(aFields1[0]); LoadUnicodeDataLine(pt, nFields1, aFields1); } else if (bRangeValid) { // Range of Code Points. // bool bMatches = false; if (nFields1 == nFields2) { bMatches = true; for (int i = 1; i < nFields1; i++) { if (strcmp(aFields1[i], aFields2[i]) != 0) { bMatches = false; } } } if (bMatches) { //printf("%s - %s\n", aFields1[0], aFields2[0]); UTF32 pt1 = DecodeCodePoint(aFields1[0]); UTF32 pt2 = DecodeCodePoint(aFields2[0]); if (pt1 != SBase) { // non-Hangul range. // for (UTF32 pt = pt1; pt <= pt2; pt++) { LoadUnicodeDataLine(pt, nFields1, aFields1); } } else { // Korean Hangul range. // for (UTF32 pt = pt1; pt <= pt2; pt++) { UTF32 SIndex = pt - SBase; UTF32 L = LBase + SIndex / NCount; UTF32 V = VBase + (SIndex % NCount) / TCount; UTF32 T = TBase + SIndex % TCount; char Hangul[1024]; if (T == TBase) { sprintf(Hangul, "%04X %04X", L, V); } else { sprintf(Hangul, "%04X %04X %04X", L, V, T); } aFields1[5] = Hangul; LoadUnicodeDataLine(pt, nFields1, aFields1); } } } else { printf("***ERROR: %s in range form does not agree with %s\n", aFields1[0], aFields2[0]); } } else { printf("***ERROR: Invalid Range form near %s\n", aFields1[0]); } } fclose(fp); } } void UniData::LoadUnicodeDataLine(UTF32 codepoint, int nFields, char *aFields[]) { if (codepoint <= codepoints) { // Description // if (2 <= nFields) { cp[codepoint].SetDescription(aFields[1]); } // Category // if (3 <= nFields) { bool bValid = false; int i = 0; while (CategoryTable[i].catlet) { if (strcmp(aFields[2], CategoryTable[i].catlet) == 0) { cp[codepoint].SetCategory(CategoryTable[i].cat); bValid = true; break; } i++; } if (!bValid) { printf("***ERROR: Invalid Category %s for U+%04X\n", aFields[2], codepoint); exit(1); } } // Combining Class. // if (4 <= nFields) { int cc = mux_atol(aFields[3]); cp[codepoint].SetCombiningClass(cc); } // Bidi algorithm. // if (5 <= nFields) { bool bValid = false; int i = 0; while (BiDiTable[i].BiDiLet) { if (strcmp(aFields[4], BiDiTable[i].BiDiLet) == 0) { cp[codepoint].SetBiDi(BiDiTable[i].BiDi); bValid = true; break; } i++; } if (!bValid) { printf("***ERROR: Invalid BiDi %s for U+%04X\n", aFields[4], codepoint); exit(1); } } // Decomposition Type and Mapping. // if (6 <= nFields) { bool bValid = false; const char *pDecomposition_Mapping = NULL; const char *pDecomposition_Type = NULL; if ('<' == aFields[5][0]) { char *p = strchr(aFields[5]+1, '>'); if (NULL != p) { *p++ = '\0'; while (mux_isspace(*p)) { p++; } pDecomposition_Type = aFields[5]+1; pDecomposition_Mapping = p; bValid = true; } } else { pDecomposition_Type = ""; pDecomposition_Mapping = aFields[5]; bValid = true; } if (bValid) { if ('\0' != pDecomposition_Type[0]) { bValid = false; int i = 0; while (DecompTypeTable[i].DecompType) { if (strcmp(pDecomposition_Type, DecompTypeTable[i].DecompTypeLet) == 0) { cp[codepoint].SetDecompositionType(DecompTypeTable[i].DecompType); bValid = true; break; } i++; } } if (!bValid) { printf("***ERROR: Decomposition Type Name not found (%s).\n", pDecomposition_Type); } else { int nPoints; const char *aPoints[30]; UTF32 pts[30]; ParsePoints(pDecomposition_Mapping, 30, nPoints, aPoints); for (int i = 0; i < nPoints; i++) { pts[i] = DecodeCodePoint(aPoints[i]); } if (0 == nPoints) { pts[0] = codepoint; nPoints = 1; } cp[codepoint].SetDecompositionMapping(nPoints, pts); } } else { printf("***ERROR: Expression malformed.\n"); } if (!bValid) { printf("***ERROR: Invalid Decomposition Type, '%s', or Mapping, '%s', for U+%04X\n", pDecomposition_Type, pDecomposition_Mapping, codepoint); exit(1); } } // Decimal Digit Value. // if ( 7 <= nFields && '\0' != aFields[6][0]) { int cc = mux_atol(aFields[6]); cp[codepoint].SetDecimalDigitValue(cc); } // Digit Value. // if ( 8 <= nFields && '\0' != aFields[7][0]) { int cc = mux_atol(aFields[7]); cp[codepoint].SetDigitValue(cc); } // Numeric Value. // if ( 9 <= nFields && '\0' != aFields[8][0]) { cp[codepoint].SetNumericValue(aFields[8]); } // Bidi_Mirrored. // if ( 10 <= nFields && '\0' != aFields[9][0]) { if ('Y' == aFields[9][0]) { cp[codepoint].SetBidiMirrored(true); } else if ('N' == aFields[9][0]) { cp[codepoint].SetBidiMirrored(false); } else { printf("Bidi_Mirrored '%s'.\n", aFields[9]); exit(1); } } // Unicode_1_Name. // if ( 11 <= nFields && '\0' != aFields[10][0]) { cp[codepoint].SetUnicode1Name(aFields[10]); } // ISO Comment. // if ( 12 <= nFields && '\0' != aFields[11][0]) { cp[codepoint].SetISOComment(aFields[11]); } // Simple Uppercase Mapping. // if ( 13 <= nFields && '\0' != aFields[12][0]) { UTF32 pt = DecodeCodePoint(aFields[12]); cp[codepoint].SetSimpleUppercaseMapping(pt); } // Simple Lowercase Mapping. // if ( 14 <= nFields && '\0' != aFields[13][0]) { UTF32 pt = DecodeCodePoint(aFields[13]); cp[codepoint].SetSimpleLowercaseMapping(pt); } // Simple Titlecase Mapping. // if ( 15 <= nFields && '\0' != aFields[14][0]) { UTF32 pt = DecodeCodePoint(aFields[14]); cp[codepoint].SetSimpleTitlecaseMapping(pt); } } } void UniData::LoadMappings(void) { for (int iMapping = 0; iMapping < NUM_MAPPINGS; iMapping++) { iconv_t iconvd = iconv_open(MappingTypeTable[iMapping].pName, "UTF-32LE"); if (((iconv_t)-1) == iconvd) { printf("iconv_open() error for %s.\n", MappingTypeTable[iMapping].pName); exit(1); } for (UTF32 pt = 0; pt <= codepoints; pt++) { if (cp[pt].IsDefined()) { UTF32 achIn[10]; size_t nIn = 2*sizeof(UTF32); char *pIn = (char *)achIn; unsigned char achOut[10]; size_t nOut = sizeof(achOut); char *pOut = (char *)achOut; achIn[0] = pt; achIn[1] = 0; size_t cnt = iconv(iconvd, NULL, NULL, NULL, NULL); cnt = iconv(iconvd, &pIn, &nIn, &pOut, &nOut); if ( ((size_t)-1) != cnt && '\0' != achOut[0] && '\0' == achOut[1]) { cp[pt].SetMapping(MappingTypeTable[iMapping].Type, achOut[0]); } } } iconv_close(iconvd); } } void UniData::SaveDecompositions() { FILE *fp = fopen("Decompositions.txt", "w+"); if (NULL == fp) { return; } for (UTF32 pt = 0; pt <= codepoints; pt++) { if (cp[pt].IsDefined()) { int nPoints = 0; UTF32 pts[100]; GetDecomposition(pt, DECOMP_TYPE_NONE, nPoints, pts); if (nPoints != 1 || pts[0] != pt) { fprintf(fp, "%04X;", pt); for (UTF32 pt2 = 0; pt2 < nPoints; pt2++) { if (pt2 != 0) { fprintf(fp, " "); } fprintf(fp, "%04X", pts[pt2]); } fprintf(fp, ";%s\n", cp[pt].GetDescription()); } } } fclose(fp); } void UniData::SaveCombiningClass() { FILE *fp = fopen("tr_class.txt", "w+"); if (NULL == fp) { return; } for (UTF32 pt = 0; pt <= codepoints; pt++) { if (cp[pt].IsDefined()) { static const int table[] = { 0, 1, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 84, 91, 103, 107, 118, 122, 129, 130, 132, 202, 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, 233, 234, 240, }; int i; int cc = cp[pt].GetCombiningClass(); for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) { if (table[i] == cc) { fprintf(fp, "%04X;%u;%s\n", pt, i, cp[pt].GetDescription()); break; } } if (i == sizeof(table)/sizeof(table[0])) { fprintf(fp, "Didn't find entry for %u\n", cc); } } } fclose(fp); } void UniData::SaveMappings() { for (int iMapping = 0; iMapping < NUM_MAPPINGS; iMapping++) { FILE *fp = fopen(MappingTypeTable[iMapping].pOutput, "w+"); if (NULL == fp) { return; } for (UTF32 pt = 0; pt <= codepoints; pt++) { if (cp[pt].IsDefined()) { int nPoints = 0; UTF32 pts[100]; GetDecomposition(pt, DECOMP_TYPE_ALL, nPoints, pts); unsigned char ch; UTF32 pt2; int cnt = 0; for (pt2 = 0; pt2 < nPoints; pt2++) { if (cp[pts[pt2]].IsMapping(MappingTypeTable[iMapping].Type, ch)) { cnt++; } } if ( 1 == cnt && cp[pts[0]].IsMapping(MappingTypeTable[iMapping].Type, ch)) { char *pUnicode1Name = cp[pt].GetUnicode1Name(); fprintf(fp, "%04X;%u;%s;%s\n", pt, ch, cp[pt].GetDescription(), (NULL == pUnicode1Name) ? "" : pUnicode1Name); } } } fclose(fp); } } void UniData::SaveTranslateToUpper(void) { FILE *fp = fopen("tr_toupper.txt", "w+"); if (NULL == fp) { return; } for (UTF32 pt = 0; pt <= codepoints; pt++) { if ( cp[pt].IsDefined() && !cp[pt].IsProhibited()) { UTF32 ptUpper = cp[pt].GetSimpleUppercaseMapping(); if ( UNI_EOF != ptUpper && cp[ptUpper].IsDefined() && !cp[ptUpper].IsProhibited()) { char *p = cp[pt].GetUnicode1Name(); fprintf(fp, "%04X;%04X;%s;%s\n", pt, ptUpper, cp[pt].GetDescription(), (NULL == p) ? "" : p); } } } fclose(fp); } void UniData::SaveTranslateToLower(void) { FILE *fp = fopen("tr_tolower.txt", "w+"); if (NULL == fp) { return; } for (UTF32 pt = 0; pt <= codepoints; pt++) { if ( cp[pt].IsDefined() && !cp[pt].IsProhibited()) { UTF32 ptLower = cp[pt].GetSimpleLowercaseMapping(); if ( UNI_EOF != ptLower && cp[ptLower].IsDefined() && !cp[ptLower].IsProhibited()) { char *p = cp[pt].GetUnicode1Name(); fprintf(fp, "%04X;%04X;%s;%s\n", pt, ptLower, cp[pt].GetDescription(), (NULL == p) ? "" : p); } } } fclose(fp); } void UniData::SaveTranslateToTitle(void) { FILE *fp = fopen("tr_totitle.txt", "w+"); if (NULL == fp) { return; } for (UTF32 pt = 0; pt <= codepoints; pt++) { if ( cp[pt].IsDefined() && !cp[pt].IsProhibited()) { UTF32 ptTitle = cp[pt].GetSimpleTitlecaseMapping(); if ( UNI_EOF != ptTitle && cp[ptTitle].IsDefined() && !cp[ptTitle].IsProhibited()) { char *p = cp[pt].GetUnicode1Name(); fprintf(fp, "%04X;%04X;%s;%s\n", pt, ptTitle, cp[pt].GetDescription(), (NULL == p) ? "" : p); } } } fclose(fp); } void UniData::SaveTranslateDecimalValue(void) { FILE *fp = fopen("tr_decimal_value.txt", "w+"); if (NULL == fp) { return; } for (UTF32 pt = 0; pt <= codepoints; pt++) { if ( cp[pt].IsDefined() && !cp[pt].IsProhibited()) { int n; if (cp[pt].GetDecimalDigitValue(&n)) { char *p = cp[pt].GetUnicode1Name(); fprintf(fp, "%04X;%u;%s;%s\n", pt, n, cp[pt].GetDescription(), (NULL == p) ? "" : p); } } } fclose(fp); } void UniData::SaveMasterFile(void) { FILE *fp = fopen("UnicodeMaster.txt", "w+"); if (NULL == fp) { return; } for (UTF32 pt = 0; pt <= codepoints; pt++) { if (cp[pt].IsDefined()) { fprintf(fp, "%04X;%s;%s;%u;%s", pt, cp[pt].GetDescription(), cp[pt].GetCategoryName(), cp[pt].GetCombiningClass(), cp[pt].GetBiDiName()); char DecompBuffer[1024]; DecompBuffer[0] = '\0'; if (cp[pt].GetDecompositionType() != DECOMP_TYPE_NONE) { strcat(DecompBuffer, "<"); strcat(DecompBuffer, cp[pt].GetDecompositionTypeName()); strcat(DecompBuffer, ">"); } UTF32 pts[30]; int nPoints = cp[pt].GetDecompositionMapping(pts); if (nPoints != 1 || pts[0] != pt) { if ('\0' != DecompBuffer[0]) { strcat(DecompBuffer, " "); } for (int i = 0; i < nPoints; i++) { if (0 != i) { strcat(DecompBuffer, " "); } char buf[12]; sprintf(buf, "%04X", pts[i]); strcat(DecompBuffer, buf); } } fprintf(fp, ";%s", DecompBuffer); int n; if (cp[pt].GetDecimalDigitValue(&n)) { fprintf(fp, ";%u", n); } else { fprintf(fp, ";"); } if (cp[pt].GetDigitValue(&n)) { fprintf(fp, ";%u", n); } else { fprintf(fp, ";"); } char *pNumericValue = NULL; if (cp[pt].GetNumericValue(&pNumericValue)) { fprintf(fp, ";%s", pNumericValue); } else { fprintf(fp, ";"); } if (cp[pt].GetBidiMirrored()) { fprintf(fp, ";Y"); } else { fprintf(fp, ";N"); } char *pUnicode1Name = cp[pt].GetUnicode1Name(); if (pUnicode1Name) { fprintf(fp, ";%s", pUnicode1Name); } else { fprintf(fp, ";"); } char *pISOComment = cp[pt].GetISOComment(); if (pISOComment) { fprintf(fp, ";%s", pISOComment); } else { fprintf(fp, ";"); } UTF32 ptUpper = cp[pt].GetSimpleUppercaseMapping(); if (UNI_EOF != ptUpper) { fprintf(fp, ";%04X", ptUpper); } else { fprintf(fp, ";"); } UTF32 ptLower = cp[pt].GetSimpleLowercaseMapping(); if (UNI_EOF != ptLower) { fprintf(fp, ";%04X", ptLower); } else { fprintf(fp, ";"); } UTF32 ptTitle = cp[pt].GetSimpleTitlecaseMapping(); if (UNI_EOF != ptTitle) { fprintf(fp, ";%04X", ptTitle); } else { fprintf(fp, ";"); } fprintf(fp, "\n"); } } fclose(fp); } void UniData::Prohibit(void) { for (UTF32 pt = 0; pt <= codepoints; pt++) { if (cp[pt].IsDefined()) { bool bShouldProhibit = false; if ( 0 != cp[pt].GetCombiningClass() || (cp[pt].GetCategory() & CATEGORY_OTHER)) { bShouldProhibit = true; } if (cp[pt].GetCategory() == (CATEGORY_OTHER|SUBCATEGORY_PRIVATE_USE)) { if ( ( 0xE000 <= pt && pt <= 0xE0FF) || ( 0xF8D0 <= pt && pt <= 0xF8FF)) { // Tengwar and Klingon // bShouldProhibit = false; } } if (bShouldProhibit) { cp[pt].SetProhibited(); } } } } void UniData::SaveClassifyPrintable(void) { FILE *fp = fopen("cl_Printable.txt", "w+"); if (NULL == fp) { return; } for (UTF32 pt = 0; pt <= codepoints; pt++) { if ( cp[pt].IsDefined() && !cp[pt].IsProhibited()) { fprintf(fp, "%04X;%s;%s;%u;%s", pt, cp[pt].GetDescription(), cp[pt].GetCategoryName(), cp[pt].GetCombiningClass(), cp[pt].GetBiDiName()); char DecompBuffer[1024]; DecompBuffer[0] = '\0'; if (cp[pt].GetDecompositionType() != DECOMP_TYPE_NONE) { strcat(DecompBuffer, "<"); strcat(DecompBuffer, cp[pt].GetDecompositionTypeName()); strcat(DecompBuffer, ">"); } UTF32 pts[30]; int nPoints = cp[pt].GetDecompositionMapping(pts); if (nPoints != 1 || pts[0] != pt) { if ('\0' != DecompBuffer[0]) { strcat(DecompBuffer, " "); } for (int i = 0; i < nPoints; i++) { if (0 != i) { strcat(DecompBuffer, " "); } char buf[12]; sprintf(buf, "%04X", pts[i]); strcat(DecompBuffer, buf); } } fprintf(fp, ";%s", DecompBuffer); int n; if (cp[pt].GetDecimalDigitValue(&n)) { fprintf(fp, ";%u", n); } else { fprintf(fp, ";"); } if (cp[pt].GetDigitValue(&n)) { fprintf(fp, ";%u", n); } else { fprintf(fp, ";"); } char *pNumericValue = NULL; if (cp[pt].GetNumericValue(&pNumericValue)) { fprintf(fp, ";%s", pNumericValue); } else { fprintf(fp, ";"); } if (cp[pt].GetBidiMirrored()) { fprintf(fp, ";Y"); } else { fprintf(fp, ";N"); } char *pUnicode1Name = cp[pt].GetUnicode1Name(); if (pUnicode1Name) { fprintf(fp, ";%s", pUnicode1Name); } else { fprintf(fp, ";"); } char *pISOComment = cp[pt].GetISOComment(); if (pISOComment) { fprintf(fp, ";%s", pISOComment); } else { fprintf(fp, ";"); } UTF32 ptUpper = cp[pt].GetSimpleUppercaseMapping(); if (UNI_EOF != ptUpper) { fprintf(fp, ";%04X", ptUpper); } else { fprintf(fp, ";"); } UTF32 ptLower = cp[pt].GetSimpleLowercaseMapping(); if (UNI_EOF != ptLower) { fprintf(fp, ";%04X", ptLower); } else { fprintf(fp, ";"); } UTF32 ptTitle = cp[pt].GetSimpleTitlecaseMapping(); if (UNI_EOF != ptTitle) { fprintf(fp, ";%04X", ptTitle); } else { fprintf(fp, ";"); } fprintf(fp, "\n"); } } fclose(fp); } void UniData::SaveClassifyPrivateUse() { FILE *fp = fopen("cl_PrivateUse.txt", "w+"); if (NULL == fp) { return; } for (UTF32 pt = 0; pt <= codepoints; pt++) { if ( cp[pt].IsDefined() && (CATEGORY_OTHER|SUBCATEGORY_PRIVATE_USE) == cp[pt].GetCategory()) { fprintf(fp, "%04X;%s\n", pt, cp[pt].GetDescription()); } } fclose(fp); } const char *CodePoint::GetCategoryName(void) { int i = 0; while (CategoryTable[i].catlet) { if (CategoryTable[i].cat == m_category) { return CategoryTable[i].catlet; } i++; } return NULL; } const char *CodePoint::GetBiDiName(void) { int i = 0; while (BiDiTable[i].BiDiLet) { if (BiDiTable[i].BiDi == m_bidi) { return BiDiTable[i].BiDiLet; } i++; } return NULL; } const char *CodePoint::GetDecompositionTypeName(void) { int i = 0; while (DecompTypeTable[i].DecompTypeLet) { if (DecompTypeTable[i].DecompType == m_DecompType) { return DecompTypeTable[i].DecompTypeLet; } i++; } return NULL; } void UniData::LoadUnicodeHanFile(void) { FILE *fp = fopen("UnicodeHan.txt", "r"); if (NULL != fp) { char buffer[1024]; while (NULL != ReadLine(fp, buffer, sizeof(buffer))) { int nFields; char *aFields[2]; ParseFields(buffer, 2, nFields, aFields); if (2 == nFields) { UTF32 pt1, pt2; char *p = strchr(aFields[0], '-'); if (NULL != p) { *p++ = '\0'; pt1 = DecodeCodePoint(aFields[0]); pt2 = DecodeCodePoint(p); } else { pt2 = DecodeCodePoint(aFields[0]); pt1 = pt2; } for (UTF32 pt = pt1; pt <= pt2; pt++) { if (cp[pt].IsDefined()) { continue; } char hex[32]; char desc[1024]; sprintf(hex, "%04X", pt); sprintf(desc, "%s CHARACTER %04X", aFields[1], pt); int nFields1 = 15; char *aFields1[15]; aFields1[0] = hex; aFields1[1] = desc; aFields1[2] = (char *)"So"; aFields1[3] = (char *)"0"; aFields1[4] = (char *)"ON"; aFields1[5] = (char *)""; aFields1[6] = (char *)""; aFields1[7] = (char *)""; aFields1[8] = (char *)""; aFields1[9] = (char *)"N"; aFields1[10] = (char *)""; aFields1[11] = (char *)""; aFields1[12] = (char *)""; aFields1[13] = (char *)""; aFields1[14] = (char *)""; LoadUnicodeDataLine(pt, nFields1, aFields1); } } } fclose(fp); } }