Java Source Code : 康煕部首文字を含むフォント一覧

 Java Source Code : 康煕部首文字を含むフォント一覧

「康煕部首文字を含んでいるフォント」のフォントファイルを全て抽出し、一覧にするJavaプログラムを作ったので公開します。
実行結果は、康煕部首文字を含むフォント一覧のとおりです。
フォントファイルの内部構造(仕様)は、The OpenType Font Fileに書かれています。
この仕様を読んだだけだと、イメージがわきにくいので、本sorce codeを併せて読めば、理解し易くなると思われます。
実行する前の準備(環境はWindows10)
1.C://Users/Public/Documents/myFontsフォルダーを作成する。
2.C:\Windows\Fontsにあるフォントを全て、上記1で作成したフォルダーにコピーする。
3.本プログラムを実行させる。(実行のさせ方は、各自で調べてください)
4.上記1のフォルダーに000勇者ああああ.txtファイルが上書き作成され、そこにフォント一覧が記載されている。

//以下、Java source code

package module;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
//https://docs.microsoft.com/ja-jp/typography/opentype/spec/otff
public class mainProgram {
static private String sDir = new String("C://Users/Public/Documents/myFonts"); 
public static class classTags {
    public int iThisRecordID;
    public int iTagID;
    public String sTagName;
    public String sDiscription;
    public long lgLength;
    public long lgOffset;
    public long lgCheckSum;
    
    public classTags(){
    iThisRecordID = 0;
    iTagID = 0;
    sTagName = null;
    sDiscription = null;
    lgLength = 0;
    lgOffset = 0;
    lgCheckSum = 0;
    }
    
    public int getIDTag() {
    return iTagID;
    }
    
