[gs-code-review] CJK TrueType mappings and aliases for Windows
installer
Russell Lang
gsview at ghostgum.com.au
Fri Oct 22 02:27:15 PDT 2004
This is applicable to 8.15 and HEAD.
Log Message:
Change MS-Windows installer to update lib/cidfmap with
the CJK fonts found in the Windows font directory.
DETAILS:
Ghostscript does not ship with CJK fonts.
If support for Chinese, Japanese or Korean is added to MS-Windows,
CJK TrueType fonts and font collections are added to the MS-Windows
fonts directory. These can be used by ghostscript by specifying
mapping and aliases in the lib/cidfmap file.
This patch looks in the MS-Windows fonts directory for known
CJK fonts, and if present it appends appropriate mappings or
aliases to the lib/cidfmap file.
The font names and aliases are currently fixed.
At present aliases are disabled due to bug #687776.
Russell Lang gsview at ghostgum.com.au
Ghostgum Software Pty Ltd http://www.ghostgum.com.au/
-------------- next part --------------
diff -u l:/cvs/gs/src/dwsetup.cpp src/dwsetup.cpp
--- l:/cvs/gs/src/dwsetup.cpp Sat Apr 12 22:04:21 2003
+++ src/dwsetup.cpp Wed Oct 06 08:45:51 2004
@@ -139,6 +139,7 @@
BOOL install_prog();
BOOL install_fonts();
BOOL make_filelist(int argc, char *argv[]);
+BOOL write_cidfmap(const char *path);
//////////////////////////////////////////////////////////////////////
@@ -694,6 +695,7 @@
char szArguments[MAXSTR];
char szDescription[MAXSTR];
char szDotVersion[MAXSTR];
+ char szCIDFmap[MAXSTR];
if (g_bQuit)
return FALSE;
@@ -726,6 +728,21 @@
if (g_bQuit)
return FALSE;
+
+ /* Create lib/cidfmap */
+ gs_addmess("Updating cidfmap\n ");
+ strcpy(szCIDFmap, g_szTargetDir);
+ strcat(szCIDFmap, "\\");
+ strcat(szCIDFmap, cinst.GetMainDir());
+ strcat(szCIDFmap, "\\lib\\cidfmap");
+ gs_addmess(szCIDFmap);
+ gs_addmess("\n");
+ if (!write_cidfmap(szCIDFmap)) {
+ gs_addmess("Failed to update \042");
+ gs_addmess(szCIDFmap);
+ gs_addmess("\042\n");
+ return FALSE;
+ }
// write registry entries
gs_addmess("Updating Registry\n");
@@ -871,6 +888,465 @@
return TRUE;
}
+//////////////////////////////////////////////////////////////////////
+// File and directory enumeration
+//////////////////////////////////////////////////////////////////////
+
+typedef struct enum_file_s {
+ HANDLE find_handle;
+ WIN32_FIND_DATA find_data;
+ char name[256];
+ char base[256];
+} enum_file_t;
+
+/* Prepare to enumerate files */
+/* name should include a wildcard if you want to find more than one file */
+enum_file_t *
+enum_file_init(const char *name)
+{
+ char *p;
+ int i;
+ int baselen;
+ int len;
+ enum_file_t *pfe = (enum_file_t *)malloc(sizeof(enum_file_t));
+ if (pfe != NULL) {
+ memset(pfe, 0, sizeof(pfe));
+ strncpy(pfe->name, name, sizeof(pfe->name)-1);
+ pfe->find_handle = INVALID_HANDLE_VALUE;
+ len = strlen(pfe->name);
+ baselen = 0;
+ for (i = 0; i < len; i++) {
+ if (pfe->name[i] == '\\')
+ pfe->name[i] = '/';
+ if ((pfe->name[i] == '/') || (pfe->name[i] == ':'))
+ baselen = i+1;
+ }
+ memcpy(pfe->base, pfe->name, baselen);
+ pfe->base[baselen] = '\0';
+ }
+ return pfe;
+}
+
+/* Return name of next file. *dir is set non-zero if a directory */
+int
+enum_file_next(enum_file_t *pfe, char *buf, unsigned int buflen, int *dir)
+{
+ BOOL found = FALSE;
+ char *p;
+ if (pfe->find_handle == INVALID_HANDLE_VALUE) {
+ pfe->find_handle = FindFirstFile(pfe->name, &pfe->find_data);
+ if (pfe->find_handle == INVALID_HANDLE_VALUE)
+ found = TRUE;
+ }
+ else
+ found = FindNextFile(pfe->find_handle, &pfe->find_data);
+ if (found) {
+ strncpy(buf, pfe->base, buflen-1);
+ strncat(buf, pfe->find_data.cFileName, strlen(buf)-buflen-1);
+ *dir = pfe->find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+ for (p=buf; *p; p++)
+ if (*p == '\\')
+ *p = '/';
+ }
+ if ((strcmp(pfe->find_data.cFileName, ".") == 0) ||
+ (strcmp(pfe->find_data.cFileName, "..") == 0))
+ found = enum_file_next(pfe, buf, buflen, dir); /* have another go */
+ return found;
+}
+
+void
+enum_file_close(enum_file_t *pfe)
+{
+ FindClose(pfe->find_handle);
+ free(pfe);
+}
+
+//////////////////////////////////////////////////////////////////////
+// Create lib/cidfmap based on installed fonts
+//////////////////////////////////////////////////////////////////////
+
+
+typedef enum font_order_e {
+ JAPAN1 = 0,
+ KOREA1 = 1,
+ GB1 = 2,
+ CNS1 = 3
+} font_order;
+
+const char *order_string[4] = {
+ "Japan1",
+ "Korea1",
+ "GB1",
+ "CNS1"
+};
+
+typedef struct cjk_font_s {
+ const char *name;
+ int subfontid;
+ font_order order;
+ int supplement;
+ const char *fontname;
+} cjk_font_t;
+
+typedef struct font_alias_s {
+ const char *substituted;
+ const char *original;
+} font_alias_t;
+
+typedef struct font_list_s font_list_t;
+struct font_list_s {
+ int cjk_index;
+ char *fontname;
+ font_list_t *next;
+};
+
+typedef struct alias_list_s alias_list_t;
+struct alias_list_s {
+ const char *fontname;
+ font_list_t *font;
+ alias_list_t *next;
+};
+
+
+/* The real fonts */
+/* serif = light font */
+/* gothic = san serif = heavy font */
+cjk_font_t cjk_fonts[] = {
+{"MS-Mincho", 1, JAPAN1, 3, "msmincho.ttc"}, /* Japanese serif */
+{"MS-PMincho", 2, JAPAN1, 3, "msmincho.ttc"}, /* Japanese serif */
+{"MS-Gothic", 1, JAPAN1, 3, "msgothic.ttc"}, /* Japanese gothic */
+{"MS-PGothic", 2, JAPAN1, 3, "msgothic.ttc"}, /* Japanese gothic */
+{"MS-UI-Gothic", 3, JAPAN1, 3, "msgothic.ttc"}, /* Japanese gothic */
+
+{"MingLiu", 1, CNS1, 2, "mingliu.ttc"}, /* Traditional Chinese serif */
+{"PMingLiu", 2, CNS1, 2, "mingliu.ttc"}, /* Traditional Chinese serif */
+{"Arial-Unicode-MS", 1, CNS1, 2, "arialuni.ttc"},/*Traditional Chinese gothic*/
+
+{"SimSun", 1, GB1, 2, "simsun.ttc"}, /* Simplified Chinese serif */
+{"NSimSun", 2, GB1, 2, "simsun.ttc"}, /* Simplified Chinese serif */
+{"SimHei", 0, GB1, 2, "simhei.ttf"}, /* Simplified Chinese gothic */
+
+{"Batang", 1, KOREA1, 3, "batang.ttc"}, /* Korean serif */
+{"BatangChe", 2, KOREA1, 3, "batang.ttc"}, /* Korean serif */
+{"Gungsuh", 3, KOREA1, 3, "batang.ttc"}, /* Korean serif */
+{"GungsuhChe", 4, KOREA1, 3, "batang.ttc"}, /* Korean serif */
+{"Gulim", 1, KOREA1, 3, "gulim.ttc"}, /* Korean gothic */
+{"GulimChe", 2, KOREA1, 3, "gulim.ttc"}, /* Korean gothic */
+{"Dotum", 3, KOREA1, 3, "gulim.ttc"}, /* Korean gothic */
+{"DotumChe", 4, KOREA1, 3, "gulim.ttc"} /* Korean gothic */
+};
+
+/* The aliases.
+ * Note that we can list multiple substitutions.
+ * The first substitution that matches a found original font will be used.
+ */
+font_alias_t font_aliases[] = {
+ /* Japanese */
+ {"Ryumin-Light", "MS-Mincho"},
+ {"GothicBBB-Medium", "MS-Gothic"},
+ {"HeiseiMi-W3", "MS-Mincho"},
+ {"HeiseiKakuGo", "MS-Gothic"},
+
+ /* Traditional Chinese (CNS1) */
+/* Sung, Hei and Kai are different styles */
+ {"MSung-Light", "MingLiu"},
+ {"MSung-Medium", "MingLiu"},
+ {"MHei-Medium", "MingLiu"},
+ {"MKai-Medium", "Arial-Unicode-MS"},
+ {"MKai-Medium", "MingLiu"},
+
+ /* Simplified Chinese (GB1) */
+ {"STSong-Light", "SimSun"},
+ {"STFangsong-Light", "SimSun"},
+ {"STHeiti-Regular", "SimHei"},
+ {"STKaiti-Regular", "SimHei"},
+
+ /* Korean */
+ {"HYSMyeongJo-Medium", "Batang"},
+ {"HYRGoThic-Medium", "Gulim"},
+ {"HYGoThic-Medium", "Dotum"}
+};
+
+
+/* Get the path to enumerate for fonts */
+int
+get_font_path(char *path, unsigned int pathlen)
+{
+ int i;
+ int len = GetWindowsDirectory(path, pathlen);
+ if (len == 0)
+ return -1;
+ if (pathlen - strlen(path) < 10)
+ return -1;
+ strncat(path, "/fonts/*", pathlen - strlen(path) - 9);
+ for (i = strlen(path)-1; i >= 0; i--)
+ if (path[i] == '\\')
+ path[i] = '/';
+ return len;
+}
+
+/* Get the name of the cidfmap used by ghostscript */
+/* This implementation assumes that this program is
+ * .../bin/wincid.exe and that we should write .../lib/cidfmap
+ */
+int
+get_cid_path(char *path, unsigned int pathlen)
+{
+ int i;
+ char *p;
+ char *basepath;
+ char *basename;
+ int len = GetModuleFileName(NULL, path, pathlen);
+ if (len == 0)
+ return -1;
+ if (pathlen - strlen(path) < 10)
+ return -1;
+ for (i = strlen(path)-1; i >= 0; i--)
+ if (path[i] == '\\')
+ path[i] = '/';
+ /* find last '// */
+ basepath = basename = path;
+ for (p = path; *p; p++) {
+ if (*p == '/') {
+ basepath = basename;
+ basename = p+1;
+ }
+ }
+ /* append lib/cidfname */
+ *basepath = '\0';
+ if (pathlen - strlen(path) < 12)
+ return -1;
+ strncat(path, "lib/cidfmap", pathlen - strlen(path) - 12);
+ return len;
+}
+
+
+int
+find_font_files(font_list_t **fflist, const char *path)
+{
+ enum_file_t *pfe;
+ char fname[256];
+ char *p;
+ char *basename;
+ int i;
+ int len;
+ int code = 0;
+ font_list_t *flistp = *fflist;
+ int isdir;
+ while (flistp && flistp->next)
+ flistp = flistp->next;
+
+ memset(fname, 0, sizeof(fname));
+ pfe = enum_file_init(path);
+ if (pfe == NULL)
+ return -1;
+ while (enum_file_next(pfe, fname, sizeof(fname)-1, &isdir)) {
+ len = strlen(fname);
+ basename = fname;
+ for (p = fname; *p; p++)
+ if (*p == '/')
+ basename = p+1;
+ /* Check to see if known font */
+ for (i = 0; i < sizeof(cjk_fonts) / sizeof(cjk_fonts[0]); i++) {
+ if (stricmp(cjk_fonts[i].fontname, basename) == 0) {
+ if (flistp == NULL)
+ *fflist = flistp = (font_list_t *)
+ malloc(sizeof(font_list_t));
+ else {
+ flistp->next = (font_list_t *)
+ malloc(sizeof(font_list_t));
+ flistp = flistp->next;
+ }
+ if (flistp == NULL) {
+ code = -1;
+ break;
+ }
+ flistp->next = NULL;
+ flistp->cjk_index = i;
+ flistp->fontname = (char *)malloc(len+1);
+ if (flistp->fontname == 0) {
+ code = -1;
+ break;
+ }
+ memcpy(flistp->fontname, fname, len+1);
+ }
+ }
+ }
+ enum_file_close(pfe);
+ return code;
+}
+
+/* Return 1 if alias already known, 0 if not found */
+int find_alias(alias_list_t *falist, const char *name)
+{
+ alias_list_t *alistp = falist;
+ while (alistp) {
+ if (strcmp(alistp->fontname, name) == 0)
+ return 1;
+ alistp = alistp->next;
+ }
+ return 0;
+}
+
+font_list_t *
+find_font(font_list_t *fflist, const char *name)
+{
+ font_list_t *flistp = fflist;
+ while (flistp) {
+ if (strcmp(cjk_fonts[flistp->cjk_index].name, name) == 0)
+ return flistp;
+ flistp = flistp->next;
+ }
+ return NULL;
+}
+
+int
+build_font_aliases(alias_list_t **falist, font_list_t *fflist)
+{
+ font_list_t *flistp = fflist;
+ alias_list_t *alistp = *falist;
+ int i;
+ int code = 0;
+ if (flistp == NULL)
+ return 0;
+
+ while (alistp && alistp->next)
+ alistp = alistp->next;
+
+ /* Add the substitutions */
+ for (i=0; i<sizeof(font_aliases)/sizeof(font_aliases[0]); i++) {
+ if ( !find_alias(*falist, font_aliases[i].substituted) &&
+ !find_font(fflist, font_aliases[i].substituted) &&
+ ((flistp = find_font(fflist, font_aliases[i].original))
+ != NULL) ) {
+ if (alistp == NULL)
+ *falist = alistp = (alias_list_t *)malloc(sizeof(alias_list_t));
+ else {
+ alistp->next = (alias_list_t *) malloc(sizeof(alias_list_t));
+ alistp = alistp->next;
+ }
+ if (alistp == NULL) {
+ code = -1;
+ break;
+ }
+ alistp->next = NULL;
+ alistp->fontname = font_aliases[i].substituted;
+ alistp->font = flistp;
+ }
+ }
+ return code;
+}
+
+void
+write_cidfmap_fonts(FILE *f, font_list_t *fflist)
+{
+ font_list_t *listp;
+ cjk_font_t *cjk;
+ for (listp = fflist; listp; listp = listp->next) {
+ cjk = &cjk_fonts[listp->cjk_index];
+ fprintf(f, "/%s\n", cjk->name);
+ fprintf(f, "<<\n");
+ fprintf(f, " /FileType /TrueType\n");
+ fprintf(f, " /Path (%s)\n", listp->fontname);;
+ fprintf(f, " /SubfontID %d\n", cjk->subfontid);
+ fprintf(f, " /CSI [(%s) %d]\n", order_string[cjk->order],
+ cjk->supplement);
+ fprintf(f, ">> ;\n\n");
+ }
+}
+
+void
+write_cidfmap_aliases(FILE *f, alias_list_t *falist)
+{
+ alias_list_t *listp;
+ cjk_font_t *cjk;
+ for (listp = falist; listp; listp = listp->next) {
+ cjk = &cjk_fonts[listp->font->cjk_index];
+#ifdef USE_ALIASES
+ /* These don't work in GS 8.32 or earlier */
+ fprintf(f, "/%s /%s ;\n", listp->fontname, cjk->name);
+#else
+ fprintf(f, "/%s\n", listp->fontname);
+ fprintf(f, "<<\n");
+ fprintf(f, " /FileType /TrueType\n");
+ fprintf(f, " /Path (%s)\n", listp->font->fontname);;
+ fprintf(f, " /SubfontID %d\n", cjk->subfontid);
+ fprintf(f, " /CSI [(%s) %d]\n", order_string[cjk->order],
+ cjk->supplement);
+ fprintf(f, ">> ;\n\n");
+#endif
+ }
+}
+
+void
+cleanup(font_list_t *fflist, alias_list_t *falist)
+{
+ alias_list_t *ap, *apnext;
+ font_list_t *fp, *fpnext;
+
+ ap = falist;
+ while (ap) {
+ apnext = ap->next;
+ free(ap);
+ ap = apnext;
+ }
+
+ fp = fflist;
+ while (fp) {
+ fpnext = fp->next;
+ free(fp->fontname);
+ free(fp);
+ fp = fpnext;
+ }
+}
+
+int
+build_cidfmap(font_list_t **ffhead, alias_list_t **fahead)
+{
+ char fontpath[256];
+
+ /* Current we only support searching a single font path */
+ if (get_font_path(fontpath, sizeof(fontpath)-1) < 0)
+ return -1;
+ if (find_font_files(ffhead, fontpath) < 0)
+ return -1;
+
+ if (build_font_aliases(fahead, *ffhead) < 0)
+ return -1;
+
+ return 0;
+}
+
+BOOL write_cidfmap(const char *cidpath)
+{
+ FILE *f;
+ font_list_t *ffhead = NULL;
+ alias_list_t *fahead = NULL;
+ int code = 0;
+
+ if (build_cidfmap(&ffhead, &fahead) < 0) {
+ code = 1;
+ gs_addmess("Failed to build cidfmap\n");
+ }
+ else {
+ f = fopen(cidpath, "a");
+ if (f == NULL) {
+ gs_addmess("Failed to update cidfmap \042");
+ gs_addmess(cidpath);
+ gs_addmess("\042\n");
+ code = 1;
+ }
+ else {
+ fprintf(f, "\n%% entries below here were generated by ghostscript\n");
+ fprintf(f, "%% installer from fonts present on this computer\n\n");
+ write_cidfmap_fonts(f, ffhead);
+ write_cidfmap_aliases(f, fahead);
+ fprintf(f, "\n");
+ fclose(f);
+ }
+ }
+ return (code == 0);
+}
//////////////////////////////////////////////////////////////////////
More information about the gs-code-review
mailing list