[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