mkdict.c
上传用户:hmc_gdtv
上传日期:2013-08-04
资源大小:798k
文件大小:23k
源码类别:

Windows Mobile

开发平台:

Visual C++

  1. #include <windows.h>
  2. #include <stdio.h>
  3. #include <locale.h>
  4. #include <tchar.h>
  5. #include "zlib.h"
  6. #define BLOCK 65536
  7. // global stuff
  8. const TCHAR *progname;
  9. int src_codepage_num;
  10. int src_locale_num;
  11. int dest_codepage_num;
  12. UINT src_cp;
  13. LCID src_lcid;
  14. UINT dest_cp;
  15. int decode;
  16. // memory allocation
  17. void nomem(void) {
  18.   _ftprintf(stderr,_T("%s: Out of memory!n"),progname);
  19.   exit(1);
  20. }
  21. void *xmalloc(size_t size) {
  22.   void *p=malloc(size);
  23.   if (p==NULL)
  24.     nomem();
  25.   return p;
  26. }
  27. void *xrealloc(void *m,size_t size) {
  28.   void *p=realloc(m,size);
  29.   if (size>0 && p==NULL)
  30.     nomem();
  31.   return p;
  32. }
  33. TCHAR *xstrdup(const TCHAR *s) {
  34.   TCHAR *n=_tcsdup(s);
  35.   if (n==NULL)
  36.     nomem();
  37.   return n;
  38. }
  39. // error handling
  40. void  syserror(const TCHAR *msg) {
  41.   DWORD   code=GetLastError();
  42.   LPTSTR  *errmsg;
  43.   if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
  44.       NULL,code,0,(LPTSTR)&errmsg,0,NULL))
  45.     _ftprintf(stderr,_T("%s: %s: %sn"),progname,msg,errmsg);
  46.   else
  47.     _ftprintf(stderr,_T("%s: %s: %sn"),progname,msg,_T("Unknown error"));
  48.   exit(1);
  49. }
  50. void  liberr(const TCHAR *msg) {
  51.   _ftprintf(stderr,
  52. #ifdef UNICODE
  53.       _T("%s: %s: %S"),
  54. #else
  55.       _T("%s: %s: %s"),
  56. #endif
  57.       progname,msg,strerror(errno));
  58.   exit(1);
  59. }
  60. TCHAR *tchar(const char *s) {
  61. #ifdef UNICODE
  62.   int srclen=strlen(s);
  63.   int wclen;
  64.   TCHAR *ws;
  65.   if (!srclen)
  66.     return xstrdup(_T(""));
  67.   wclen=MultiByteToWideChar(CP_OEMCP,0,s,srclen,NULL,0);
  68.   if (wclen==0)
  69.     syserror(_T("Can't convert string"));
  70.   ws=xmalloc((wclen+1)*sizeof(TCHAR));
  71.   MultiByteToWideChar(CP_OEMCP,0,s,srclen,ws,wclen);
  72.   ws[wclen]='';
  73.   return ws;
  74. #else
  75.   return xstrdup(s);
  76. #endif
  77. }
  78. // custom getopt
  79. int   xgetopt(int *argc,char ***argv,const char *ospec,
  80.       const char **state,const char **arg)
  81. {
  82.   const char   *cp;
  83.   char   opt;
  84.   if (!*state || !(*state)[0]) { // look a the next arg
  85.     if (!*argc || !(*argv)[0] || (*argv)[0][0]!='-') // no more options
  86.       return 0;
  87.     if (!(*argv)[0][1]) // a lone '-', treat as an end of list
  88.       return 0;
  89.     if ((*argv)[0][1]=='-') { // '--', ignore rest of text and stop
  90.       --*argc; ++*argv;
  91.       return 0;
  92.     }
  93.     *state=(*argv)[0]+1;
  94.     --*argc;
  95.     ++*argv;
  96.   }
  97.   // we are in a middle of an arg
  98.   opt=*(*state)++;
  99.   for (cp=ospec;*cp;++cp) {
  100.     if (*cp==opt)
  101.       goto found;
  102.     if (cp[1]==':')
  103.       ++cp;
  104.   }
  105.   _ftprintf(stderr,_T("%s: Invalid option: '%c'n"),progname,opt);
  106.   exit(1);
  107. found:
  108.   if (cp[1]==':') { // option requires an argument
  109.     if (**state) { // use rest of string
  110.       *arg=*state;
  111.       *state=NULL;
  112.       return (unsigned char)opt;
  113.     }
  114.     // use next arg if available
  115.     if (*argc) {
  116.       *arg=(*argv)[0];
  117.       --*argc;
  118.       ++*argv;
  119.       return (unsigned char)opt;
  120.     }
  121.     // barf about missing args
  122.     _ftprintf(stderr,_T("%s: Option '%c' requires an argumentn"),progname,opt);
  123.     exit(1);
  124.   }
  125.   // just return current option
  126.   return (unsigned char)opt;
  127. }
  128. // hexdump
  129. void  hexdump(const wchar_t *str) {
  130.   int len=wcslen(str);
  131.   int i;
  132.   while (len>0) {
  133.     printf("  ");
  134.     for (i=0;i<8 && len>0;--i,--len,++str)
  135.       printf("%04x ",*str);
  136.     printf("n");
  137.   }
  138. }
  139. // generic arrays support
  140. void   growarray(void **arr,int itemsize,int *maxitems) {
  141.   int mi=*maxitems;
  142.   mi+=mi ? (mi>8192 ? 8192 : mi) : 32;
  143.   *arr=xrealloc(*arr,mi*itemsize);
  144.   *maxitems=mi;
  145. }
  146. #define CHECKADD(ptr,cur,max) do { 
  147. if ((cur)>=(max)) 
  148.   growarray((void **)&(ptr), 
  149.       sizeof((ptr)[0]),&(max)); 
  150.       } while (0)
  151. // languages support
  152. struct lang {
  153.   LCID   lcid;
  154.   TCHAR   *country;
  155.   TCHAR   *lang;
  156. };
  157. struct lang   *languages;
  158. int       curlang,maxlang;
  159. void addlang(LCID lcid,const TCHAR *country,const TCHAR *lang) {
  160.   CHECKADD(languages,curlang,maxlang);
  161.   languages[curlang].lcid=lcid;
  162.   languages[curlang].country=xstrdup(country);
  163.   languages[curlang].lang=xstrdup(lang);
  164.   ++curlang;
  165. }
  166. BOOL CALLBACK EnumLocalesProc(LPTSTR name) {
  167.   LCID     lcid;
  168.   TCHAR     country[1024],lang[1024];
  169.   int     ret;
  170.   if (_stscanf(name,_T("%x"),&lcid)==1) {
  171.     ret=GetLocaleInfo(lcid,LOCALE_SENGCOUNTRY,country,sizeof(country)/sizeof(TCHAR)-1);
  172.     if (ret==0)
  173.       return TRUE;
  174.     country[ret]='';
  175.     ret=GetLocaleInfo(lcid,LOCALE_SENGLANGUAGE,lang,sizeof(lang)/sizeof(TCHAR));
  176.     lang[ret]='';
  177.     addlang(lcid,country,lang);
  178.   }
  179.   return TRUE;
  180. }
  181. int   langcmp(const void *v1,const void *v2) {
  182.   const struct lang *l1=v1;
  183.   const struct lang *l2=v2;
  184.   int     val;
  185.   val=_tcsicmp(l1->lang,l2->lang);
  186.   if (val==0)
  187.     val=_tcsicmp(l1->country,l2->country);
  188.   return val;
  189. }
  190. int   langcmp_lcid(const void *v1,const void *v2) {
  191.   const struct lang *l1=v1;
  192.   const struct lang *l2=v2;
  193.   int     val;
  194.   val=_tcsicmp(l1->lang,l2->lang);
  195.   if (val==0)
  196.     val=l1->lcid<l2->lcid ? -1 : l1->lcid==l2->lcid ? 0 : 1;
  197.   return val;
  198. }
  199. #define LANGFMT1 "  %6s %-30s %-30sn"
  200. #define LANGFMT2 "  %6x %-30s %-30sn"
  201. void  showlocales(void) {
  202.   int i;
  203.   LCID deflcid;
  204.   
  205.   qsort(languages,curlang,sizeof(struct lang),langcmp);
  206.   _tprintf(_T("Installed locales:n"));
  207.   _tprintf(_T(LANGFMT1),_T("LCID"),_T("Language"),_T("Country"));
  208.   for (i=0;i<70;++i)
  209.     putc('-',stdout);
  210.   putc('n',stdout);
  211.   deflcid=GetUserDefaultLCID();
  212.   for (i=0;i<curlang;++i)
  213.     _tprintf(_T(LANGFMT2),
  214. languages[i].lcid,
  215. languages[i].lang,
  216. languages[i].country);
  217.   exit(0);
  218. }
  219. int  find_locale(const char *l) {
  220.   TCHAR   *wl=tchar(l);
  221.   LCID   id;
  222.   int   i;
  223.   TCHAR   *country;
  224.   
  225.   country=_tcschr(wl,_T('.'));
  226.   if (country)
  227.     *country++='';
  228.   for (i=0;i<curlang;++i)
  229.     if (!_tcsicmp(wl,languages[i].lang) &&
  230. (!country || !_tcsicmp(country,languages[i].country)))
  231.       goto found;
  232.   if (_stscanf(wl,_T("%x"),&id)==1)
  233.     for (i=0;i<curlang;++i)
  234.       if (languages[i].lcid==id)
  235. goto found;
  236.   _ftprintf(stderr,_T("%s: Language '%s' not found.n"),progname,wl);
  237.   exit(1);
  238. found:
  239.   free(wl);
  240.   return i;
  241. }
  242. // code pages support
  243. struct codepage {
  244.   UINT       cp;
  245.   const TCHAR *name;
  246. };
  247. struct codepage   *codepages;
  248. int   curcodepage,maxcodepage;
  249. void  addcodepage(UINT id,const TCHAR *name) {
  250.   CHECKADD(codepages,curcodepage,maxcodepage);
  251.   codepages[curcodepage].cp=id;
  252.   codepages[curcodepage].name=xstrdup(name);
  253.   ++curcodepage;
  254. }
  255. BOOL CALLBACK EnumCodePagesProc(LPTSTR name) {
  256.   UINT id;
  257.   CPINFOEX iex;
  258.   if (_stscanf(name,_T("%d"),&id)==1 && GetCPInfoEx(id,0,&iex)) {
  259.     TCHAR   *rbr,*lbr=_tcschr(iex.CodePageName,_T('('));
  260.     if (lbr) {
  261.       ++lbr;
  262.       rbr=_tcschr(lbr,_T(')'));
  263.       if (rbr)
  264. *rbr='';
  265.       else
  266. lbr=iex.CodePageName;
  267.     }
  268.     addcodepage(iex.CodePage,lbr);
  269.   }
  270.   return TRUE;
  271. }
  272. int   codepagecmp(const void *v1,const void *v2) {
  273.   const struct codepage *c1=v1;
  274.   const struct codepage *c2=v2;
  275.   return c1->cp<c2->cp ? -1 : c1->cp>c2->cp ? 1 : 0;
  276. }
  277. void  showcodepages(void) {
  278.   int i;
  279.   qsort(codepages,curcodepage,sizeof(struct codepage),codepagecmp);
  280.   _tprintf(_T("Installed code pages:n"));
  281.   for (i=0;i<curcodepage;++i)
  282.     _tprintf(_T("  %5d  %sn"),codepages[i].cp,codepages[i].name);
  283.   exit(1);
  284. }
  285. int  find_codepage(const char *cp) {
  286.   TCHAR   *wcp=tchar(cp);
  287.   UINT   ucp;
  288.   int   i;
  289.   if (sscanf(cp,"%d",&ucp)==1) { // looks like a numeric codepage
  290.     for (i=0;i<curcodepage;++i)
  291.       if (codepages[i].cp==ucp)
  292. goto found;
  293.   } else {
  294.     for (i=0;i<curcodepage;++i)
  295.       if (!_tcsicmp(wcp,codepages[i].name))
  296. goto found;
  297.   }
  298.   _ftprintf(stderr,_T("%s: Codepage '%s' not found.n"),progname,wcp);
  299.   exit(1);
  300. found:
  301.   free(wcp);
  302.   return i;
  303. }
  304. // usage
  305. void  usage(void) {
  306.   _tprintf(_T("Usage: %s [options] source destinationn")
  307.          _T("  Options:n")
  308.  _T("    -L              list available languagesn")
  309.  _T("    -C              list available code pagesn")
  310.  _T("    -l <language>   specify the language for dictionary keysn")
  311.  _T("    -c <code page>  specify source code pagen")
  312.  _T("    -o <code page>  specify output code pagen")
  313.  _T("    -d              unpack a compiled dictionaryn"),
  314.  progname
  315.       );
  316.   exit(1);
  317. }
  318. // word entry
  319. struct word {
  320.   const char   *entry; // utf8 text
  321.   int   elen; // entry length
  322.   const char   *key; // unicode sort key
  323.   int   klen; // key length
  324. };
  325. struct word   *words;
  326. int       curword,maxword;
  327. void  addword(const char *entry,int mblen,int line) {
  328.   int   wclen;
  329.   int   ulen;
  330.   wchar_t *wentry;
  331.   char   *sortkey;
  332.   char   *uentry;
  333.   int   sortkeylen;
  334.   int   i;
  335.   if (mblen==0) // ignore empty words
  336.     return;
  337.   wclen=MultiByteToWideChar(src_cp,0,entry,mblen,NULL,0);
  338.   if (wclen==0)
  339.     syserror(_T("Can't convert string to unicode"));
  340.   wentry=xmalloc((wclen+1)*sizeof(wchar_t));
  341.   MultiByteToWideChar(src_cp,0,entry,mblen,wentry,wclen);
  342.   wentry[wclen]='';
  343.   for (i=1;i<wclen-1;++i)
  344.     if (wentry[i]==' ' && wentry[i+1]==' ')
  345.       goto found;
  346.   _ftprintf(stderr,_T("%s: Invalid entry: '%s' at line %d (%d,%d)n"),progname,wentry,line,mblen,wclen);
  347.   exit(1);
  348. found:
  349.   sortkeylen=LCMapStringW(src_lcid,LCMAP_SORTKEY|NORM_IGNORECASE,
  350.       wentry,i,NULL,0);
  351.   if (sortkeylen==0)
  352.     syserror(_T("Can't get sort key"));
  353.   sortkey=xmalloc(sortkeylen);
  354.   LCMapStringW(src_lcid,LCMAP_SORTKEY|NORM_IGNORECASE,
  355.       wentry,i,(wchar_t *)sortkey,sortkeylen);
  356.   --sortkeylen; // we don't want an extra NUL byte
  357.   // replace tabs with 'n'
  358.   for (i=0;i<wclen;++i)
  359.     if (wentry[i]=='t')
  360.       wentry[i]='n';
  361.   // convert to utf8
  362.   ulen=WideCharToMultiByte(dest_cp,0,wentry,wclen,NULL,0,NULL,NULL);
  363.   if (ulen==0)
  364.     syserror(_T("Can't convert string to multibyte"));
  365.   uentry=xmalloc(ulen+1);
  366.   WideCharToMultiByte(dest_cp,0,wentry,wclen,uentry,ulen,NULL,NULL);
  367.   uentry[ulen]='';
  368.   free(wentry);
  369.   // add word
  370.   CHECKADD(words,curword,maxword);
  371.   words[curword].entry=uentry;
  372.   words[curword].elen=ulen;
  373.   words[curword].key=sortkey;
  374.   words[curword].klen=sortkeylen;
  375.   ++curword;
  376. }
  377. void  readfile(const char *filename) {
  378.   FILE   *fp;
  379.   char   inbuf[65536];
  380.   int   line=1;
  381.   _tprintf(_T("Loading... ")); fflush(stdout);
  382.   if ((fp=fopen(filename,"r"))==NULL)
  383.     liberr(_T("Can't open file"));
  384.   setvbuf(fp,NULL,_IOFBF,65536);
  385.   while (fgets(inbuf,sizeof(inbuf),fp)) {
  386.     int   len=strlen(inbuf);
  387.     while (len>0 && (inbuf[len-1]=='r' || inbuf[len-1]=='n'))
  388.       --len;
  389.     inbuf[len]='';
  390.     if (len)
  391.       addword(inbuf,len,line);
  392.     ++line;
  393.   }
  394.   fclose(fp);
  395.   _tprintf(_T("done (%d entries).n"),curword);
  396. }
  397. int   wordcmp(const void *v1,const void *v2) {
  398.   return strcmp(((const struct word *)v1)->key,((const struct word *)v2)->key);
  399. }
  400. void  sortwords(void) {
  401.   _tprintf(_T("Sorting... ")); fflush(stdout);
  402.   qsort(words,curword,sizeof(struct word),wordcmp);
  403.   _tprintf(_T("done.n"));
  404. }
  405. void  mergewords(void) {
  406.   struct word *nwords;
  407.   int nwp;
  408.   int cur,end,totlen;
  409.   char *ne,*cp;
  410.   int merged;
  411.   _tprintf(_T("Merging... ")); fflush(stdout);
  412.   nwords=xmalloc(curword*sizeof(struct word));
  413.   for (cur=nwp=merged=0;cur<curword;)
  414.     if (cur<curword-1 && !strcmp(words[cur].key,words[cur+1].key)) {
  415.       totlen=words[cur].elen+words[cur+1].elen+1;
  416.       for (end=cur+2;end<curword&&!strcmp(words[cur].key,words[end].key);++end)
  417.       {
  418. totlen+=words[end].elen;
  419. totlen++;
  420.       }
  421.       merged+=end-cur-1;
  422.       ne=xmalloc(totlen+1);
  423.       memcpy(ne,words[cur].entry,words[cur].elen);
  424.       nwords[nwp].key=words[cur].key;
  425.       nwords[nwp].klen=words[cur].klen;
  426.       nwords[nwp].elen=totlen;
  427.       nwords[nwp].entry=ne;
  428.       ++nwp;
  429.       cp=ne+words[cur].elen;
  430.       free((void*)words[cur].entry);
  431.       ++cur;
  432.       while (cur<end) {
  433. *cp++='n';
  434. memcpy(cp,words[cur].entry,words[cur].elen);
  435. cp+=words[cur].elen;
  436. free((void*)words[cur].entry);
  437. free((void*)words[cur].key);
  438. ++cur;
  439.       }
  440.       *cp='';
  441.     } else {
  442.       nwords[nwp].entry=words[cur].entry;
  443.       nwords[nwp].elen=words[cur].elen;
  444.       nwords[nwp].key=words[cur].key;
  445.       nwords[nwp].klen=words[cur].klen;
  446.       ++nwp;
  447.       ++cur;
  448.     }
  449.   free(words);
  450.   words=nwords;
  451.   maxword=curword=nwp;
  452.   _tprintf(_T("done (%d merged).n"),merged);
  453. }
  454. // blocks
  455. struct block {
  456.   int       size;
  457.   int       compressed_size;
  458.   char       *key;
  459.   int       keylen;
  460.   int       nent;
  461.   int         npara;
  462. };
  463. struct block *blocks;
  464. int curblock,maxblock;
  465. void  putblock(const char *block,int blen,int nent,FILE *fp) {
  466.   char   compressed[BLOCK];
  467.   int     res;
  468.   uLongf  dsize=sizeof(compressed);
  469.   int   docomp=0;
  470.   const char *bend;
  471.   CHECKADD(blocks,curblock,maxblock);
  472.   res=compress2((Bytef *)compressed,&dsize,(Bytef *)block,blen,9);
  473.   if (res==Z_MEM_ERROR) // don't want to compress this
  474.     fwrite(block,blen,1,fp);
  475.   else if (res==Z_OK) {
  476.     if (dsize>=(unsigned)blen) // write uncompressed
  477.       fwrite(block,blen,1,fp);
  478.     else {
  479.       docomp=1;
  480.       fwrite(compressed,dsize,1,fp);
  481.     }
  482.   } else {
  483.     _ftprintf(stderr,_T("%s: zlib error: %dn"),progname,res);
  484.     exit(1);
  485.   }
  486.   blocks[curblock].size=blen;
  487.   blocks[curblock].compressed_size=docomp ? dsize : blen;
  488.   blocks[curblock].keylen=strlen(block);
  489.   blocks[curblock].key=xmalloc(blocks[curblock].keylen+1);
  490.   memcpy(blocks[curblock].key,block,blocks[curblock].keylen+1);
  491.   blocks[curblock].nent=nent;
  492.   for (bend=block+blen;block<bend;) {
  493.     while (block<bend && *block)
  494.       ++block;
  495.     if (block<bend)
  496.       ++block;
  497.     while (block<bend && *block) {
  498.       if (*block=='n')
  499. ++nent;
  500.       ++block;
  501.     }
  502.     if (block<bend)
  503.       ++block;
  504.   }
  505.   blocks[curblock].npara=nent;
  506.   ++curblock;
  507. }
  508. void  putword(WORD w,FILE *fp) {
  509.   putc(w&0xff,fp);
  510.   putc(w>>8,fp);
  511. }
  512. void  putdword(DWORD d,FILE *fp) {
  513.   putc(d&0xff,fp);
  514.   putc((d>>8)&0xff,fp);
  515.   putc((d>>16)&0xff,fp);
  516.   putc(d>>24,fp);
  517. }
  518. DWORD  getdword(FILE *fp) {
  519.   BYTE b1,b2,b3,b4;
  520.   b1=getc(fp); b2=getc(fp); b3=getc(fp); b4=getc(fp);
  521.   return (DWORD)b4<<24|(DWORD)b3<<16|(DWORD)b2<<8|b1;
  522. }
  523. WORD  getword(FILE *fp) {
  524.   BYTE b1,b2;
  525.   b1=getc(fp); b2=getc(fp);
  526.   return (WORD)b2<<8|b1;
  527. }
  528. void  writewords(const char *filename) {
  529.   FILE   *fp;
  530.   int   i;
  531.   char   block[BLOCK];
  532.   int   blen,nent;
  533.   long   tboff,size;
  534.   _tprintf(_T("Writing... ")); fflush(stdout);
  535.   if ((fp=fopen(filename,"wb"))==NULL)
  536.     liberr(_T("Can't open file"));
  537.   setvbuf(fp,NULL,_IOFBF,65536);
  538.   // write header
  539.   fputs("DICq",fp);
  540.   putdword(src_lcid,fp); // key locale
  541.   putdword(curword,fp); // total number of entries
  542.   putdword(dest_cp,fp); // encoding
  543.   putdword(0,fp); // block table offset
  544.   // write blocks
  545.   for (i=blen=nent=0;i<curword;++i) {
  546.     if (words[i].klen+words[i].elen+2>BLOCK) {
  547.       _ftprintf(stderr,_T("%s: Entry too long.n"),progname);
  548.       exit(1);
  549.     }
  550.     if (blen+words[i].klen+1+words[i].elen+1>BLOCK) { // flush block
  551.       putblock(block,blen,nent,fp);
  552.       blen=nent=0;
  553.       if ((curblock&7)==0) {
  554. putc('.',stdout);
  555. fflush(stdout);
  556.       }
  557.     }
  558.     memcpy(block+blen,words[i].key,words[i].klen+1);
  559.     blen+=words[i].klen+1;
  560.     memcpy(block+blen,words[i].entry,words[i].elen+1);
  561.     blen+=words[i].elen+1;
  562.     ++nent;
  563.   }
  564.   if (nent>0)
  565.     putblock(block,blen,nent,fp);
  566.   tboff=ftell(fp);
  567.   // write block table
  568.   putdword(curblock,fp); // number of blocks
  569.   for (i=0;i<curblock;++i) {
  570.     putdword(blocks[i].size,fp); // uncompressed size
  571.     putdword(blocks[i].compressed_size,fp); // compressed size
  572.     putdword(blocks[i].keylen,fp); // key length
  573.     putdword(blocks[i].nent,fp); // number of words in this block
  574.     putdword(blocks[i].npara,fp); // number of "paragraphs" in this block
  575.   }
  576.   for (i=0;i<curblock;++i) // keys
  577.     fwrite(blocks[i].key,blocks[i].keylen,1,fp);
  578.   fflush(fp);
  579.   size=ftell(fp);
  580.   // write block table offset
  581.   fseek(fp,16,SEEK_SET);
  582.   putdword(tboff,fp);
  583.   fclose(fp);
  584.   _tprintf(_T(" done (%d block(s), %ld byte(s)).n"),curblock,size);
  585. }
  586. // convert string and write
  587. void  write_str(const char *s,int len,UINT srccp,UINT dstcp,FILE *fp) {
  588.   wchar_t   *wcs;
  589.   int     wclen;
  590.   char     *dcs;
  591.   int     dclen;
  592.   int     j;
  593.   if (srccp==dstcp) {
  594.     for (j=0;j<len;++j)
  595.       if (s[j]=='n')
  596. putc('t',fp);
  597.       else
  598. putc(s[j],fp);
  599.     putc('n',fp);
  600.     return;
  601.   }
  602.   if (len==0) {
  603.     putc('n',fp);
  604.     return;
  605.   }
  606.   wclen=MultiByteToWideChar(srccp,0,s,len,NULL,0);
  607.   if (wclen==0)
  608.     syserror(_T("Can't convert string"));
  609.   wcs=xmalloc(wclen*sizeof(wchar_t));
  610.   MultiByteToWideChar(srccp,0,s,len,wcs,wclen);
  611.   dclen=WideCharToMultiByte(dstcp,0,wcs,wclen,NULL,0,NULL,NULL);
  612.   if (dclen==0)
  613.     syserror(_T("Can't convert string"));
  614.   dcs=xmalloc(dclen);
  615.   WideCharToMultiByte(dstcp,0,wcs,wclen,dcs,dclen,NULL,NULL);
  616.   for (j=0;j<dclen;++j)
  617.     if (dcs[j]=='n')
  618.       dcs[j]='t';
  619.   fwrite(dcs,dclen,1,fp);
  620.   putc('n',fp);
  621.   free(wcs);
  622.   free(dcs);
  623. }
  624. // find code page names
  625. void  get_cp_name(void) {
  626.   int i;
  627.   if (src_codepage_num<0) {
  628.     CPINFOEX  iex;
  629.     if (GetCPInfoEx(src_cp,0,&iex)) {
  630.       for (i=0;i<curcodepage;++i)
  631. if (codepages[i].cp==iex.CodePage) {
  632.   src_codepage_num=i;
  633.   break;
  634. }
  635.     }
  636.   }
  637.   if (dest_codepage_num<0) {
  638.     CPINFOEX  iex;
  639.     if (GetCPInfoEx(dest_cp,0,&iex)) {
  640.       for (i=0;i<curcodepage;++i)
  641. if (codepages[i].cp==iex.CodePage) {
  642.   dest_codepage_num=i;
  643.   break;
  644. }
  645.     }
  646.   }
  647. }
  648. // find locale name
  649. void  get_locale_name(void) {
  650.   int i;
  651.   if (src_locale_num<0) {
  652.     for (i=0;i<curlang;++i)
  653.       if (src_lcid==languages[i].lcid) {
  654. src_locale_num=i;
  655. break;
  656.       }
  657.   }
  658. }
  659. // print codepage info
  660. void  print_cp_lang_info(void) {
  661.   if (src_locale_num>=0)
  662.     _tprintf(_T("Source language: %x %s.%sn"),
  663. languages[src_locale_num].lcid,languages[src_locale_num].lang,
  664. languages[src_locale_num].country);
  665.   if (src_codepage_num>=0)
  666.     _tprintf(_T("Source code page: %d %sn"),
  667. codepages[src_codepage_num].cp,codepages[src_codepage_num].name);
  668.   if (dest_codepage_num>=0)
  669.     _tprintf(_T("Output code page: %d %sn"),
  670. codepages[dest_codepage_num].cp,codepages[dest_codepage_num].name);
  671. }
  672. // decompile an existing dictionary
  673. void  decode_words(const char *ifile,const char *ofile) {
  674.   FILE   *ifp,*ofp;
  675.   char   buf[5];
  676.   int   *csizes;
  677.   int   *sizes;
  678.   long   *offs;
  679.   int   nblk;
  680.   int   totwords,nwords;
  681.   long   blocktaboff,boff;
  682.   int   i;
  683.   char   *cblk,*blk;
  684.   char   *cp,*ep,*pp;
  685.   int   mode;
  686.   if ((ifp=fopen(ifile,"rb"))==NULL)
  687.     liberr(_T("Can't open file"));
  688.   setvbuf(ifp,NULL,_IOFBF,65536);
  689.   if ((ofp=fopen(ofile,"w"))==NULL)
  690.     liberr(_T("Can't open file"));
  691.   setvbuf(ofp,NULL,_IOFBF,65536);
  692.   fread(buf,4,1,ifp);
  693.   buf[4]='';
  694.   if (strcmp(buf,"DICq")==0)
  695.     mode=0;
  696.   else if (strcmp(buf,"DICt")==0)
  697.     mode=1;
  698.   else
  699.     goto invalid;
  700.   src_lcid=getdword(ifp);
  701.   totwords=getdword(ifp);
  702.   src_cp=getdword(ifp);
  703.   if (dest_codepage_num<0)
  704.     dest_cp=src_cp;
  705.   get_cp_name();
  706.   get_locale_name();
  707.   print_cp_lang_info();
  708.   _tprintf(_T("Unpacking... ")); fflush(stdout);
  709.   blocktaboff=getdword(ifp);
  710.   fseek(ifp,blocktaboff,SEEK_SET);
  711.   nblk=getdword(ifp);
  712.   csizes=xmalloc(nblk*sizeof(int));
  713.   sizes=xmalloc(nblk*sizeof(int));
  714.   offs=xmalloc(nblk*sizeof(int));
  715.   // read block table
  716.   for (i=0,boff=20;i<nblk;++i) {
  717.     sizes[i]=getdword(ifp);
  718.     csizes[i]=getdword(ifp);
  719.     offs[i]=boff;
  720.     boff+=csizes[i];
  721.     getdword(ifp); // skip key length
  722.     getdword(ifp); // skip number of words in block
  723.     if (mode==0)
  724.       getdword(ifp); // skip number of paragraphs in block
  725.   }
  726.   // read blocks
  727.   for (i=nwords=0;i<nblk;++i) {
  728.     fseek(ifp,offs[i],SEEK_SET);
  729.     cblk=xmalloc(csizes[i]);
  730.     fread(cblk,csizes[i],1,ifp);
  731.     if (csizes[i]<sizes[i]) { // decompress
  732.       uLongf  dlen=sizes[i];
  733.       int     res;
  734.       blk=xmalloc(sizes[i]);
  735.       res=uncompress((Bytef*)blk,&dlen,(Bytef*)cblk,csizes[i]);
  736.       if (res!=Z_OK) {
  737. _ftprintf(stderr,_T("%s: zlib error: %dn"),progname,res);
  738. goto error;
  739.       }
  740.       if (dlen!=(unsigned)sizes[i])
  741. goto invalid;
  742.     } else {
  743.       blk=cblk;
  744.       cblk=NULL;
  745.     }
  746.     // write entries
  747.     for (cp=blk,ep=blk+sizes[i];cp<ep;) {
  748.       // skip key
  749.       while (cp<ep && *cp)
  750. ++cp;
  751.       if (cp<ep)
  752. pp=++cp;
  753.       // skip entry
  754.       while (cp<ep && *cp)
  755. ++cp;
  756.       if (pp!=cp)
  757. write_str(pp,cp-pp,src_cp,dest_cp,ofp);
  758.       if (cp<ep)
  759. ++cp;
  760.       ++nwords;
  761.     }
  762.     // cleanup
  763.     free(blk);
  764.     free(cblk);
  765.   }
  766.   if (nwords!=totwords)
  767.     goto invalid;
  768.   fclose(ifp);
  769.   fclose(ofp);
  770.   _tprintf(_T("done (%d entries).n"),nwords);
  771.   return;
  772. invalid:
  773.   _ftprintf(stderr,_T("%s: Invalid dictionary file.n"),progname);
  774. error:
  775.   fclose(ofp);
  776.   remove(ofile);
  777.   exit(1);
  778. }
  779. int   main(int argc,char **argv) {
  780.   char *state=NULL,*arg;
  781.   int opt;
  782.   // setup default locale
  783.   _tsetlocale(LC_ALL,_T(""));
  784.   // fetch the list of installed locales and code pages
  785.   EnumSystemLocales(EnumLocalesProc,LCID_INSTALLED|LCID_ALTERNATE_SORTS);
  786.   EnumSystemCodePages(EnumCodePagesProc,CP_INSTALLED);
  787.   qsort(languages,curlang,sizeof(struct lang),langcmp_lcid);
  788.   // set program name
  789.   if (argc>0)
  790.     progname=tchar(argv[0]);
  791.   if (progname==NULL)
  792.     progname=_T("mkdict");
  793.   // setup defaults
  794.   src_locale_num=-1;
  795.   src_lcid=GetUserDefaultLCID();
  796.   src_codepage_num=-1;
  797.   dest_codepage_num=-1;
  798.   src_cp=CP_OEMCP;
  799.   dest_cp=CP_UTF8;
  800.   // process options
  801.   if (argc<2)
  802.     usage();
  803.   --argc; ++argv; // skip program name
  804.   while ((opt=xgetopt(&argc,&argv,"LCl:c:o:d",&state,&arg)))
  805.     switch (opt) {
  806.       case 'L':
  807. showlocales();
  808. break;
  809.       case 'C':
  810. showcodepages();
  811. break;
  812.       case 'c':
  813. src_codepage_num=find_codepage(arg);
  814. src_cp=codepages[src_codepage_num].cp;
  815. if (dest_codepage_num<0) { // also set output cp
  816.   dest_codepage_num=src_codepage_num;
  817.   dest_cp=src_cp;
  818. }
  819. break;
  820.       case 'l':
  821. src_locale_num=find_locale(arg);
  822. src_lcid=languages[src_locale_num].lcid;
  823. break;
  824.       case 'o':
  825. dest_codepage_num=find_codepage(arg);
  826. dest_cp=codepages[dest_codepage_num].cp;
  827. break;
  828.       case 'd':
  829. decode=1;
  830. break;
  831.     }
  832.   if (argc<2) // at least source and destination files is required
  833.     usage();
  834.   // try to find locale and code page ids
  835.   // print locale and code page info
  836.   // do the work
  837.   if (decode) {
  838.     decode_words(argv[0],argv[1]);
  839.   } else {
  840.     get_locale_name();
  841.     get_cp_name();
  842.     print_cp_lang_info();
  843.     readfile(argv[0]);
  844.     sortwords();
  845.     mergewords();
  846.     writewords(argv[1]);
  847.   }
  848.   return 0;
  849. }