com.jcraft.weirdx.res.XFont.java Source code

Java tutorial

Introduction

Here is the source code for com.jcraft.weirdx.res.XFont.java

Source

/* -*-mode:java; c-basic-offset:2; -*- */
/* WeirdX - Guess.
 *
 * Copyright (C) 1999-2004 JCraft, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

package com.jcraft.weirdx.res;

import java.io.*;
import java.util.*;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.jcraft.weirdx.Client;
import com.jcraft.weirdx.DDXFont;
import com.jcraft.weirdx.Font_CharSet;
import com.jcraft.weirdx.InputOutput;

public final class XFont extends XResource {
    private static Log LOG = LogFactory.getLog(XFont.class);

    public static XFont dflt;
    public static List<Font_CharSet> charSets = new ArrayList<Font_CharSet>();

    byte[] name;
    byte[] lfname;
    public String encoding = null;
    DDXFont font;

    public int ascent;
    public int descent;

    private static String[] _flist = { "-misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso8859-1", // fixed

            "-misc-fixed-bold-r-normal--0-0-100-100-c-0-iso8859-1",
            "-misc-fixed-bold-r-normal--0-0-75-75-c-0-iso8859-1",

            "-misc-fixed-bold-r-normal--13-100-100-100-c-70-iso8859-1",
            "-misc-fixed-bold-r-normal--13-100-100-100-c-80-iso8859-1",
            "-misc-fixed-bold-r-normal--13-120-75-75-c-70-iso8859-1",
            "-misc-fixed-bold-r-normal--13-120-75-75-c-80-iso8859-1",
            "-misc-fixed-bold-r-normal--14-130-75-75-c-70-iso8859-1",
            "-misc-fixed-bold-r-normal--15-120-100-100-c-90-iso8859-1",
            "-misc-fixed-bold-r-normal--15-140-75-75-c-90-iso8859-1",
            "-misc-fixed-bold-r-semicondensed--13-100-100-100-c-60-iso8859-1",
            "-misc-fixed-bold-r-semicondensed--13-120-75-75-c-60-iso8859-1",

            "-misc-fixed-medium-r-normal--0-0-100-100-c-0-iso8859-1",
            "-misc-fixed-medium-r-normal--0-0-75-75-c-0-iso8859-1",

            "-misc-fixed-medium-r-normal--10-100-75-75-c-60-iso8859-1",
            "-misc-fixed-medium-r-normal--10-70-100-100-c-60-iso8859-1",
            "-misc-fixed-medium-r-normal--13-100-100-100-c-70-iso8859-1",
            "-misc-fixed-medium-r-normal--13-100-100-100-c-80-iso8859-1",
            "-misc-fixed-medium-r-normal--13-120-75-75-c-70-iso8859-1",
            "-misc-fixed-medium-r-normal--13-120-75-75-c-80-iso8859-1",
            "-misc-fixed-medium-r-normal--14-110-100-100-c-70-iso8859-1",
            "-misc-fixed-medium-r-normal--14-130-75-75-c-70-iso8859-1",
            "-misc-fixed-medium-r-normal--15-120-100-100-c-90-iso8859-1",
            "-misc-fixed-medium-r-normal--15-140-75-75-c-90-iso8859-1",
            "-misc-fixed-medium-r-normal--16-150-75-75-c-80-iso8859-1",
            "-misc-fixed-medium-r-normal--20-140-100-100-c-100-iso8859-1",
            "-misc-fixed-medium-r-normal--20-200-75-75-c-100-iso8859-1",
            "-misc-fixed-medium-r-normal--7-50-100-100-c-50-iso8859-1",
            "-misc-fixed-medium-r-normal--7-70-75-75-c-50-iso8859-1",
            "-misc-fixed-medium-r-normal--8-60-100-100-c-50-iso8859-1",
            "-misc-fixed-medium-r-normal--8-80-75-75-c-50-iso8859-1",
            "-misc-fixed-medium-r-normal--9-80-100-100-c-60-iso8859-1",
            "-misc-fixed-medium-r-normal--9-90-75-75-c-60-iso8859-1",
            "-misc-fixed-medium-r-semicondensed--12-110-75-75-c-60-iso8859-1",
            "-misc-fixed-medium-r-semicondensed--12-90-100-100-c-60-iso8859-1",
            "-misc-fixed-medium-r-semicondensed--13-100-100-100-c-60-iso8859-1",
            "-sony-fixed-medium-r-normal--16-120-100-100-c-80-iso8859-1",
            "-sony-fixed-medium-r-normal--16-150-75-75-c-80-iso8859-1",
            "-sony-fixed-medium-r-normal--24-170-100-100-c-120-iso8859-1",
            "-sony-fixed-medium-r-normal--24-230-75-75-c-120-iso8859-1",

            "-adobe-courier-bold-o-normal--0-0-100-100-m-0-iso8859-1",
            "-adobe-courier-bold-r-normal--0-0-100-100-m-0-iso8859-1",
            "-adobe-courier-medium-o-normal--0-0-100-100-m-0-iso8859-1",
            "-adobe-courier-medium-r-normal--0-0-100-100-m-0-iso8859-1",

            //  "-adobe-helvetica-bold-o-normal--0-0-100-100-p-0-iso8859-1",
            //  "-adobe-helvetica-bold-r-normal--0-0-100-100-p-0-iso8859-1",
            //  "-adobe-helvetica-medium-o-normal--0-0-100-100-p-0-iso8859-1",
            //  "-adobe-helvetica-medium-r-normal--0-0-100-100-p-0-iso8859-1",
            //  "-adobe-new century schoolbook-bold-i-normal--0-0-100-100-p-0-iso8859-1",
            //  "-adobe-new century schoolbook-bold-r-normal--0-0-100-100-p-0-iso8859-1",
            //  "-adobe-new century schoolbook-medium-i-normal--0-0-100-100-p-0-iso8859-1",
            //  "-adobe-new century schoolbook-medium-r-normal--0-0-100-100-p-0-iso8859-1",
            //  "-adobe-times-bold-i-normal--0-0-100-100-p-0-iso8859-1",
            //  "-adobe-times-bold-r-normal--0-0-100-100-p-0-iso8859-1",
            //  "-adobe-times-medium-i-normal--0-0-100-100-p-0-iso8859-1",
            //  "-adobe-times-medium-r-normal--0-0-100-100-p-0-iso8859-1",

            "-adobe-courier-bold-o-normal--0-0-75-75-m-0-iso8859-1",
            "-adobe-courier-bold-r-normal--0-0-75-75-m-0-iso8859-1",
            "-adobe-courier-medium-o-normal--0-0-75-75-m-0-iso8859-1",
            "-adobe-courier-medium-r-normal--0-0-75-75-m-0-iso8859-1",

            //  "-adobe-helvetica-medium-o-normal--0-0-75-75-p-0-iso8859-1",
            //  "-adobe-helvetica-medium-r-normal--0-0-75-75-p-0-iso8859-1",
            //  "-adobe-new century schoolbook-bold-i-normal--0-0-75-75-p-0-iso8859-1",
            //  "-adobe-new century schoolbook-bold-r-normal--0-0-75-75-p-0-iso8859-1",
            //  "-adobe-new century schoolbook-medium-i-normal--0-0-75-75-p-0-iso8859-1",
            //  "-adobe-new century schoolbook-medium-r-normal--0-0-75-75-p-0-iso8859-1",
            //  "-adobe-times-bold-i-normal--0-0-75-75-p-0-iso8859-1",
            //  "-adobe-times-bold-r-normal--0-0-75-75-p-0-iso8859-1",
            //  "-adobe-times-medium-i-normal--0-0-75-75-p-0-iso8859-1",
            //  "-adobe-times-medium-r-normal--0-0-75-75-p-0-iso8859-1",

            "-adobe-helvetica-bold-o-normal--0-0-0-0-p-0-iso8859-1",
            "-adobe-helvetica-bold-r-normal--0-0-0-0-p-0-iso8859-1",
            "-adobe-helvetica-medium-o-normal--0-0-0-0-p-0-iso8859-1",
            "-adobe-helvetica-medium-r-normal--0-0-0-0-p-0-iso8859-1",
            "-adobe-new century schoolbook-bold-i-normal--0-0-0-0-p-0-iso8859-1",
            "-adobe-new century schoolbook-bold-r-normal--0-0-0-0-p-0-iso8859-1",
            "-adobe-new century schoolbook-medium-i-normal--0-0-0-0-p-0-iso8859-1",
            "-adobe-new century schoolbook-medium-r-normal--0-0-0-0-p-0-iso8859-1",
            "-adobe-times-bold-i-normal--0-0-0-0-p-0-iso8859-1",
            "-adobe-times-bold-r-normal--0-0-0-0-p-0-iso8859-1",
            "-adobe-times-medium-i-normal--0-0-0-0-p-0-iso8859-1",
            "-adobe-times-medium-r-normal--0-0-0-0-p-0-iso8859-1"

    };

    static DDXFont[] flist = null;

    private static String[] _aliases = { "fixed", "-misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso8859-1",
            "7x14", "-misc-fixed-bold-r-normal--14-130-75-75-c-70-iso8859-1", "7x13",
            "-misc-fixed-medium-r-normal--13-120-75-75-c-70-iso8859-1", "7x13bold",
            "-misc-fixed-bold-r-normal--13-120-75-75-c-70-iso8859-1", "8x16",
            "-misc-fixed-medium-r-normal--16-150-75-75-c-80-iso8859-1", "12x24",
            "-sony-fixed-medium-r-normal--24-170-100-100-c-120-iso8859-1", "a14",
            "-misc-fixed-medium-r-normal--14-130-75-75-c-70-iso8859-1" };

    private static Alias[] aliases = null;

    static void addFont(String _name) {
        byte[] name = _name.getBytes();
        DDXFont f = null;
        try {
            f = new DDXFont();
            f.init(name);
        } catch (Exception e) {
            LOG.debug(e);
        }
        if (f == null)
            return;
        DDXFont[] tmp = new DDXFont[flist.length + 1];
        System.arraycopy(flist, 0, tmp, 1, flist.length);
        flist = tmp;
        flist[0] = f;
    }

    public static void addFont(String[] name) {
        List<DDXFont> v = new ArrayList<DDXFont>();
        for (int i = 0; i < name.length; i++) {
            try {
                DDXFont f = new DDXFont();
                f.init(name[i].getBytes());
                v.add(f);
            } catch (Exception e) {
            }
        }
        if (v.size() == 0)
            return;

        DDXFont[] tmp = null;
        int offset = 0;
        if (flist == null) {
            tmp = new DDXFont[v.size()];
        } else {
            tmp = new DDXFont[flist.length + v.size()];
            System.arraycopy(flist, 0, tmp, 0, flist.length);
            offset = flist.length;
        }
        for (int i = 0; i < v.size(); i++) {
            tmp[i + offset] = v.get(i);
        }
        flist = tmp;
    }

    public static void addAlias(String[] name) {
        List<Alias> v = new ArrayList<Alias>();
        for (int i = 0; i < name.length; i += 2) {
            byte[] b = name[i + 1].getBytes();
            DDXFont fl = null;
            for (int j = 0; j < flist.length; j++) {
                if (match_aux(flist[j].lfname, 0, b, 0)) {
                    fl = flist[j];
                    break;
                }
            }
            if (fl == null)
                continue;
            v.add(new Alias(name[i].getBytes(), fl));
        }
        if (v.size() == 0)
            return;

        Alias[] tmp = null;
        int offset = 0;
        if (aliases == null) {
            tmp = new Alias[v.size()];
        } else {
            tmp = new Alias[aliases.length + v.size()];
            System.arraycopy(aliases, 0, tmp, 0, aliases.length);
            offset = aliases.length;
        }
        for (int i = 0; i < v.size(); i++) {
            tmp[i + offset] = (Alias) v.get(i);
        }
        aliases = tmp;
    }

    static void addAlias(String name, String font) {
        byte[] b = font.getBytes();
        for (int i = 0; i < flist.length; i++) {
            if (match_aux(flist[i].lfname, 0, b, 0)) {
                if (aliases == null) {
                    aliases = new Alias[1];
                } else {
                    Alias[] foo = new Alias[aliases.length + 1];
                    System.arraycopy(aliases, 0, foo, 1, aliases.length);
                    aliases = foo;
                }
                aliases[0] = new Alias(name.getBytes(), flist[i]);
                return;
            }
        }
    }

    static byte[][] fpath = { "/tmp".getBytes() };

    public static void init(int id, String charset) {
        if (_flist != null) {
            addFont(_flist);
            _flist = null; // go away!!
        }
        if (_aliases != null) {
            addAlias(_aliases);
            _aliases = null; // go away!!
        }
        dflt = new XFont(id, "fixed");

        if (charset != null) {
            int start = 0, end;
            while (true) {
                if ((end = charset.indexOf(',', start)) > 0) {
                    loadCharSet(charset.substring(start, end));
                    start = end + 1;
                    continue;
                }
                if (start < charset.length()) {
                    loadCharSet(charset.substring(start));
                }
                break;
            }
        }
        loadCharSet("FONTSPECIFIC");
    }

    @SuppressWarnings("unchecked")
    static void loadCharSet(String name) {
        try {
            Class<Font_CharSet> c = (Class<Font_CharSet>) Class.forName("com.jcraft.weirdx.Font_CharSet_" + name);

            Font_CharSet o = c.newInstance();
            charSets.add(o);
            o.init();
        } catch (Exception e) {
        }
    }

    public java.awt.Font getFont() {
        return font.getFont();
    }

    int bytesWidth(byte[] b, int i, int j) {
        return font.metric.bytesWidth(b, i, j);
    }

    public int charsWidth(char[] b, int i, int j) {
        return font.metric.charsWidth(b, i, j);
    }

    private static boolean match_aux(byte[] b1, int i1, byte[] b2, int i2) {
        while (i1 < b1.length && i2 < b2.length) {
            if (b1[i1] != b2[i2])
                break;
            i1++;
            i2++;
        }
        if (i2 == b2.length)
            return true;
        if (b2[i2] == '*') {
            i2++;
            if (i2 == b2.length)
                return true;
            if (i1 == b1.length)
                return false; // a <-> a*-
            for (int i = i1; i < b1.length; i++) {
                if (b1[i] == b2[i2]) {
                    boolean res = match_aux(b1, i, b2, i2);
                    if (res)
                        return res;
                }
            }
            return false;
        }
        if (b2[i2] == '?') {
            if (i1 == b1.length)
                return false;
            i2++;
            i1++;
            return match_aux(b1, i1, b2, i2);
        }
        return false;
    }

    private static boolean match_scalable(byte[] b1, byte[] b2) {
        int i1 = 0;
        int i2 = 0;
        int i = 0;
        //System.out.println("s1: "+new String(b1)+ ", s2: "+new String(b2));
        for (int j = 0; j < b2.length; j++) {
            if (b2[j] == '-')
                i++;
        }
        if (i != 14)
            return false;

        i = 0;
        while (i1 < b1.length && i2 < b2.length) {
            if (b1[i1] == '-')
                i++;
            //System.out.println("s1: "+new Character((char)b1[i1])+
            //       ", s2: "+new Character((char)b2[i2]));
            if (b1[i1] != b2[i2]) {
                if (b2[i2] == '*' || b2[i2] == '0') {
                    if (i2 + 1 == b2.length)
                        return true; // end
                    if (b1[i1] == '-') {
                        i--;
                        i1--;
                    } // again
                    else {
                        for (; i1 < b1.length; i1++) {
                            if (b1[i1] == '-') {
                                i1--;
                                break;
                            }
                        }
                        if (i1 == b1.length)
                            return false;
                    }
                } else if (b2[i2] == '?') {
                    if (i2 + 1 == b2.length)
                        return true; // end
                    if (b1[i1] == '-')
                        return false;
                    if ((i1 + 1) >= b1.length || (b1[i1 + 1] != '-')) {
                        return false;
                    }
                } else if (b1[i1] == '0' && (i == 7 || i == 8 || i == 9 || i == 10 || i == 11 || i == 12)) {
                    // scalable font!!
                    if (b2[i2] < '0' || '9' < b2[i2])
                        return false;
                    for (; i2 < b2.length; i2++) {
                        if (b2[i2] == '-') {
                            i2--;
                            break;
                        }
                    }
                    if (i2 == b2.length)
                        return false;
                } else {
                    return false;
                }
            }
            i1++;
            i2++;
        }
        return true;
    }

    public static byte[] genScaleName(byte[] lfname, byte[] name) {
        return genScaleName(lfname, name, 0);
    }

    static byte[] genScaleName(byte[] lfname, byte[] name, int size) {
        //System.out.println("lfname: "+new String(lfname)+
        //", name: "+new String(name));

        if (size == 0) {
            size = getScalableSize(name);
            if (size == 0) {
                //System.out.println("scalable font error: "+new String(name));
                size = 14;
            }
        }

        StringBuffer tmp = new StringBuffer();
        int i = 0;
        int skip = 7;
        while (i < lfname.length) {
            if (lfname[i] == '-') {
                skip--;
            }
            tmp.append((char) lfname[i]);
            i++;
            if (skip == 0)
                break;
        }
        tmp.append(size + "-" + (size * 10) + "-");
        skip = 2;
        while (i < lfname.length) {
            if (lfname[i] == '-') {
                skip--;
            }
            i++;
            if (skip == 0)
                break;
        }
        skip = 3;
        while (i < lfname.length) {
            if (lfname[i] == '-') {
                skip--;
            }
            tmp.append((char) lfname[i]);
            i++;
            if (skip == 0)
                break;
        }
        tmp.append(size + "-");
        skip = 1;
        while (i < lfname.length) {
            if (lfname[i] == '-') {
                skip--;
            }
            i++;
            if (skip == 0)
                break;
        }
        while (i < lfname.length) {
            tmp.append((char) lfname[i]);
            i++;
        }
        //System.out.println(tmp.toString());
        return tmp.toString().getBytes();
    }

    static int getScalableSize(byte[] name) {
        int size = 0;
        int i = 0;
        int skip = 7;
        while (i < name.length) {
            if (name[i] == '-') {
                skip--;
            }
            i++;
            if (skip == 0)
                break;
        }
        if (i >= name.length)
            return 0;
        if ('0' <= name[i] && name[i] <= '9') {
            while (i < name.length) {
                if (name[i] == '-')
                    break;
                size = size * 10 + name[i] - '0';
                i++;
            }
        }
        if (size == 0) {
            i++;
            skip = 1;
            while (i < name.length) {
                if (name[i] == '-') {
                    skip--;
                }
                i++;
                if (skip == 0)
                    break;
            }
            if (i >= name.length)
                return 0;
            if ('0' <= name[i] && name[i] <= '9') {
                while (i < name.length) {
                    if (name[i] == '-')
                        break;
                    size = size * 10 + name[i] - '0';
                    i++;
                }
            }
            if (size > 0)
                size = (int) (size / 10);
        }
        if (size == 0) {
            i++;
            skip = 3;
            while (i < name.length) {
                if (name[i] == '-') {
                    skip--;
                }
                i++;
                if (skip == 0)
                    break;
            }
            if (i >= name.length)
                return 0;
            if ('0' <= name[i] && name[i] <= '9') {
                while (i < name.length) {
                    if (name[i] == '-')
                        break;
                    size = size * 10 + name[i] - '0';
                    i++;
                }
            }
        }
        return size;
    }

    XFont(int id, String name) {
        super(id, RT_FONT);
        this.name = name.getBytes();
        if (name.equals("fixed") || name.equals("cursor")) {
            font = flist[0];
            lfname = font.lfname;
        } else {
            for (int i = 0; i < aliases.length; i++) {
                if (match_aux(aliases[i].name, 0, this.name, 0)) {
                    font = aliases[i].font;
                    lfname = font.lfname;
                }
            }
            if (lfname == null) {
                for (int i = 0; i < flist.length; i++) {
                    if (match_aux(flist[i].lfname, 0, this.name, 0)) {
                        font = flist[i];
                        lfname = font.lfname;
                        break;
                    }
                }
            }
            if (lfname == null) {
                int size = getScalableSize(this.name);
                if (size > 0) {
                    for (int i = 0; i < flist.length; i++) {
                        if (flist[i].getScalable()) {
                            if (match_scalable(flist[i].lfname, this.name)) {
                                font = flist[i].getScalableFont(this.name);
                                lfname = font.lfname;
                                break;
                            }
                        }
                    }
                }
            }
            if (lfname == null) {
                font = flist[0];
                lfname = font.lfname;
            }
        }
        font.getFont();
        ascent = font.getAscent();
        descent = font.getDescent();
        encoding = font.encoding;
    }

    public static void reqQueryTextExtents(Client c) throws IOException {
        int n, foo;
        boolean odd = false;
        InputOutput io = c.client;
        foo = c.data;
        if (foo != 0)
            odd = true;
        n = c.length;
        foo = io.readInt();
        c.length -= 2;
        XFont f = (XFont) XResource.lookupIDByType(foo, RT_FONT);
        if (f == null) {
            c.errorValue = foo;
            c.errorReason = 7; // BadFont;
            return;
        }
        n = n - 2;
        n *= 4;
        io.readByte(c.bbuffer, 0, n);

        if (odd)
            n -= 2;

        synchronized (io) {
            io.writeByte(1);
            if (f.encoding != null) {
                for (int i = 0; i < n; i++) {
                    c.bbuffer[i] |= 0x80;
                }
                try {
                    String s = new String(c.bbuffer, 0, n, f.encoding);
                    n = s.length();
                    s.getChars(0, n, c.cbuffer, 0);
                } catch (Exception e) {
                    LOG.error(e);
                    return;
                }
            } else {
                for (int i = 0; i < n; i++) {
                    c.cbuffer[i] = (char) c.bbuffer[i];
                }
            }

            foo = f.charsWidth(c.cbuffer, 0, n);

            io.writeByte((byte) 0);
            io.writeShort(c.seq);
            io.writeInt(0);
            io.writeShort(f.font.getMaxAscent());
            io.writeShort(f.font.getMaxDescent());
            io.writeShort(f.font.getMaxAscent());
            io.writeShort(f.font.getMaxDescent());
            io.writeInt(foo);
            io.writeInt(0);
            io.writeInt(foo);
            io.writePad(4);
            io.flush();
        }
    }

    @SuppressWarnings("unused")
    public static void reqListFontsWithInfo(Client c) throws IOException {
        int foo, n;
        int maxname;
        InputOutput io = c.client;
        n = c.length;
        maxname = io.readShort();
        foo = io.readShort();
        byte[] qqqq = null;
        String s;
        {
            qqqq = c.bbuffer;
            io.readByte(qqqq, 0, foo);
            io.readPad((-foo) & 3);
            s = new String(qqqq, 0, foo);
            qqqq = s.getBytes();
        }
        byte[] pattern = qqqq;
        byte[] bb = new byte[12];
        int count = 0;
        for (int i = 0; i < aliases.length; i++) {
            if (match_aux(aliases[i].name, 0, pattern, 0)) {
                count++;
                if (maxname < count)
                    break;
            }
        }

        if (maxname >= count) {
            for (int i = 0; i < flist.length; i++) {
                if (match_aux(flist[i].lfname, 0, pattern, 0)) {
                    count++;
                    if (maxname < count)
                        break;
                }
            }
        }
        if (maxname >= count && count == 0) {
            for (int i = 0; i < flist.length; i++) {
                if (match_scalable(flist[i].lfname, pattern)) {
                    count++;
                    if (maxname < count)
                        break;
                }
            }
        }

        synchronized (io) {
            if (count > 0) {
                for (int i = 0; i < aliases.length; i++) {
                    if (match_aux(aliases[i].name, 0, pattern, 0)) {
                        count--;
                        DDXFont font = aliases[i].font;
                        int[] prop = font.getProp();

                        io.writeByte(1);

                        io.writeByte(aliases[i].name.length);
                        io.writeShort(c.seq);
                        io.writeInt(
                                7 + (prop != null ? prop.length / 2 : 0) * 2 + (aliases[i].name.length + 3) / 4);
                        // min-bounds
                        io.writeShort(0);
                        io.writeShort(0);
                        io.writeShort(font.min_width);
                        io.writeShort(0);
                        io.writeShort(0);
                        io.writeShort(0);
                        io.writePad(4);

                        // max-bounds
                        io.writeShort(0);
                        io.writeShort(font.max_width);
                        io.writeShort(font.max_width);
                        io.writeShort(font.getMaxAscent());
                        io.writeShort(font.getMaxDescent());
                        io.writeShort(0);
                        io.writePad(4);

                        io.writeShort(font.min_char_or_byte2); // min-char-or-byte2
                        io.writeShort(font.max_char_or_byte2); // max-char-or-byte2

                        io.writeShort(font.default_char); // default-char

                        io.writeShort(prop != null ? prop.length / 2 : 0); // m

                        io.writeByte(0); // draw-direction
                        io.writeByte(font.min_byte1); // min-byte1
                        io.writeByte(font.max_byte1); // max-byte1
                        io.writeByte(0); // all-char-exists

                        io.writeShort(font.getMaxAscent()); // font-ascent
                        io.writeShort(font.getMaxDescent()); // font-descent
                        io.writeInt(count); // reply-hint

                        // property 
                        if (prop != null) {
                            for (int j = 0; j < prop.length; j++) {
                                io.writeInt(prop[j]);
                            }
                        }

                        io.writeByte(aliases[i].name);
                        io.writePad((-aliases[i].name.length) & 3);

                        if (count == 0)
                            break;
                    }
                }

                if (count > 0) {
                    for (int i = 0; i < flist.length; i++) {
                        if (match_aux(flist[i].lfname, 0, pattern, 0)) {
                            count--;

                            DDXFont font = flist[i];
                            int[] prop = font.getProp();

                            io.writeByte(1);

                            io.writeByte(font.lfname.length);
                            io.writeShort(c.seq);
                            io.writeInt(
                                    7 + (prop != null ? prop.length / 2 : 0) * 2 + (font.lfname.length + 3) / 4);

                            io.writeShort(0);
                            io.writeShort(0);
                            io.writeShort(font.min_width);
                            io.writeShort(0);
                            io.writeShort(0);
                            io.writeShort(0);
                            io.writePad(4);

                            // max-bounds
                            io.writeShort(0); // left-side-bearing
                            io.writeShort(font.max_width); // right-side-bearing
                            io.writeShort(font.max_width); // character-width
                            io.writeShort(font.getMaxAscent()); // ascent
                            io.writeShort(font.getMaxDescent()); // descent
                            io.writeShort(0); // attribute
                            io.writePad(4);

                            io.writeShort(font.min_char_or_byte2); // min-char-or-byte2
                            io.writeShort(font.max_char_or_byte2); // max-char-or-byte2

                            io.writeShort(font.default_char); // default-char
                            io.writeShort(prop != null ? prop.length / 2 : 0); // m
                            io.writeByte(0); // draw-direction
                            io.writeByte(font.min_byte1); // min-byte1
                            io.writeByte(font.max_byte1); // max-byte1
                            io.writeByte(0); // all-char-exists
                            io.writeShort(font.getMaxAscent()); // font-ascent
                            io.writeShort(font.getMaxDescent()); // font-descent
                            io.writeInt(count); // reply-hint

                            if (prop != null) {
                                for (int j = 0; j < prop.length; j++) {
                                    io.writeInt(prop[j]);
                                }
                            }

                            io.writeByte(font.lfname);
                            io.writePad((-font.lfname.length) & 3);

                            if (count == 0)
                                break;
                        }
                    }
                }

                if (count > 0) {
                    for (int i = 0; i < flist.length; i++) {
                        if (match_scalable(flist[i].lfname, pattern)) {
                            count--;

                            DDXFont font = flist[i].getScalableFont(pattern);
                            int[] prop = font.getProp();

                            io.writeByte(1);

                            io.writeByte(font.lfname.length);
                            io.writeShort(c.seq);
                            io.writeInt(
                                    7 + (prop != null ? prop.length / 2 : 0) * 2 + (font.lfname.length + 3) / 4);

                            // min-bounds
                            io.writeShort(0); // left-side-bearing 
                            io.writeShort(0); // right-side-bearing
                            io.writeShort(font.min_width); // character-width
                            io.writeShort(0); // ascent
                            io.writeShort(0); // descent
                            io.writeShort(0); // attribute
                            io.writePad(4);

                            // max-bounds
                            io.writeShort(0); // left-side-bearing
                            io.writeShort(font.max_width); // right-side-bearing
                            io.writeShort(font.max_width); // character-width
                            io.writeShort(font.getMaxAscent()); // ascent
                            io.writeShort(font.getMaxDescent()); // descent
                            io.writeShort(0); // attribute
                            io.writePad(4);

                            io.writeShort(font.min_char_or_byte2); // min-char-or-byte2
                            io.writeShort(font.max_char_or_byte2); // max-char-or-byte2
                            io.writeShort(font.default_char); // default-char

                            io.writeShort(prop != null ? prop.length / 2 : 0); // m

                            io.writeByte(0); // draw-direction
                            io.writeByte(font.min_byte1); // min-byte1
                            io.writeByte(font.max_byte1); // max-byte1
                            io.writeByte(0); // all-char-exists

                            io.writeShort(font.getMaxAscent()); // font-ascent
                            io.writeShort(font.getMaxDescent()); // font-descent
                            io.writeInt(count); // reply-hint

                            // property 
                            if (prop != null) {
                                for (int j = 0; j < prop.length; j++) {
                                    io.writeInt(prop[j]);
                                }
                            }

                            io.writeByte(font.lfname);
                            io.writePad((-font.lfname.length) & 3);

                            if (count == 0)
                                break;
                        }
                    }
                }
            }

            io.writeByte(1);
            io.writeByte(0);
            io.writeShort(c.seq);
            io.writeInt(7);
            io.writePad(52);
            io.flush();
        }
    }

    @SuppressWarnings("unused")
    public static void reqSetFontPath(Client c) throws IOException {
        int foo, n;
        InputOutput io = c.client;

        n = c.length;
        foo = io.readShort();
        io.readPad(2);
        byte[][] path;
        path = new byte[foo][];
        int count = 0;
        for (int i = 0; i < path.length; i++) {
            foo = io.readByte();
            count += (1 + foo);
            path[i] = new byte[foo];
            io.readByte(path[i], 0, foo);
        }
        io.readPad((-count) & 3);
        synchronized (XFont.class) {
            fpath = path;
        }
    }

    @SuppressWarnings("unused")
    public static void reqGetFontPath(Client c) throws IOException {
        int foo, n;
        InputOutput io = c.client;
        foo = c.length;

        synchronized (io) {
            io.writeByte(1);
            int length = 0;
            for (int i = 0; i < fpath.length; i++) {
                length += (1 + fpath[i].length);
            }
            io.writePad(1);
            io.writeShort(c.seq);
            io.writeInt((length + 3) / 4);
            io.writeShort(fpath.length);
            io.writePad(22);

            for (int i = 0; i < fpath.length; i++) {
                io.writeByte(fpath[i].length);
                io.writeByte(fpath[i]);
            }
            io.writePad((-length) & 3);
            io.flush();
        }
    }

    @SuppressWarnings("unused")
    public static void reqListFonts(Client c) throws IOException {
        int foo, n;
        int maxname;
        InputOutput io = c.client;
        n = c.length;
        maxname = foo = io.readShort();
        foo = io.readShort();
        byte[] pattern = null;
        {
            io.readByte(c.bbuffer, 0, foo);
            io.readPad((-foo) & 3);
            for (int i = 0; i < foo; i++) {
                if ('A' <= c.bbuffer[i] && c.bbuffer[i] <= 'Z')
                    c.bbuffer[i] = (byte) ('a' + c.bbuffer[i] - 'A');
            }
            String s = new String(c.bbuffer, 0, foo);
            pattern = s.getBytes();
        }

        synchronized (io) {
            io.writeByte(1);

            int count = 0;
            int length = 0;

            for (int i = 0; i < aliases.length; i++) {
                if (match_aux(aliases[i].name, 0, pattern, 0)) {
                    count++;
                    length += (1 + aliases[i].name.length);
                    if (maxname < count)
                        break;
                }
            }
            if (maxname >= count) {
                for (int i = 0; i < flist.length; i++) {
                    if (match_aux(flist[i].lfname, 0, pattern, 0)) {
                        count++;
                        length += (1 + flist[i].lfname.length);
                        if (maxname < count)
                            break;
                    }
                }
            }
            if (maxname >= count && count == 0) {
                for (int i = 0; i < flist.length; i++) {
                    if (match_scalable(flist[i].lfname, pattern)) {
                        count++;
                        byte[] tmp = XFont.genScaleName(flist[i].lfname, pattern);
                        length += (1 + tmp.length);
                        if (maxname < count)
                            break;
                    }
                }
            }

            io.writePad(1);
            io.writeShort(c.seq);
            io.writeInt((length + 3) / 4);
            io.writeShort(count);
            io.writePad(22);

            if (count > 0) {
                for (int i = 0; i < aliases.length; i++) {
                    if (match_aux(aliases[i].name, 0, pattern, 0)) {
                        count--;
                        io.writeByte(aliases[i].name.length);
                        io.writeByte(aliases[i].name);
                        if (count == 0)
                            break;
                    }
                }
            }
            if (count > 0) {
                for (int i = 0; i < flist.length; i++) {
                    if (match_aux(flist[i].lfname, 0, pattern, 0)) {
                        count--;
                        io.writeByte(flist[i].lfname.length);
                        io.writeByte(flist[i].lfname);
                        if (count == 0)
                            break;
                    }
                }
            }
            if (count > 0) {
                for (int i = 0; i < flist.length; i++) {
                    if (match_scalable(flist[i].lfname, pattern)) {
                        count--;
                        byte[] tmp = XFont.genScaleName(flist[i].lfname, pattern);
                        io.writeByte(tmp.length);
                        io.writeByte(tmp);
                        if (count == 0)
                            break;
                    }
                }
            }
            io.writePad((-length) & 3);
            io.flush();
        }
    }

    public static void reqCloseFont(Client c) throws IOException {
        int foo;
        InputOutput io = c.client;
        foo = c.length;
        foo = io.readInt();
        XResource.freeResource(foo, XResource.RT_NONE);
    }

    void delete() throws IOException {
        name = null;
        lfname = null;
        encoding = null;
        if (font != null)
            font.delete();
        font = null;
    }

    @SuppressWarnings("unused")
    public static void reqOpenFont(Client c) throws IOException {
        int foo;
        int n;
        int fid;
        InputOutput io = c.client;
        n = c.length;
        foo = io.readInt();
        fid = foo;
        foo = io.readShort();
        io.readPad(2);
        byte[] qqqq = null;
        String s;
        {
            qqqq = c.bbuffer;
            io.readByte(qqqq, 0, foo);
            io.readPad((-foo) & 3);
            for (int i = 0; i < foo; i++) {
                if ('A' <= qqqq[i] && qqqq[i] <= 'Z')
                    qqqq[i] = (byte) ('a' + qqqq[i] - 'A');
            }
            s = new String(qqqq, 0, foo);
        }

        try {
            XFont f = new XFont(fid, s);
            XResource.add(f);
        } catch (Exception e) {
            //System.out.println(e);
        }
    }

    @SuppressWarnings("unused")
    public static void reqQueryFont(Client c) throws IOException {
        int foo;
        int n;
        InputOutput io = c.client;
        foo = io.readInt();
        c.length -= 2;
        XFont f = (XFont) XResource.lookupIDByType(foo, XResource.RT_FONT);
        if (f == null) {
            c.errorValue = foo;
            c.errorReason = 7; // BadFont
            return;
        }

        int nn;
        int[] prop = f.getProp();
        boolean hascinfo = f.hasCharInfo();

        synchronized (io) {
            io.writeByte(1);
            io.writePad(1);
            io.writeShort(c.seq);
            io.writeInt(7 + (prop != null ? prop.length / 2 : 0) * 2
                    + (hascinfo ? (f.font.max_char_or_byte2 - f.font.min_char_or_byte2 + 1) * 3 : 0));

            // min-bounds
            io.writeShort(0); // left-side-bearing
            io.writeShort(0); // right-side-bearing
            io.writeShort(f.font.min_width); // character-width
            io.writeShort(0); // ascent
            io.writeShort(0); // descent
            io.writeShort(0); // attribute
            io.writePad(4);

            // max-bounds
            io.writeShort(0); // left-side-bearing
            io.writeShort(f.font.max_width); // right-side-bearing
            io.writeShort(f.font.max_width); // character-width
            io.writeShort(f.font.getMaxAscent()); // ascent
            io.writeShort(f.font.getMaxDescent()); // descent
            io.writeShort(0); // attribute
            io.writePad(4);

            io.writeShort(f.font.min_char_or_byte2); // min-char-or-byte2
            io.writeShort(f.font.max_char_or_byte2); // max-char-or-byte2

            io.writeShort(f.font.default_char); // default-char
            io.writeShort(prop != null ? prop.length / 2 : 0);

            io.writeByte(0); // draw direction
            io.writeByte(f.font.min_byte1); // min-byte1
            io.writeByte(f.font.max_byte1); // max-byte1
            io.writeByte(0); // all char exist

            io.writeShort(f.font.getMaxAscent());
            io.writeShort(f.font.getMaxDescent());
            if (hascinfo) {
                io.writeInt(f.font.max_char_or_byte2 - f.font.min_char_or_byte2 + 1); // m 
            } else {
                io.writeInt(0); // m 
            }

            if (prop != null) {
                for (int i = 0; i < prop.length; i++) {
                    io.writeInt(prop[i]);
                }
            }

            if (hascinfo) {
                f.dumpCharInfo(c); // m 
            }

            io.flush();
        }
    }

    int[] getProp() {
        return font.getProp();
    }

    boolean hasCharInfo() {
        return (font.min_width != font.max_width) || font.min_byte1 == 0;
    }

    void dumpCharInfo(Client c) throws IOException {
        InputOutput io = c.client;
        char w = 0;
        int ma = font.getMaxAscent();
        int md = font.getMaxDescent();
        if (font.min_width == font.max_width) {
            w = (char) font.min_width;
            for (int i = font.min_char_or_byte2; i <= font.max_char_or_byte2; i++) {
                io.writeShort(0); // left-side-bearing
                io.writeShort(w); // right-side-bearing
                io.writeShort(w); // character-width
                io.writeShort(ma); // ascent
                io.writeShort(md); // descent
                io.writeShort(0); // attribute
            }
            return;
        }
        if (font.encoding == null) {
            int[] widths = font.getWidths();
            for (int i = font.min_char_or_byte2; i <= font.max_char_or_byte2; i++) {
                w = (char) widths[i];
                io.writeShort(0); // left-side-bearing
                io.writeShort(w); // right-side-bearing
                io.writeShort(w); // character-width
                io.writeShort(ma); // ascent
                io.writeShort(md); // descent
                io.writeShort(0); // attribute
            }
            return;
        }
        if (font.max_char_or_byte2 <= 0xff) {
            byte[] src = new byte[1];
            char[] dst = new char[1];
            // int width;
            for (int i = font.min_char_or_byte2; i <= font.max_char_or_byte2; i++) {
                src[0] = (byte) i;
                encode(src, 0, 1, dst);
                w = (char) font.charWidth(dst[0]);
                io.writeShort(0); // left-side-bearing
                io.writeShort(w); // right-side-bearing
                io.writeShort(w); // character-width
                io.writeShort(ma); // ascent
                io.writeShort(md); // descent
                io.writeShort(0); // attribute
            }
            return;
        } else {
            byte[] src = new byte[2];
            char[] dst = new char[1];
            // int width;
            for (int i = font.min_char_or_byte2; i <= font.max_char_or_byte2; i++) {
                src[0] = (byte) (i >> 8);
                src[1] = (byte) (i);
                encode(src, 0, 2, dst);
                w = (char) font.charWidth(dst[0]);
                io.writeShort(0); // left-side-bearing
                io.writeShort(w); // right-side-bearing
                io.writeShort(w); // character-width
                io.writeShort(ma); // ascent
                io.writeShort(md); // descent
                io.writeShort(0); // attribute
            }
            return;
        }
    }

    public int encode(byte[] bbuffer, int start, int len, char[] cbuffer) {
        if (font.charset == null) {
            return 0;
        }
        return font.charset.encode(bbuffer, start, len, cbuffer);
    }
}

class Alias {
    byte[] name;
    DDXFont font;

    Alias(byte[] n, DDXFont f) {
        this.name = n;
        this.font = f;
    }
}