    public String getTagName() {
    return sTagName; 
    }
}
public static ArrayList<classTags> cTs = null;
private static PrintWriter fw;
private static int hasKangxiRadicals;
private static String sNameOfFont = "";

private static class classTagsCompare implements Comparator<classTags> {
    public int compare(classTags c1, classTags c2) {
        if(c1.getIDTag() < c2.getIDTag()) {
            return -1;
        }
        else {
        if(c1.getIDTag() > c2.getIDTag()) return 1;
        else return c1.getTagName().compareTo(c2.getTagName());
        }
    }
}

public static void main(String[] args) {
        System.out.println("start of program");
        RandomAccessFile f;
        int iCounter, iTTFiles;
        
        try {
            fw = new PrintWriter(sDir + "/000勇者ああああ.txt");
            fw.println("analyze font files");
        }
        catch (IOException ex) {
            ex.printStackTrace();
        System.exit(0);
        }        
        
        File dir = new File(sDir);
        File[] list = dir.listFiles();
        
        iTTFiles = 0;
        for(iCounter = 0; iCounter<list.length; iCounter++) {
        String s;
       
        s = list[iCounter].getName();
        s.toLowerCase();
        if(s.endsWith(".ttc")) {
        boolean bRet = true;
        iTTFiles++;
        s = list[iCounter].getAbsolutePath();
            System.out.println(s);
                try {
                f = new RandomAccessFile(s, "r");
                    fw.print(String.valueOf(iTTFiles) + " " + s);
                bRet = proceed_ttc(f);
                f.close();
               
                }
                catch(FileNotFoundException e) {
                System.out.println(e);
                System.exit(0);
                }
                catch(IOException e) {
                System.out.println(e);
                System.exit(0);
            }
                if(bRet==false) break;
        }
        else {
            if(s.endsWith(".ttf")) {
            boolean bRet = true;
            iTTFiles++;
            s = list[iCounter].getAbsolutePath();
                System.out.println(s);
                    try {
                    f = new RandomAccessFile(s, "r");
                        fw.print(String.valueOf(iTTFiles) + " " + s);
                        bRet = proceedFontTable_ttf(f);
                    f.close();
                    }
                    catch(FileNotFoundException e) {
                    System.out.println(e);
                    System.exit(0);
                    }
                    catch(IOException e) {
                    System.out.println(e);
                    System.exit(0);
                }
                    if(bRet==false) break;
            }
        }
        }
        
        fw.close();
    System.out.println("Number of all font files : " + String.valueOf(iTTFiles));
    System.out.println("end of program");
    }

static private boolean proceed_ttc(RandomAccessFile f) {
long lgOffsetFonts[];
lgOffsetFonts = proceedHeader(f);
    if(lgOffsetFonts==null) return false;
    else return proceedFontTable(f, lgOffsetFonts);
}
static private long[] proceedHeader(RandomAccessFile f) {
int iMajorV,iValue;
byte b4[] = new byte[4];

try {
f.read(b4);
}
catch(IOException e) {
        System.out.println(e);
return null;
}

String s4 = new String(b4);
if(s4.toString().equals("ttcf")) System.out.println("This is " + s4);
else {
        System.out.println("error : " + s4 + " is not ttcf");
        return null;
}

iMajorV = get16(f, 0);
if(iMajorV == -1) return null;
System.out.println("major version : " + String.valueOf(iMajorV));
iValue = get16(f, 0);
if(iValue == -1) return null;
System.out.println("minor version : " + String.valueOf(iValue));

long lgMax;
lgMax = get32(f, 0);
if(lgMax == -1) return null;
System.out.println("number of fonts : " + String.valueOf(lgMax));

long lgOffsetFonts[] = new long[(int) lgMax];
for(long lg=0; lg<lgMax ; lg++) {
long lgValue;
lgValue = get32(f, 0);
lgOffsetFonts[(int)lg] = lgValue;
System.out.println("    offset : 0x" +  Long.toHexString(lgValue));
}

if(iMajorV==2) {
try {
f.read(b4);
}
catch(IOException e) {
        System.out.println(e);
return null;
}

s4 = new String(b4);
if(s4.toString().equals("DSIG")) {
System.out.println("DSIG - Digital Signature - Other OpenType Tables");
long lg;
lg = get32(f, 0);
if(lg == -1) return null;
System.out.println("    length : " + String.valueOf(lg));
lg = get32(f, 0);
if(lg == -1) return null;
System.out.println("    offset : 0x" + Long.toHexString(lg));
}
else {
if(b4[0]==0) {
System.out.println("This font has no DSIG, although major version is 2.");
get32(f, 0);
get32(f, 0);
}
else {
        System.out.println("*** error : proceedHeader() " + s4 + " is not DSIG");
        return null;
}
}
}
return lgOffsetFonts;
}

static private boolean proceedFontTable_ttf (RandomAccessFile f) {
hasKangxiRadicals = 0;
long lgValue;
lgValue = get32(f, 0);
if(lgValue == -1) return false;

if(lgValue==0x10000) {
System.out.println("This font has TrueType outlines");
}
else {
if(lgValue==0x4F54544F) {
System.out.println("This font has CFF data");
}
else {
System.out.println("error : proceedFontTable_ttf() at sfntVersion");
return false;
}
}
boolean bRet;
bRet = getFontTable(f);
if(bRet==false) {
return false;
}
if(hasKangxiRadicals==0) {
            fw.println(" has no Kangxi Radical");
}
return true;
}
static private boolean proceedFontTable(RandomAccessFile f, long lgOffsetFonts[]) {
int i, iSize = lgOffsetFonts.length;
hasKangxiRadicals = 0;
for(i=0; i<iSize; i++) {
long lgOffset = lgOffsetFonts[i], lgValue;
try {
f.seek(lgOffset);
}
catch (IOException e) {
e.printStackTrace();
return false;
}
lgValue = get32(f, 0);
if(lgValue == -1) return false;

if(lgValue==0x10000) {
System.out.println("font[" + String.valueOf(i) + "] : has TrueType outlines");
}
else {
if(lgValue==0x4F54544F) {
System.out.println("*** font[" + String.valueOf(i) + "] : has CFF data");
}
else {
System.out.println("error : font[" + String.valueOf(i) + "] : at sfntVersion");
return false;
}
}
boolean bRet;
bRet = getFontTable(f);
if(bRet==false) {
return false;
}
}
if(hasKangxiRadicals==0) {
            fw.println(" has no Kangxi Radical");
}
return true;
}
static private boolean getFontTable(RandomAccessFile f) {
int i, iTables;

iTables = get16(f, 0);
if(iTables == -1) return false;
System.out.println("  number of Tables : " + String.valueOf(iTables));
i = get16(f, 0);
if(i == -1) return false;
System.out.println("  searchRange : " + String.valueOf(i));
i = get16(f, 0);
if(i == -1) return false;
System.out.println("  entrySelector : " + String.valueOf(i));
i = get16(f, 0);
if(i == -1) return false;
System.out.println("  rangeShift : " + String.valueOf(i));

ArrayList<classTags> cTs = new ArrayList<>();
for(i=0; i<iTables; i++) {
classTags ct = new classTags();
ct.iThisRecordID= i;
byte b4[] = new byte[4];
try {
f.read(b4);
}
catch(IOException e) {
        System.out.println(e);
return false;
}

ct.sTagName = new String(b4);
if(getTableTag(ct)==false) return false;
long lgValue = get32(f, 0);
if(lgValue == -1) return false;
ct.lgCheckSum = lgValue;

lgValue = get32(f, 0);
if(lgValue == -1) return false;
ct.lgOffset = lgValue;

lgValue = get32(f, 0);
if(lgValue == -1) return false;
ct.lgLength = lgValue;
cTs.add(ct);
}

    Collections.sort(cTs, new classTagsCompare());
    
    int iTag = cTs.get(0).iTagID;
    printTagGroupName(iTag);
for(i=0; i<iTables; i++) {
boolean bRet;
if(iTag!=cTs.get(i).iTagID) {
iTag = cTs.get(i).iTagID;
printTagGroupName(iTag);
}
        System.out.println("  " + cTs.get(i).sTagName + " - " + cTs.get(i).sDiscription);
       
        switch(cTs.get(i).sTagName) {
        case "cmap":
        bRet = cmap(f, cTs.get(i).lgOffset);
        if(bRet==false) return false;
        break;
       
        case "name":
        bRet = name(f, cTs.get(i).lgOffset);
        if(bRet==false) return false;
        break;
        }
}

if(hasKangxiRadicals>=1) {
if(hasKangxiRadicals==1) {
fw.println(" has Kangxi Radical");
}
fw.println(sNameOfFont);
sNameOfFont = "";
}
    
return true;
}

static private boolean name(RandomAccessFile f, long lgOffset) {
long lgOffsetStorage = lgOffset, lgOffsetNameRecode = lgOffset;
int i, iCounter, j, iNames;
String s;

i = get16(f, lgOffset);
lgOffsetNameRecode += 2;
    System.out.println("    format : " + String.valueOf(i));
   
iNames = get16(f, 0);
lgOffsetNameRecode += 2;
    System.out.println("    number of name records : " + String.valueOf(iNames));
    i = get16(f, 0);
lgOffsetNameRecode += 2;
    lgOffsetStorage += i;
    System.out.println("    stringOffset : 0x" + Long.toHexString(i));
   
String s1J="", s1nJ="", s2J="", s2nJ="";

//Name Records
    for(iCounter=0; iCounter<iNames; iCounter++) {
    int iPlatformID, iEncordingID, iLanguage, iNameID, iLength, iLength2;
    long lgOffsetString;
   
    lgOffsetString = lgOffsetStorage;
   
    iPlatformID = get16(f, lgOffsetNameRecode);
    lgOffsetNameRecode += 2;
    s = "  - platform ID : " + String.valueOf(iPlatformID);
    switch(iPlatformID) {
    case 0: s += " for Unicode"; break;
    case 1: s += " for Macintosh"; break;
    case 2: s += " for ISO [deprecated]"; break;
    case 3: s += " for Windows"; break;
    case 4: s += " for Custom"; break;
    default:
            System.out.println("error : name() " + s);
            return false;
    }
        System.out.println(s);
   
        iEncordingID = get16(f, 0);
    lgOffsetNameRecode += 2;
    s = "    encording ID : " + String.valueOf(iEncordingID);
    switch(iPlatformID) {
    case 0:
    switch(iEncordingID) {
    case 0: s += " 1.0 semantics"; break;
    case 1: s += " 1.1 semantics"; break;
    case 2: s += " ISO/IEC 10646 semantics"; break;
    case 3: s += " BMP only"; break;
    case 4: s += " full repertoire"; break;
    case 5: s += " Variation Sequences"; break;
    case 6: s += " full repertoire"; break;
        default:
                System.out.println("* error : name() " + s);
                return false;
    }
    break;
    case 1:
    break;
    case 3:
    switch(iEncordingID) {
    case 0: s += " for Symbol"; break;
    case 1: s += " for Unicode BMP"; break;
    case 2: s += " for ShiftJIS"; break;
    case 3: s += " for PRC"; break;
    case 4: s += " for Big5"; break;
    case 5: s += " for Wansung"; break;
    case 6: s += " for Johab"; break;
    case 7: s += " Reserved"; break;
    case 8: s += " Reserved"; break;
    case 9: s += " Reserved"; break;
    case 10: s += " for Unicode full repertoire"; break;
        default:
                System.out.println("error : name() " + s);
                return false;
    }
    break;
    default:
            System.out.println("* error : not programed. name() " + s);
            return false;
    }
        System.out.println(s);
       
        String sEncording = "UTF-16";
        iLanguage= get16(f, 0);
    lgOffsetNameRecode += 2;
        s = "    language ID : 0x" + Long.toHexString(iLanguage);
        switch(iLanguage) {
        case 0x0000:
        if(iPlatformID==1 || iPlatformID==3) sEncording = "UTF-8";
        break;
        case 0x0403: s += " Catalan Catalan"; break;
        case 0x0405: s += " Czech Czech Republic"; break;
        case 0x0406: s += " Danish Denmark"; break;
        case 0x0407: s += " German Germany"; break;
        case 0x0408: s += " Greek Greece"; break;
        case 0x0409: s += " English United States"; break;
        case 0x040a: s += " Spanish (Traditional Sort) Spain"; break;
        case 0x040b: s += " Finnish Finland"; break;
        case 0x040c: s += " French France"; break;
        case 0x040e: s += " Hungarian Hungary"; break;
        case 0x0410: s += " Italian Italy"; break;
        case 0x0411: s += " Japanese Japan"; break;
        case 0x0413: s += " Dutch Netherlands"; break;
        case 0x0414: s += " Norwegian (Bokmal) Norway"; break;
        case 0x0415: s += " Polish Poland"; break;
        case 0x0416: s += " Portuguese Brazil"; break;
        case 0x0419: s += " Russian Russia"; break;
        case 0x041b: s += " Slovak Slovakia"; break;
        case 0x041d: s += " Swedish Sweden"; break;
        case 0x041f: s += " Turkish Turkey"; break;
        case 0x0424: s += " Slovenian Slovenia"; break;
        case 0x042d: s += " Basque Basque"; break;
        case 0x080a: s += " Spanish Mexico"; break;
        case 0x0816: s += " Portuguese Portugal"; break;
        case 0x0c0a: s += " Spanish (Modern Sort) Spain"; break;
        case 0x0c0c: s += " French Canada"; break;
        default: s += " *** not programed ***"; break;
        }
        System.out.println(s);
       
    iNameID = get16(f, 0);
    lgOffsetNameRecode += 2;
    s = "    name ID : " + String.valueOf(iNameID);
    switch(iNameID) {
    case 0: s += " Copyright notice"; break;
    case 1: s += " Font Family name"; break;
    case 2: s += " Font Subfamily name"; break;
    case 3: s += " Unique font identifier"; break;
    case 4: s += " Full font name"; break;
    case 5: s += " Version string"; break;
    case 6: s += " PostScript name"; break;
    case 7: s += " Trademark"; break;
    case 8: s += " Manufacturer Name"; break;
    case 9: s += " Designer"; break;
    case 10: s += " description of the typeface"; break;
    case 11: s += " URL of font vendor"; break;
    case 12: s += " URL of typeface designer"; break;
    case 13: s += " License Description"; break;
    case 14: s += " License Info URL"; break;
    case 15: s += " Reserved"; break;
    case 16: s += " Typographic Family name"; break;
    case 17: s += " Typographic Subfamily name"; break;
    case 18: s += " Compatible Full (Macintosh only)"; break;
    case 19: s += " Sample text"; break;
        default: s += " *** not programed"; break;
    }
        System.out.println(s);
       
    iLength= get16(f, 0);
    lgOffsetNameRecode += 2;
        System.out.println("    length : " + String.valueOf(iLength) + " bytes");
       
    j= get16(f, 0);
    lgOffsetNameRecode += 2;
    lgOffsetString = lgOffsetStorage + j;
        System.out.println("    offset : 0x" + Long.toHexString(j));
       
        if(iLength>200) iLength2 = 200;
        else iLength2 = iLength;
    byte b[] = new byte[iLength2];
    try {
    f.seek(lgOffsetString);
    f.read(b);
    }
    catch(IOException e) {
            System.out.println(e);
    return false;
    }
   
    try {
s = new String(b, sEncording);
}
    catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
        if(iLength>200) s += "...";
        System.out.println("    " + s);
       
        if(iLanguage==0x0411) {
        if(iNameID==1) s1J = s;
        else if(iNameID==5) s2J = s;
        }
        else {
        if(iNameID==1) s1nJ = s;
        else if(iNameID==5) s2nJ = s;
        }
    }
   
    if(s1J.equals("")) {
    sNameOfFont = s1nJ + " " + s2nJ;
    }
    else {
    sNameOfFont = s1J + " " + s2J;
    }
return true;
}

static private boolean cmap(RandomAccessFile f, long lgOffset) {
long lgAdressStart = lgOffset, lgProgress, lg;
int i, j, iNumTables, iCounter;
boolean bHasKangxiRadicals = false;

//cmap Header
i = get16(f, lgOffset);
lgAdressStart += 2;
    System.out.println("    version : " + String.valueOf(i));

iNumTables = get16(f, 0);
lgAdressStart += 2;
    System.out.println("    number of tables : " + String.valueOf(iNumTables));
   
    lgProgress = 0;
    for(iCounter = 0; iCounter<iNumTables; iCounter++) {
   
    //ncoding records and encodings
    int iK, iPlatformID, iEncordingID, iFormat, iValue;
    long lgGroupings, lgValue;
   
    iPlatformID = get16(f, lgAdressStart + lgProgress);
    lgProgress += 2;
   
    iEncordingID = get16(f, 0);
    lgProgress += 2;
   
    String s = "    - platform ID : ";
    switch(iPlatformID) {
    case 0: s += " " + String.valueOf(iPlatformID) + ". for Unicode"; break;
    case 1: s += " " + String.valueOf(iPlatformID) + ". for Macintosh"; break;
    case 3:
    s += " " + String.valueOf(iPlatformID) + ". for Windows";
            System.out.println(s);
            switch(iEncordingID) {
            case 0: s = "      Symbol"; break;
            case 1: s = "      Unicode BMP"; break;
            case 10: s = "      Unicode full repertoire"; break;
            default: s = "*** cmap() not programed at EncordingID"; break;
            }
    break;
    default: s += " " + String.valueOf(iPlatformID) + ". error"; break;
    }
        System.out.println(s);
        System.out.println("      encording ID : " + String.valueOf(iEncordingID));
       
        lg = get32(f, 0);//Byte offset from beginning of table to the subtable for this encoding
        lgProgress += 4;
        System.out.println("      offset : 0x" + String.valueOf(lg));
       
        lg += lgOffset;
       
        switch(iPlatformID) {
        case 0://for Unicode. Format 14: Unicode Variation Sequences
        i = get16(f, lg);
        if(i==14) {
                System.out.println("      format : 14 Unicode Variation Sequences");
            lg = get32(f, 0);
                System.out.println("      length : 0x" + Long.toHexString(lg));
               
            lg = get32(f, 0);
                System.out.println("      numVarSelectorRecords : 0x" + Long.toHexString(lg));
        }
        else {
                System.out.println("      format : " + String.valueOf(i));
                System.out.println("      *** error format is NOT 14 Unicode Variation Sequences");
        }
        break;
        
        case 1: //Macintosh platform
            System.out.println("    format : 1 Macintosh platform");
            break;
        
        case 3: //for Windows
        iFormat = get16(f, lg);
        switch(iEncordingID) {
        case 0:
        case 1://format: 4 Segment mapping to delta values
        if(iFormat==4) System.out.println("      format: 4 Segment mapping to delta values");
        else {
                    System.out.println("*** error cmap() format : " + String.valueOf(iFormat));
                    return false;
        }
       
            i = get16(f, 0);
            System.out.println("      length : " + String.valueOf(i));
            i = get16(f, 0);
            System.out.println("      language : " + String.valueOf(i));
           
            j = get16(f, 0);
            System.out.println("      segCountX2 : " + String.valueOf(j));
           
            i = get16(f, 0);
            System.out.println("      searchRange : " + String.valueOf(i));
            i = get16(f, 0);
            System.out.println("      entrySelector : " + String.valueOf(i));
            i = get16(f, 0);
            System.out.println("      rangeShift : " + String.valueOf(i));
            i = get16(f, 0);
            System.out.println("      endCode[0] : 0x" + Long.toHexString(i));
           
            iValue = 0;
            j /= 2;
            j--;
            for(i=0; i<j; i++) {
            iValue = get16(f, 0);
            }
            System.out.println("      endCode[last] : 0x" + Long.toHexString(iValue));
           
            i = get16(f, 0);
            System.out.println("      reservedPad : " + String.valueOf(i));//Set to 0.
           
            i = get16(f, 0);
            System.out.println("      startCode[0] : 0x" + Long.toHexString(i));
            iK = 0;
            iValue = 0;
            for(i=0; i<j; i++) {
            iValue = get16(f, 0);
                if(
                iValue>=0x2f00 && iValue<=0x2fdf
                || iValue>=0x2e80 && iValue<=0x2eff
                ) {
                bHasKangxiRadicals = true;
                //Kangxi Radicals Range: 2F00–2FDF
                //CJK Radicals Supplement Range: 2E80–2EFF
                iK++;
                        System.out.println("    * Kangxi Radicals start Unicode 0x" + Long.toHexString(iValue));
                }
            }
            if(iK==0) {
            System.out.println("      endCode[last] : 0x" + Long.toHexString(iValue));
                    System.out.println("      This font has no Kangxi Radicals");
            }
            else {
                    System.out.println("  ***  found Kangxi Radicals");
            }
            break;
        case 10://format:12 Segmented coverage
        if(iFormat!=12) {
                    System.out.println("*** error cmap() format not 12");
                    return false;
        }
                System.out.println("      format:12 Segmented coverage");
            i = get16(f, 0);
            if(i==0) System.out.println("      Reserved; set to 0");
            else {
                    System.out.println("*** error cmap() Reserved; set to 0");
                    return false;
            }
           
            lg = get32(f, 0);//Byte length of this subtable (including the header)
                System.out.println("      length : 0x" + Long.toHexString(lg));
               
            lg = get32(f, 0);//For requirements on use of the language field
            //The language field must be set to zero 
                System.out.println("      Language : " + String.valueOf(lg));
               
                lgGroupings = get32(f, 0);//Number of groupings which follow
                System.out.println("      number of groupings : " + String.valueOf(lgGroupings));
               
                iK = 0;
                for(lg=0; lg<lgGroupings; lg++) {
                lgValue = get32(f, 0);
                get32(f, 0);
                get32(f, 0);
                if(
                lgValue>=0x2f00 && lgValue<=0x2fdf
                || lgValue>=0x2e80 && lgValue<=0x2eff
                ) {
                //Kangxi Radicals Range: 2F00–2FDF
                bHasKangxiRadicals = true;
                iK++;
                }
                }
                if(iK==0) {
                    System.out.println("      This font has no Kangxi Radicals");
                }
                else{
                    System.out.println("   ***  found Kangxi Radicals. number is " + String.valueOf(iK));
                }
        break;
       
        default:
                System.out.println("*** error cmap() not programed format : "+ String.valueOf(iFormat));
                return false;
        }
       
        break;
        default:
            System.out.println("*** error cmap() iPlatformID");
            return false;
        }
    }
    if(bHasKangxiRadicals) {
hasKangxiRadicals++;
    }
return true;
}

static private boolean printTagGroupName(int iTagID) {
boolean bRet = true;
    switch(iTagID) {
    case 0:
        System.out.println("- Required Tables");
        break;
    case 1:
        System.out.println("- Tables Related to TrueType Outlines");
        break;
    case 2:
        System.out.println("- Tables Related to Bitmap Glyphs");
        break;
    case 3:
        System.out.println("- Advanced Typographic Tables");
        break;
    case 4:
        System.out.println("- Tables used for OpenType Font Variations");
        break;
    case 5:
        System.out.println("- Tables Related to Color Fonts");
        break;
    case 6:
        System.out.println("- Other OpenType Tables");
        break;
    default:
        System.out.println("not programed at printTagGroupName()");
    bRet = false;
    break;
    }
    return bRet;
}

static private boolean getTableTag(classTags cT) {
boolean bRet = true;

switch(cT.sTagName) {
//Required Tables
case "cmap":
cT.sDiscription =  "Character to Glyph Index Mapping";
cT.iTagID = 0;
break;

case "OS/2":
cT.sDiscription = "OS/2 and Windows Metrics";
cT.iTagID = 0;
break;

    case "head":
cT.sDiscription = "Font Header";
cT.iTagID = 0;
break;

    case "hhea":
cT.sDiscription = "Horizontal Header";
cT.iTagID = 0;
break;

    case "hmtx":
cT.sDiscription = "Horizontal Metrics";
cT.iTagID = 0;
break;

    case "maxp":
cT.sDiscription = "Maximum Profile";
cT.iTagID = 0;
break;
    case "name":
cT.sDiscription = "Naming";
cT.iTagID = 0;
break;
case "post":
cT.sDiscription = "PostScript";
cT.iTagID = 0;
break;

//Tables Related to TrueType Outlines
case "cvt ":
cT.sDiscription = "Control Value";
cT.iTagID = 1;
break;

case "fpgm":
cT.sDiscription = "Font Program";
cT.iTagID = 1;
break;

    case "gasp":
cT.sDiscription = "Grid-fitting and Scan-conversion Procedure";
cT.iTagID = 1;
break;

case "glyf":
cT.sDiscription = "Glyph Data";
cT.iTagID = 1;
break;

    case "loca":
cT.sDiscription = "Index to Location";
cT.iTagID = 1;
break;

    case "prep":
cT.sDiscription = "Control Value Program";
cT.iTagID = 1;
break;

//Tables Related to Bitmap Glyphs
    case "EBDT":
cT.sDiscription = "Embedded Bitmap Data";
cT.iTagID = 2;
break;

    case "EBLC":
cT.sDiscription = "Embedded Bitmap Location";
cT.iTagID = 2;
break;

//Advanced Typographic Tables
case "BASE":
cT.sDiscription = "Baseline";
cT.iTagID = 3;
break;

case "GDEF":
cT.sDiscription = "Glyph Definition";
cT.iTagID = 3;
break;

    case "GPOS":
cT.sDiscription = "Glyph Positioning";
cT.iTagID = 3;
break;

    case "GSUB":
cT.sDiscription = "Glyph Substitution";
cT.iTagID = 3;
break;

    case "MATH":
cT.sDiscription = "mathematical typesetting table";
cT.iTagID = 3;
break;
    case "JSTF":
cT.sDiscription = "Justification Table";
cT.iTagID = 3;
break;
//Tables used for OpenType Font Variations
    case "avar":
cT.sDiscription = "Axis Variations Table";
cT.iTagID = 4;
    break;
    case "fvar":
cT.sDiscription = "Font Variations Table";
cT.iTagID = 4;
    break;
    case "gvar":
cT.sDiscription = "Glyph Variations Table";
cT.iTagID = 4;
    break;
    case "STAT":
cT.sDiscription = "Style Attributes Table";
cT.iTagID = 4;
    break;
    case "HVAR":
cT.sDiscription = "Horizontal Metrics Variations Table";
cT.iTagID = 4;
    break;
    case "MVAR":
cT.sDiscription = "Metrics Variations Table";
cT.iTagID = 4;
    break;
    //Tables Related to Color Fonts
    case "COLR":
cT.sDiscription = "Color Table";
cT.iTagID = 5;
break;

    case "CPAL":
cT.sDiscription = "Color Palette Table";
cT.iTagID = 5;
break;

    //Other OpenType Tables
    case "meta":
cT.sDiscription = "Metadata";
cT.iTagID = 6;
break;

    case "vhea":
cT.sDiscription = "Vertical Header";
cT.iTagID = 6;
break;

    case "vmtx":
cT.sDiscription = "Vertical Metrics";
cT.iTagID = 6;
break;

    case "LTSH":
cT.sDiscription = "Linear Threshold";
cT.iTagID = 6;
break;

    case "MERG":
cT.sDiscription = "Merge";
cT.iTagID = 6;
break;

    case "kern":
cT.sDiscription = "Kerning";
cT.iTagID = 6;
break;

    case "VDMX":
cT.sDiscription = "Vertical Device Metrics";
cT.iTagID = 6;
break;

    case "hdmx":
cT.sDiscription = "Horizontal Device Metrics";
cT.iTagID = 6;
break;

    case "DSIG":
cT.sDiscription = "Digital Signature Table";
cT.iTagID = 6;
break;
    case "PCLT":
cT.sDiscription = "PCL 5 Table";
cT.iTagID = 6;
break;
    case "ASCP":
    case "bdat":
    case "bloc":
cT.sDiscription = "*** I dont know such a thing!!!";
cT.iTagID = 6;
break;
//error
default:
cT.sDiscription = "not programed !";
cT.iTagID = -1;
bRet = false;
System.out.println("*** getTableTag() not programed : " + cT.sTagName);
break;
}
return bRet;
}
static private int get16(RandomAccessFile f, long lgOffset) {
int retInt;
byte b2[] = new byte[2];
try {
if(lgOffset>0) {
f.seek(lgOffset);
}
f.read(b2);
}
catch(IOException e) {
        System.out.println(e);
return(-1);
}

retInt = b2[0] & 0xFF;
retInt <<= 8;
retInt += b2[1] & 0xFF;
return retInt;
}
static private long get32(RandomAccessFile f, long lgOffset) {
long retLong;
byte b4[] = new byte[4];
try {
if(lgOffset>0) {
f.seek(lgOffset);
}
f.read(b4);
}
catch(IOException e) {
        System.out.println(e);
return(-1);
}

retLong = b4[0] & 0xFF;
retLong <<= 8;
retLong += b4[1] & 0xFF;
retLong <<= 8;
retLong += b4[2] & 0xFF;
retLong <<= 8;
retLong += b4[3] & 0xFF;
return retLong;
}
}

//以上、Java source code