/* vi: set sw=4 ts=4: */ #include #include #include #include #include #include "defs.h" #include "convert.h" #include "hzinput.h" #include "pinyin.h" #include "zhuyin.h" #include "cin2tab.h" #define MAX_LEN2PHRASE_NUM 512 /* max 65535 16 bits, actually only ~300 */ #define MAX_PHRASE_NUM 255 #define MAX_PHRASE_LEN 32 #define FREQ_UNKNOWN 0xFFFF static int zinum; /* total zi number */ static Zi *ZiTable; /* Big5 space */ static Yin yin_table[TOTAL_ZHUYIN_NUM]; static u_short NumZi[TOTAL_ZHUYIN_NUM][MAX_TONE_NUM]; static u_short YinZiMap[TOTAL_ZHUYIN_NUM][MAX_TONE_NUM][150]; static int maxyinchar = 0, maxyinyin = 0; static int file_size = 0; typedef struct { int PhraseNum[MAX_ZYPHRASE_LEN]; /* 2,3/4,5 */ u_char *PhrasePtr[MAX_ZYPHRASE_LEN]; }Ci; static Ci *CiAry; /* Big5 space for phrases */ static int CiStat[MAX_ZYPHRASE_LEN+1], TotalCi, MaxCiNum; /* how many cis */ static int MinCiIndex = 0xffff, MaxCiIndex = -1; static void AddToYinZiMapTable(unsigned short yin, unsigned short zi) { int i, j; int index = yin & 0x07FF; /* 11 bits */ for(i = 0; i < 5; i++) { if ((1 << (TONE_OFFSET + i)) & yin) /* valid tone */ { for(j = 0; j < NumZi[index][i]; j++) if (YinZiMap[index][i][j] == zi) return; /* ignore it */ YinZiMap[index][i][ NumZi[index][i]++ ] = zi; if (NumZi[index][i] > maxyinchar) { maxyinchar = NumZi[index][i]; maxyinyin = index | ( 1<< (TONE_OFFSET + i)); } } } } static int AddOneYin(u_short from_yin, u_short to_yin[], int numyin) { int i; for(i = 0; i < numyin && to_yin[i] ; i++) { if ((to_yin[i] & 0x07FF) == (from_yin & 0x07FF)) { /* same yin different tones */ to_yin[i] |= from_yin; return 0; /* done */ } } if (i >= numyin) return -1; /* no space */ to_yin[i] = from_yin; return 0; } static int ConvertOneYinToZhuyin(int format, unsigned char *buf, u_short yin[MAX_ZHUYIN_NUMBER]) { unsigned char key[10]; ZYString zhuyin[1]; unsigned short y[1]; unsigned short mask[1]; memset(zhuyin, 0, sizeof(zhuyin)); if (format == ZHUYIN_FORMAT) { if ( ConvertZhuyinStrToKeys(buf, key) <= 0 ) /* failure */ return 0; if (ParseZhuyinKeys(KEYBOARD_MAP_ZOZY, key, zhuyin, y, mask, 1) != 1) { return 0; } } else if (format == PINYIN_FORMAT) { u_char pystr[1][MAX_PY_LEN+3]; buf = skip_space(buf); if (ConvertPinyinKeysToZhuyin(KEYBOARD_MAP_PINYIN, buf, zhuyin, y, mask, pystr, NULL, 1) != 1) { return 0; } } else return 0; /* unknown format */ AddOneYin(y[0], yin, MAX_ZHUYIN_NUMBER); return y[0]; } static int ConvertMultiYinToZhuyin(int format, unsigned char *buf, u_short yin[MAX_ZHUYIN_NUMBER]) { int total = 0; int n; u_char *p; p = buf; while(*p) { n = ConvertOneYinToZhuyin(format, p, yin); if (n == 0) /* 0 for failure */ return 0; total++; while (*p && *p != ',') p++; if (*p == ',') p++; } return total; } int convert_to_zhuyins(int format, u_char *p, u_short yin[][MAX_ZHUYIN_NUMBER], int len) { int yincount = 0, ret; u_char *m1, *m2; while(*p && *p != '\r' && *p != '\n' && *p != '#') { p = skip_space(p); /* skip space */ if (*p == '\r' || *p == '\n' || *p == '#') break; if (*p == '[') /* multiyin */ { m1 = ++p; while(*p && *p != ']') p++; if (*p == ']') *p++ = '\0'; ret = ConvertMultiYinToZhuyin(format, m1, yin[yincount % len]); if (ret == 0) { fprintf(stderr, "Error MultiYin Yin=%s\n", m1); return yincount; } } else /* single yin */ { m2 = p; while(*p && *p != ' ' && *p != '#' && *p != '\t' && *p != '\r' && *p != '\n') p++; if (*p) *p++ = '\0'; ret = ConvertOneYinToZhuyin(format, m2, yin[yincount % len]); if (ret == 0) { fprintf(stderr, "Error SingleYin Yin=%s\n", m2); return yincount; } } yincount++; } return yincount; } #define MAXNUM(len) (len == 2? MAX_LEN2PHRASE_NUM : MAX_PHRASE_NUM) #define PHR_SIZE(num, len) ( (num) * (2 * (len-1) + sizeof(ZYFREQTYPE)) ) static void AddToCiAry(u_char *c, int len, int freq) { int j, index; u_char *p; /*, tmpbuf[3]; */ u_int phr_size; index = CalculateCharIndex(NewCoding, c[0], c[1]); if (CiAry[index].PhrasePtr[len-1] == NULL) /* have not allocated memory yet */ { phr_size = PHR_SIZE(/* MAXNUM(len) */ MAX_PHRASE_NUM, len); CiAry[index].PhrasePtr[len-1] = (u_char *)malloc(phr_size); if (CiAry[index].PhrasePtr[len-1] == NULL) { fprintf(stderr, "Failed to allocate %d bytes! (len=%d)\n", phr_size, len); return; } memset(CiAry[index].PhrasePtr[len-1], 0, phr_size); } p = CiAry[index].PhrasePtr[len-1]; for(j = 0; j < CiAry[index].PhraseNum[len-1]; j++) { if (strncmp(c+2, p, 2*(len-1)) == 0) break; p += 2*(len-1) + sizeof(ZYFREQTYPE); /* also skip freq */ } if (j < CiAry[index].PhraseNum[len-1]) /* */ { #ifdef DEBUG fprintf(stderr, "Duplicate phrase %s found, ignored.\n", c); #endif return; } if (len == 2 && CiAry[index].PhraseNum[len-1] == MAX_PHRASE_NUM) /* realloc */ { u_char *tmpp = CiAry[index].PhrasePtr[len-1]; int tmpoff = (u_int)p - (u_int)tmpp; phr_size = PHR_SIZE(MAX_LEN2PHRASE_NUM, len); CiAry[index].PhrasePtr[len-1] = realloc(tmpp,phr_size); if (CiAry[index].PhrasePtr[len-1] == NULL) { fprintf(stderr, "Failed to allocate %d bytes.\n", phr_size); return; } p = CiAry[index].PhrasePtr[len-1]+tmpoff; } CiAry[index].PhraseNum[len-1]++; if (CiAry[index].PhraseNum[len-1] > MaxCiNum) MaxCiNum = CiAry[index].PhraseNum[len-1]; if (CiAry[index].PhraseNum[len-1] >= MAXNUM(len) ) { if (CiAry[index].PhraseNum[len-1] == MAXNUM(len) ) { fprintf(stderr, "Only max %d phrase supported per char/length(Char=%c%c len=%d)\n", MAX_PHRASE_NUM, c[0], c[1], /*tmpbuf[0], tmpbuf[1],*/ len); } return; } strncpy(p, c+2, (len-1)*2); /* save it */ p += 2*(len-1); *((ZYFREQTYPE *)p) = (ZYFREQTYPE)freq; if (index < MinCiIndex) MinCiIndex = index; if (index > MaxCiIndex) MaxCiIndex = index; CiStat[len-1]++; TotalCi++; } static int LoadCharPhraseFromFile(FILE *fp) { int i; unsigned char *p, *c; int len, freq, yincount, index; unsigned short zhi, yin[MAX_PHRASE_LEN][MAX_ZHUYIN_NUMBER]; YinFormat = ZHUYIN_FORMAT; /* default */ while ( !feof( fp )) { if ( fgets(LineBuf,LINE_BUFFER_LEN,fp) == NULL) continue; p = FilterFormatCharFreq(LineBuf, /*ZIYINMAP_STR*/SYSPH_MAP_STR, &c, &len, &freq, 2); if (p == NULL || len <= 0) continue; else if (p == (u_char *)-1) break; /* end */ if (len == 1) /* single-char: add to ZiTable */ { if (!*p) { fprintf(stderr, "ERROR %c%c no freq or yin information! \n", c[0], c[1]); continue; } memset(yin, 0, sizeof(yin)); yincount = convert_to_zhuyins(YinFormat, p, yin, len); if (yincount < 1) fprintf(stderr, "Single Char %c%c has no yin information!\n", c[0], c[1]); zhi = ((unsigned short)c[0]) << 8 | c[1]; index = CalculateCharIndex(NewCoding, c[0], c[1]); ZiTable[index].freq = freq; for(i = 0; yin[0][i]; i++) { AddOneYin(yin[0][i], ZiTable[index].yin, MAX_YIN_NUM); AddToYinZiMapTable(yin[0][i], zhi); } } else /* phrase: add to CiAry */ { AddToCiAry(c, len, freq); } } return 0; } static int SaveYinTable(FILE *fout, FILE *fmonitor) { int i, j; int offset = 0, pad = 0; for(i = 0; i < TOTAL_ZHUYIN_NUM; i++) { yin_table[i].offset = offset; for(j = 0; j < MAX_TONE_NUM; j++) { yin_table[i].ZiNum[j] = NumZi[i][j]; offset += NumZi[i][j]; } } fwrite(yin_table, sizeof(yin_table), 1, fout); if (offset % 2) { offset++; pad = 1; } offset *= sizeof(unsigned short); /* conver to bytes */ fwrite( &offset, sizeof(int), 1, fout); /* how many bytes */ #ifdef DEBUG fprintf(stderr, "ZiLibSize=%d\n", offset); #endif for(i = 0; i < TOTAL_ZHUYIN_NUM; i++) { for(j = 0; j < MAX_TONE_NUM; j++) { if (NumZi[i][j] == 0) continue; fwrite( &YinZiMap[i][j], sizeof(unsigned short), NumZi[i][j], fout); if (fmonitor) { int k; for(k = 0; k < NumZi[i][j]; k++) fprintf(fmonitor, "%c%c", YinZiMap[i][j][k] >> 8, YinZiMap[i][j][k] & 0xFF); fprintf(fmonitor, "\n"); } } } if (pad) /* pad two bytes */ fwrite(&offset, sizeof(unsigned short), 1, fout); file_size += offset + sizeof(yin_table) + 4; /* including the yin_table and ZiLib */ return 0; } static int SaveZiCiTable(FILE *fout, FILE *fmonitor) { int i, j; int offset = 0, pad = 0; fwrite(&zinum, sizeof(int), 1, fout); /* zi_num */ for(i = 0; i < zinum; i++) { ZiTable[i].offset = offset; ZiTable[i].phnum.PhraseNum1 = CiAry[i].PhraseNum[1]; /* two bytes for 1 */ offset += CiAry[i].PhraseNum[1] * (2 + sizeof(ZYFREQTYPE)); for(j = 2; j < MAX_ZYPHRASE_LEN; j++) { ZiTable[i].phnum.PhraseNum[j] = CiAry[i].PhraseNum[j]; offset += CiAry[i].PhraseNum[j] * (j * 2 + sizeof(ZYFREQTYPE)); } fwrite(&ZiTable[i], sizeof(ZiTable[0]), 1, fout); } pad = offset % 4 ? 4 - (offset % 4) : 0; offset += pad; fwrite( &offset, sizeof(int), 1, fout); /* how many bytes */ for(i = 0; i < zinum; i++) { for(j = 0; j < MAX_ZYPHRASE_LEN; j++) { if (CiAry[i].PhraseNum[j] == 0 || !CiAry[i].PhrasePtr[j]) continue; fwrite(CiAry[i].PhrasePtr[j], (2*j + sizeof(ZYFREQTYPE))*CiAry[i].PhraseNum[j], 1, fout); if (fmonitor) { fprintf(fmonitor, "%s\n", CiAry[i].PhrasePtr[j]); } } } if (pad) fwrite(&offset, 1, pad, fout); file_size += 8 + offset + sizeof(ZiTable[0]) * zinum; #ifdef DEBUG fprintf(stderr, "ZiNum=%d CiLibSize=%d TotalCi=%d, MinCiIndex=%d MaxCiIndex=%d MaxCiNum=%d\n", zinum, offset, TotalCi, MinCiIndex, MaxCiIndex, MaxCiNum); fprintf(stderr, "Ci Statistics:\n"); CiStat[0] = zinum; for(i = 0; i <= MAX_ZYPHRASE_LEN; i++) { fprintf(stderr, "Ci Len=%d Num=%d\n", i+1, CiStat[i]); } #endif return 0; } int ConvertZhuyinCIN(FILE *fr, hz_input_table *table, char *filename ) { FILE *fw; /* , *fp; */ if ((fw=fopen(filename,"w"))==NULL) { fprintf(stderr, "Failed to create output file!\n"); return -1; } OldCoding = NewCoding = table->encoding; zinum = GetEncodingSpace(NewCoding); fprintf(stderr, "EncodingSpace=%d\n", zinum); ZiTable = (Zi *)malloc(zinum * sizeof(Zi)); CiAry = (Ci *)malloc(zinum * sizeof(Ci)); if (ZiTable == NULL || CiAry == NULL) { fprintf(stderr, "Out of memory allocating Zi/Ci array!\n"); return -1; } memset(ZiTable, 0, zinum * sizeof(Zi)); memset(CiAry, 0, zinum * sizeof(Ci)); fwrite(table,sizeof(*table),1, fw); file_size += sizeof(*table); if ( LoadFileSection(cmd, arg, /*ZIYINMAP_STR*/SYSPH_MAP_STR, fr, LoadCharPhraseFromFile)) print_error("%" /*ZIYINMAP_STR*/ SYSPH_MAP_STR " [ | begin ] expected!"); do { cmd_arg(fr, LineBuf, &cmd, &arg); } while ( LoadFileSection(cmd, arg, SYSPH_MAP_STR, fr, LoadCharPhraseFromFile) == 0); fclose(fr); SaveYinTable(fw, NULL); /* save the yin->zi map, will update file_size */ SaveZiCiTable(fw, NULL); /* stdout); // save zi->yin map, will update file_size */ file_size += 4; /* itself */ fwrite(&file_size, sizeof(int), 1, fw); fprintf(stderr, "%s:\tFileSize=%d ZiNum=%d TotalCiNum=%d MaxCiNum=%d\n", filename, file_size, zinum, TotalCi, MaxCiNum); fclose(fw); return 0; }