diff options
Diffstat (limited to 'tools/sci')
-rw-r--r-- | tools/sci/5x8.font | 2307 | ||||
-rw-r--r-- | tools/sci/6x10.font | 2819 | ||||
-rw-r--r-- | tools/sci/bdf.cpp | 7434 | ||||
-rw-r--r-- | tools/sci/bdf.h | 675 | ||||
-rw-r--r-- | tools/sci/bdfP.h | 142 | ||||
-rw-r--r-- | tools/sci/bdfgname.cpp | 439 | ||||
-rw-r--r-- | tools/sci/bdfgrid.cpp | 3515 | ||||
-rw-r--r-- | tools/sci/bdftofont.cpp | 177 | ||||
-rw-r--r-- | tools/sci/classes.cpp | 51 | ||||
-rw-r--r-- | tools/sci/fonttoc.cpp | 256 | ||||
-rw-r--r-- | tools/sci/graphics_png.h | 112 | ||||
-rw-r--r-- | tools/sci/listwords.cpp | 85 | ||||
-rw-r--r-- | tools/sci/musicplayer.cpp | 103 | ||||
-rw-r--r-- | tools/sci/old_objects.cpp | 679 | ||||
-rw-r--r-- | tools/sci/old_objects.h | 72 | ||||
-rw-r--r-- | tools/sci/scidisasm.cpp | 987 | ||||
-rw-r--r-- | tools/sci/scipack.cpp | 208 | ||||
-rw-r--r-- | tools/sci/sciunpack.cpp | 473 | ||||
-rw-r--r-- | tools/sci/sciunpack.h | 68 | ||||
-rw-r--r-- | tools/sci/scriptdump.cpp | 45 | ||||
-rw-r--r-- | tools/sci/vocabdump.cpp | 70 |
21 files changed, 20717 insertions, 0 deletions
diff --git a/tools/sci/5x8.font b/tools/sci/5x8.font new file mode 100644 index 0000000000..53fc58c70d --- /dev/null +++ b/tools/sci/5x8.font @@ -0,0 +1,2307 @@ +# 256 8 +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x00 ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x01 ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x02 ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x03 ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x04 ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x05 ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x06 ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x07 ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x08 ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x09 ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x0a ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x0b ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x0c ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x0d ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x0e ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x0f ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x10 ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x11 ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x12 ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x13 ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x14 ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x15 ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x16 ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x17 ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x18 ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x19 ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x1a ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x1b ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x1c ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x1d ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x1e ('.') */ +..... +#.#.. +...#. +#.... +...#. +#.... +.#.#. +..... +---- 0x1f ('.') */ +..... +..... +..... +..... +..... +..... +..... +..... +---- 0x20 (' ') */ +.. +#. +#. +#. +#. +.. +#. +.. +---- 0x21 ('!') */ +.... +#.#. +#.#. +.... +.... +.... +.... +.... +---- 0x22 ('"') */ +.#.#.. +.#.#.. +#####. +.#.#.. +#####. +.#.#.. +.#.#.. +...... +---- 0x23 ('#') */ +..#... +.###.. +#.#... +.###.. +..#.#. +.###.. +..#... +...... +---- 0x24 ('$') */ +...... +##..#. +#..#.. +..#... +.#..#. +#..##. +...... +...... +---- 0x25 ('%') */ +.#.... +#.#... +#.#... +.#.... +#.###. +#..#.. +.##.#. +...... +---- 0x26 ('&') */ +.. +#. +#. +.. +.. +.. +.. +.. +---- 0x27 (''') */ +... +.#. +#.. +#.. +#.. +#.. +.#. +... +---- 0x28 ('(') */ +... +#.. +.#. +.#. +.#. +.#. +#.. +... +---- 0x29 (')') */ +..... +..... +#..#. +.##.. +####. +.##.. +#..#. +..... +---- 0x2a ('*') */ +...... +...... +..#... +..#... +#####. +..#... +..#... +...... +---- 0x2b ('+') */ +... +... +... +... +... +.#. +.#. +#.. +---- 0x2c (',') */ +..... +..... +..... +..... +####. +..... +..... +..... +---- 0x2d ('-') */ +.. +.. +.. +.. +.. +.. +#. +.. +---- 0x2e ('.') */ +....... +.....#. +....#.. +...#... +..#.... +.#..... +#...... +....... +---- 0x2f ('/') */ +..... +.##.. +#..#. +#..#. +#..#. +#..#. +.##.. +..... +---- 0x30 ('0') */ +.... +.#.. +##.. +.#.. +.#.. +.#.. +###. +.... +---- 0x31 ('1') */ +..... +.##.. +#..#. +...#. +.##.. +#.... +####. +..... +---- 0x32 ('2') */ +..... +####. +..#.. +.##.. +...#. +#..#. +.##.. +..... +---- 0x33 ('3') */ +..... +..#.. +.##.. +#.#.. +####. +..#.. +..#.. +..... +---- 0x34 ('4') */ +..... +####. +#.... +###.. +...#. +#..#. +.##.. +..... +---- 0x35 ('5') */ +..... +.##.. +#.... +###.. +#..#. +#..#. +.##.. +..... +---- 0x36 ('6') */ +..... +####. +...#. +..#.. +..#.. +.#... +.#... +..... +---- 0x37 ('7') */ +..... +.##.. +#..#. +.##.. +#..#. +#..#. +.##.. +..... +---- 0x38 ('8') */ +..... +.##.. +#..#. +#..#. +.###. +...#. +.##.. +..... +---- 0x39 ('9') */ +.. +.. +#. +.. +.. +#. +.. +.. +---- 0x3a (':') */ +... +... +.#. +... +... +.#. +.#. +#.. +---- 0x3b (';') */ +.... +..#. +.#.. +#... +#... +.#.. +..#. +.... +---- 0x3c ('<') */ +..... +..... +..... +####. +..... +####. +..... +..... +---- 0x3d ('=') */ +.... +#... +.#.. +..#. +..#. +.#.. +#... +.... +---- 0x3e ('>') */ +..... +.##.. +#..#. +...#. +..#.. +..... +..#.. +..... +---- 0x3f ('?') */ +..##.. +.#..#. +#..##. +#.#.#. +#.#.#. +#..#.. +.#.... +..##.. +---- 0x40 ('@') */ +..... +.##.. +#..#. +#..#. +####. +#..#. +#..#. +..... +---- 0x41 ('A') */ +..... +###.. +#..#. +###.. +#..#. +#..#. +###.. +..... +---- 0x42 ('B') */ +..... +.##.. +#..#. +#.... +#.... +#..#. +.##.. +..... +---- 0x43 ('C') */ +..... +###.. +#..#. +#..#. +#..#. +#..#. +###.. +..... +---- 0x44 ('D') */ +..... +####. +#.... +###.. +#.... +#.... +####. +..... +---- 0x45 ('E') */ +..... +####. +#.... +###.. +#.... +#.... +#.... +..... +---- 0x46 ('F') */ +..... +.##.. +#..#. +#.... +#.##. +#..#. +.##.. +..... +---- 0x47 ('G') */ +..... +#..#. +#..#. +####. +#..#. +#..#. +#..#. +..... +---- 0x48 ('H') */ +.... +###. +.#.. +.#.. +.#.. +.#.. +###. +.... +---- 0x49 ('I') */ +..... +.###. +..#.. +..#.. +..#.. +#.#.. +.#... +..... +---- 0x4a ('J') */ +..... +#..#. +#.#.. +##... +#.#.. +#.#.. +#..#. +..... +---- 0x4b ('K') */ +..... +#.... +#.... +#.... +#.... +#.... +####. +..... +---- 0x4c ('L') */ +...... +#...#. +##.##. +#.#.#. +#...#. +#...#. +#...#. +...... +---- 0x4d ('M') */ +..... +#..#. +##.#. +##.#. +#.##. +#.##. +#..#. +..... +---- 0x4e ('N') */ +..... +.##.. +#..#. +#..#. +#..#. +#..#. +.##.. +..... +---- 0x4f ('O') */ +..... +###.. +#..#. +#..#. +###.. +#.... +#.... +..... +---- 0x50 ('P') */ +..... +.##.. +#..#. +#..#. +#..#. +#.##. +.##.. +...#. +---- 0x51 ('Q') */ +..... +###.. +#..#. +#..#. +###.. +#..#. +#..#. +..... +---- 0x52 ('R') */ +..... +.##.. +#..#. +.#... +..#.. +#..#. +.##.. +..... +---- 0x53 ('S') */ +.... +###. +.#.. +.#.. +.#.. +.#.. +.#.. +.... +---- 0x54 ('T') */ +..... +#..#. +#..#. +#..#. +#..#. +#..#. +.##.. +..... +---- 0x55 ('U') */ +..... +#..#. +#..#. +#..#. +#..#. +#.#.. +.#... +..... +---- 0x56 ('V') */ +...... +#...#. +#...#. +#...#. +#.#.#. +##.##. +#...#. +...... +---- 0x57 ('W') */ +..... +#..#. +#..#. +.##.. +.##.. +#..#. +#..#. +..... +---- 0x58 ('X') */ +...... +#...#. +#...#. +.#.#.. +..#... +..#... +..#... +...... +---- 0x59 ('Y') */ +..... +####. +...#. +..#.. +.#... +#.... +####. +..... +---- 0x5a ('Z') */ +.... +###. +#... +#... +#... +#... +###. +.... +---- 0x5b ('[') */ +....... +#...... +.#..... +..#.... +...#... +....#.. +.....#. +....... +---- 0x5c ('\') */ +.... +###. +..#. +..#. +..#. +..#. +###. +.... +---- 0x5d (']') */ +.... +.#.. +#.#. +.... +.... +.... +.... +.... +---- 0x5e ('^') */ +.... +.... +.... +.... +.... +.... +.... +#### +---- 0x5f ('_') */ +... +#.. +.#. +... +... +... +... +... +---- 0x60 ('`') */ +..... +..... +..... +.###. +#..#. +#..#. +.###. +..... +---- 0x61 ('a') */ +..... +#.... +#.... +###.. +#..#. +#..#. +###.. +..... +---- 0x62 ('b') */ +.... +.... +.... +.##. +#... +#... +.##. +.... +---- 0x63 ('c') */ +..... +...#. +...#. +.###. +#..#. +#..#. +.###. +..... +---- 0x64 ('d') */ +..... +..... +..... +.##.. +#.##. +##... +.##.. +..... +---- 0x65 ('e') */ +..... +..#.. +.#.#. +.#... +###.. +.#... +.#... +..... +---- 0x66 ('f') */ +..... +..... +..... +.##.. +#..#. +.###. +...#. +.##.. +---- 0x67 ('g') */ +..... +#.... +#.... +###.. +#..#. +#..#. +#..#. +..... +---- 0x68 ('h') */ +.... +.#.. +.... +##.. +.#.. +.#.. +###. +.... +---- 0x69 ('i') */ +.... +..#. +.... +..#. +..#. +..#. +#.#. +.#.. +---- 0x6a ('j') */ +..... +#.... +#.... +#..#. +###.. +#..#. +#..#. +..... +---- 0x6b ('k') */ +.... +##.. +.#.. +.#.. +.#.. +.#.. +###. +.... +---- 0x6c ('l') */ +...... +...... +...... +##.#.. +#.#.#. +#.#.#. +#.#.#. +...... +---- 0x6d ('m') */ +..... +..... +..... +###.. +#..#. +#..#. +#..#. +..... +---- 0x6e ('n') */ +..... +..... +..... +.##.. +#..#. +#..#. +.##.. +..... +---- 0x6f ('o') */ +..... +..... +..... +###.. +#..#. +###.. +#.... +#.... +---- 0x70 ('p') */ +..... +..... +..... +.###. +#..#. +.###. +...#. +...#. +---- 0x71 ('q') */ +..... +..... +..... +#.#.. +##.#. +#.... +#.... +..... +---- 0x72 ('r') */ +.... +.... +.... +.##. +##.. +..#. +##.. +.... +---- 0x73 ('s') */ +..... +.#... +.#... +###.. +.#... +.#.#. +..#.. +..... +---- 0x74 ('t') */ +..... +..... +..... +#..#. +#..#. +#..#. +.###. +..... +---- 0x75 ('u') */ +.... +.... +.... +#.#. +#.#. +#.#. +.#.. +.... +---- 0x76 ('v') */ +...... +...... +...... +#...#. +#.#.#. +#.#.#. +.#.#.. +...... +---- 0x77 ('w') */ +..... +..... +..... +#..#. +.##.. +.##.. +#..#. +..... +---- 0x78 ('x') */ +..... +..... +..... +#..#. +#..#. +.###. +#..#. +.##.. +---- 0x79 ('y') */ +..... +..... +..... +####. +..#.. +.#... +####. +..... +---- 0x7a ('z') */ +..##. +.#... +..#.. +##... +..#.. +.#... +..##. +..... +---- 0x7b ('{') */ +.. +#. +#. +#. +#. +#. +#. +.. +---- 0x7c ('|') */ +##... +..#.. +.#... +..##. +.#... +..#.. +##... +..... +---- 0x7d ('}') */ +..... +.#.#. +#.#.. +..... +..... +..... +..... +..... +---- 0x7e ('~') */ +..... +..... +..... +..... +..... +..... +..... +..... +---- 0x7f ('.') */ +..... +..#.. +..... +..#.. +..#.. +..#.. +..#.. +..... +---- 0x80 ('.') */ +..... +..... +..#.. +.###. +#.#.. +#.#.. +.###. +..#.. +---- 0x81 ('.') */ +..... +..#.. +.#.#. +###.. +.#... +.#.#. +#.#.. +..... +---- 0x82 ('.') */ +..... +..... +#...# +.###. +.#.#. +.###. +#...# +..... +---- 0x83 ('.') */ +..... +#...# +.#.#. +##### +..#.. +##### +..#.. +..... +---- 0x84 ('.') */ +..#.. +..#.. +..#.. +..... +..#.. +..#.. +..#.. +..... +---- 0x85 ('.') */ +.###. +#.... +###.. +#..#. +.###. +...#. +###.. +..... +---- 0x86 ('.') */ +..... +.#.#. +..... +..... +..... +..... +..... +..... +---- 0x87 ('.') */ +..... +.###. +#.#.# +##..# +##..# +#.#.# +.###. +..... +---- 0x88 ('.') */ +..##. +.#.#. +..##. +..... +.###. +..... +..... +..... +---- 0x89 ('.') */ +..... +..... +..... +.#.#. +#.#.. +.#.#. +..... +..... +---- 0x8a ('.') */ +..... +..... +..... +..... +.###. +...#. +...#. +..... +---- 0x8b ('.') */ +..... +..... +..... +..... +.###. +..... +..... +..... +---- 0x8c ('.') */ +..... +.###. +###.# +##.## +###.# +##.## +.###. +..... +---- 0x8d ('.') */ +..... +.###. +..... +..... +..... +..... +..... +..... +---- 0x8e ('.') */ +..... +..#.. +.#.#. +..#.. +..... +..... +..... +..... +---- 0x8f ('.') */ +..... +..... +..#.. +.###. +..#.. +..... +.###. +..... +---- 0x90 ('.') */ +..#.. +.#.#. +...#. +..#.. +.###. +..... +..... +..... +---- 0x91 ('.') */ +.##.. +...#. +.##.. +...#. +.##.. +..... +..... +..... +---- 0x92 ('.') */ +..... +..#.. +.#... +..... +..... +..... +..... +..... +---- 0x93 ('.') */ +..... +..... +..... +#..#. +#..#. +#..#. +###.. +#.... +---- 0x94 ('.') */ +..... +.#### +###.# +###.# +.##.# +..#.# +..#.# +..... +---- 0x95 ('.') */ +..... +..... +..... +..... +..#.. +..... +..... +..... +---- 0x96 ('.') */ +..... +..... +..... +..... +..... +..... +..#.. +.#... +---- 0x97 ('.') */ +..#.. +.##.. +..#.. +..#.. +.###. +..... +..... +..... +---- 0x98 ('.') */ +..#.. +.#.#. +..#.. +..... +.###. +..... +..... +..... +---- 0x99 ('.') */ +..... +..... +..... +#.#.. +.#.#. +#.#.. +..... +..... +---- 0x9a ('.') */ +#.... +#.... +#.... +#.#.. +.##.. +####. +..#.. +..... +---- 0x9b ('.') */ +#.... +#.... +#.#.. +##.#. +...#. +..#.. +.###. +..... +---- 0x9c ('.') */ +#.... +.#... +#.... +.##.. +#.#.. +####. +..#.. +..... +---- 0x9d ('.') */ +..... +..#.. +..... +..#.. +.#... +.#.#. +..#.. +..... +---- 0x9e ('.') */ +.#... +..#.. +.##.. +#..#. +####. +#..#. +#..#. +..... +---- 0x9f ('.') */ +..#.. +.#... +.##.. +#..#. +####. +#..#. +#..#. +..... +---- 0xa0 ('.') */ +.##.. +#..#. +.##.. +#..#. +####. +#..#. +#..#. +..... +---- 0xa1 ('.') */ +.#.#. +#.#.. +.##.. +#..#. +####. +#..#. +#..#. +..... +---- 0xa2 ('.') */ +#..#. +..... +.##.. +#..#. +####. +#..#. +#..#. +..... +---- 0xa3 ('.') */ +.##.. +#..#. +.##.. +#..#. +####. +#..#. +#..#. +..... +---- 0xa4 ('.') */ +..... +.###. +#.#.. +#.#.. +####. +#.#.. +#.##. +..... +---- 0xa5 ('.') */ +..... +.##.. +#..#. +#.... +#.... +#..#. +.##.. +.#... +---- 0xa6 ('.') */ +.#... +..#.. +####. +#.... +###.. +#.... +####. +..... +---- 0xa7 ('.') */ +..#.. +.#... +####. +#.... +###.. +#.... +####. +..... +---- 0xa8 ('.') */ +.##.. +#..#. +####. +#.... +###.. +#.... +####. +..... +---- 0xa9 ('.') */ +#..#. +..... +####. +#.... +###.. +#.... +####. +..... +---- 0xaa ('.') */ +.#... +..#.. +.###. +..#.. +..#.. +..#.. +.###. +..... +---- 0xab ('.') */ +...#. +..#.. +.###. +..#.. +..#.. +..#.. +.###. +..... +---- 0xac ('.') */ +..#.. +.#.#. +.###. +..#.. +..#.. +..#.. +.###. +..... +---- 0xad ('.') */ +.#.#. +..... +.###. +..#.. +..#.. +..#.. +.###. +..... +---- 0xae ('.') */ +..... +.###. +.#..# +###.# +.#..# +.#..# +.###. +..... +---- 0xaf ('.') */ +.#.#. +#.#.. +#..#. +##.#. +#.##. +#..#. +#..#. +..... +---- 0xb0 ('.') */ +.#... +..#.. +.##.. +#..#. +#..#. +#..#. +.##.. +..... +---- 0xb1 ('.') */ +..#.. +.#... +.##.. +#..#. +#..#. +#..#. +.##.. +..... +---- 0xb2 ('.') */ +.##.. +#..#. +.##.. +#..#. +#..#. +#..#. +.##.. +..... +---- 0xb3 ('.') */ +.#.#. +#.#.. +.##.. +#..#. +#..#. +#..#. +.##.. +..... +---- 0xb4 ('.') */ +#..#. +..... +.##.. +#..#. +#..#. +#..#. +.##.. +..... +---- 0xb5 ('.') */ +..... +..... +..... +..... +.#.#. +..#.. +.#.#. +..... +---- 0xb6 ('.') */ +..... +.###. +#.##. +#.##. +##.#. +##.#. +###.. +..... +---- 0xb7 ('.') */ +.#... +..#.. +#..#. +#..#. +#..#. +#..#. +.##.. +..... +---- 0xb8 ('.') */ +..#.. +.#... +#..#. +#..#. +#..#. +#..#. +.##.. +..... +---- 0xb9 ('.') */ +.##.. +#..#. +#..#. +#..#. +#..#. +#..#. +.##.. +..... +---- 0xba ('.') */ +#..#. +..... +#..#. +#..#. +#..#. +#..#. +.##.. +..... +---- 0xbb ('.') */ +...#. +..#.. +#...# +.#.#. +..#.. +..#.. +..#.. +..... +---- 0xbc ('.') */ +..... +#.... +###.. +#..#. +#..#. +###.. +#.... +..... +---- 0xbd ('.') */ +..... +.##.. +#..#. +#.#.. +#.#.. +#..#. +#.#.. +..... +---- 0xbe ('.') */ +.#... +..#.. +..... +.###. +#..#. +#..#. +.###. +..... +---- 0xbf ('.') */ +..#.. +.#... +..... +.###. +#..#. +#..#. +.###. +..... +---- 0xc0 ('.') */ +..#.. +.#.#. +..... +.###. +#..#. +#..#. +.###. +..... +---- 0xc1 ('.') */ +.#.#. +#.#.. +..... +.###. +#..#. +#..#. +.###. +..... +---- 0xc2 ('.') */ +..... +.#.#. +..... +.###. +#..#. +#..#. +.###. +..... +---- 0xc3 ('.') */ +.##.. +#..#. +.##.. +.###. +#..#. +#..#. +.###. +..... +---- 0xc4 ('.') */ +..... +..... +..... +####. +.##.# +#.##. +.#### +..... +---- 0xc5 ('.') */ +..... +..... +..... +..##. +.#... +.#... +..##. +..#.. +---- 0xc6 ('.') */ +.#... +..#.. +..... +.##.. +#.##. +##... +.##.. +..... +---- 0xc7 ('.') */ +..#.. +.#... +..... +.##.. +#.##. +##... +.##.. +..... +---- 0xc8 ('.') */ +.##.. +#..#. +..... +.##.. +#.##. +##... +.##.. +..... +---- 0xc9 ('.') */ +..... +.#.#. +..... +.##.. +#.##. +##... +.##.. +..... +---- 0xca ('.') */ +.#... +..#.. +..... +.##.. +..#.. +..#.. +.###. +..... +---- 0xcb ('.') */ +...#. +..#.. +..... +.##.. +..#.. +..#.. +.###. +..... +---- 0xcc ('.') */ +..#.. +.#.#. +..... +.##.. +..#.. +..#.. +.###. +..... +---- 0xcd ('.') */ +..... +.#.#. +..... +.##.. +..#.. +..#.. +.###. +..... +---- 0xce ('.') */ +#.#.. +.#... +#.#.. +...#. +.###. +#..#. +.##.. +..... +---- 0xcf ('.') */ +.#.#. +#.#.. +..... +###.. +#..#. +#..#. +#..#. +..... +---- 0xd0 ('.') */ +.#... +..#.. +..... +.##.. +#..#. +#..#. +.##.. +..... +---- 0xd1 ('.') */ +..#.. +.#... +..... +.##.. +#..#. +#..#. +.##.. +..... +---- 0xd2 ('.') */ +.##.. +#..#. +..... +.##.. +#..#. +#..#. +.##.. +..... +---- 0xd3 ('.') */ +.#.#. +#.#.. +..... +.##.. +#..#. +#..#. +.##.. +..... +---- 0xd4 ('.') */ +..... +#..#. +..... +.##.. +#..#. +#..#. +.##.. +..... +---- 0xd5 ('.') */ +..... +..... +..#.. +..... +.###. +..... +..#.. +..... +---- 0xd6 ('.') */ +..... +..... +..... +.###. +#.##. +##.#. +###.. +..... +---- 0xd7 ('.') */ +.#... +..#.. +..... +#..#. +#..#. +#..#. +.###. +..... +---- 0xd8 ('.') */ +..#.. +.#... +..... +#..#. +#..#. +#..#. +.###. +..... +---- 0xd9 ('.') */ +.##.. +#..#. +..... +#..#. +#..#. +#..#. +.###. +..... +---- 0xda ('.') */ +..... +#..#. +..... +#..#. +#..#. +#..#. +.###. +..... +---- 0xdb ('.') */ +..#.. +.#... +..... +#..#. +#..#. +.###. +#..#. +.##.. +---- 0xdc ('.') */ +..... +#.... +#.... +###.. +#..#. +###.. +#.... +#.... +---- 0xdd ('.') */ +..... +#..#. +..... +#..#. +#..#. +.###. +#..#. +.##.. +---- 0xde ('.') */ +####. +..... +.##.. +#..#. +####. +#..#. +#..#. +..... +---- 0xdf ('.') */ +..... +####. +..... +.###. +#..#. +#..#. +.###. +..... +---- 0xe0 ('.') */ +#..#. +.##.. +.##.. +#..#. +####. +#..#. +#..#. +..... +---- 0xe1 ('.') */ +#..#. +.##.. +..... +.###. +#..#. +#..#. +.###. +..... +---- 0xe2 ('.') */ +..... +.##.. +#..#. +#..#. +####. +#..#. +#..#. +..##. +---- 0xe3 ('.') */ +..... +..... +..... +.###. +#..#. +#..#. +.###. +..#.. +---- 0xe4 ('.') */ +..#.. +.#... +.##.. +#..#. +#.... +#..#. +.##.. +..... +---- 0xe5 ('.') */ +...#. +..#.. +..... +..##. +.#... +.#... +..##. +..... +---- 0xe6 ('.') */ +.##.. +#..#. +.##.. +#..#. +#.... +#..#. +.##.. +..... +---- 0xe7 ('.') */ +.##.. +#..#. +..... +.##.. +#.... +#.... +.##.. +..... +---- 0xe8 ('.') */ +.#... +..... +.##.. +#..#. +#.... +#..#. +.##.. +..... +---- 0xe9 ('.') */ +..... +..#.. +..... +..##. +.#... +.#... +..##. +..... +---- 0xea ('.') */ +#..#. +.##.. +.##.. +#..#. +#.... +#..#. +.##.. +..... +---- 0xeb ('.') */ +#..#. +.##.. +..... +.##.. +#.... +#.... +.##.. +..... +---- 0xec ('.') */ +#..#. +.##.. +###.. +#..#. +#..#. +#..#. +###.. +..... +---- 0xed ('.') */ +#.#.. +.#.#. +...#. +.###. +#..#. +#..#. +.###. +..... +---- 0xee ('.') */ +..... +.###. +.#..# +###.# +.#..# +.#..# +.###. +..... +---- 0xef ('.') */ +..... +..#.. +.###. +..#.. +.##.. +#.#.. +.##.. +..... +---- 0xf0 ('.') */ +####. +..... +####. +#.... +###.. +#.... +####. +..... +---- 0xf1 ('.') */ +..... +####. +..... +.##.. +#.##. +##... +.##.. +..... +---- 0xf2 ('.') */ +#..#. +.##.. +####. +#.... +###.. +#.... +####. +..... +---- 0xf3 ('.') */ +#..#. +.##.. +..... +.##.. +#.##. +##... +.##.. +..... +---- 0xf4 ('.') */ +.##.. +..... +####. +#.... +###.. +#.... +####. +..... +---- 0xf5 ('.') */ +..... +.##.. +..... +.##.. +#.##. +##... +.##.. +..... +---- 0xf6 ('.') */ +..... +####. +#.... +###.. +#.... +#.... +####. +..#.. +---- 0xf7 ('.') */ +..... +..... +..... +.##.. +#.##. +##... +.##.. +..#.. +---- 0xf8 ('.') */ +#..#. +.##.. +####. +#.... +###.. +#.... +####. +..... +---- 0xf9 ('.') */ +#..#. +.##.. +..... +.##.. +#.##. +##... +.##.. +..... +---- 0xfa ('.') */ +.##.. +#..#. +.###. +#.... +#.##. +#..#. +.##.. +..... +---- 0xfb ('.') */ +.##.. +#..#. +..... +.##.. +#..#. +.###. +...#. +.##.. +---- 0xfc ('.') */ +#..#. +.##.. +.###. +#.... +#.##. +#..#. +.##.. +..... +---- 0xfd ('.') */ +#..#. +.##.. +..... +.##.. +#..#. +.###. +...#. +.##.. +---- 0xfe ('.') */ +.##.. +..... +.###. +#.... +#.##. +#..#. +.##.. +..... +---- 0xff ('.') */ + + diff --git a/tools/sci/6x10.font b/tools/sci/6x10.font new file mode 100644 index 0000000000..c672d07b98 --- /dev/null +++ b/tools/sci/6x10.font @@ -0,0 +1,2819 @@ +# 256 10 +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x00 ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x01 ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x02 ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x03 ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x04 ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x05 ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x06 ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x07 ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x08 ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x09 ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x0a ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x0b ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x0c ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x0d ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x0e ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x0f ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x10 ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x11 ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x12 ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x13 ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x14 ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x15 ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x16 ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x17 ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x18 ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x19 ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x1a ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x1b ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x1c ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x1d ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x1e ('.') */ +...... +#.#.#. +...... +#...#. +...... +#...#. +...... +#.#.#. +...... +...... +---- 0x1f ('.') */ +.... +.... +.... +.... +.... +.... +.... +.... +.... +.... +---- 0x20 (' ') */ +.... +.#.. +.#.. +.#.. +.#.. +.#.. +.... +.#.. +.... +.... +---- 0x21 ('!') */ +.... +#.#. +#.#. +#.#. +.... +.... +.... +.... +.... +.... +---- 0x22 ('"') */ +...... +.#.#.. +.#.#.. +#####. +.#.#.. +#####. +.#.#.. +.#.#.. +...... +...... +---- 0x23 ('#') */ +...... +..#... +.###.. +#.#... +.###.. +..#.#. +.###.. +..#... +...... +...... +---- 0x24 ('$') */ +...... +.#..#. +#.#.#. +.#.#.. +..#... +.#.#.. +#.#.#. +#..#.. +...... +...... +---- 0x25 ('%') */ +...... +.#.... +#.#... +#.#... +.#.... +#.#.#. +#..#.. +.##.#. +...... +...... +---- 0x26 ('&') */ +.. +#. +#. +#. +.. +.. +.. +.. +.. +.. +---- 0x27 (''') */ +..... +...#. +..#.. +.#... +.#... +.#... +..#.. +...#. +..... +..... +---- 0x28 ('(') */ +..... +.#... +..#.. +...#. +...#. +...#. +..#.. +.#... +..... +..... +---- 0x29 (')') */ +...... +...... +#...#. +.#.#.. +#####. +.#.#.. +#...#. +...... +...... +...... +---- 0x2a ('*') */ +...... +...... +..#... +..#... +#####. +..#... +..#... +...... +...... +...... +---- 0x2b ('+') */ +.... +.... +.... +.... +.... +.... +.##. +.#.. +#... +.... +---- 0x2c (',') */ +...... +...... +...... +...... +#####. +...... +...... +...... +...... +...... +---- 0x2d ('-') */ +..... +..... +..... +..... +..... +..... +.##.. +.##.. +..... +..... +---- 0x2e ('.') */ +....... +......# +.....#. +....#.. +...#... +..#.... +.#..... +#...... +....... +....... +---- 0x2f ('/') */ +...... +..#... +.#.#.. +#...#. +#...#. +#...#. +.#.#.. +..#... +...... +...... +---- 0x30 ('0') */ +.... +.#.. +##.. +.#.. +.#.. +.#.. +.#.. +###. +.... +.... +---- 0x31 ('1') */ +...... +.###.. +#...#. +....#. +..##.. +.#.... +#..... +#####. +...... +...... +---- 0x32 ('2') */ +...... +#####. +....#. +...#.. +..##.. +....#. +#...#. +.###.. +...... +...... +---- 0x33 ('3') */ +...... +...#.. +..##.. +.#.#.. +#..#.. +#####. +...#.. +...#.. +...... +...... +---- 0x34 ('4') */ +...... +#####. +#..... +#.##.. +##..#. +....#. +#...#. +.###.. +...... +...... +---- 0x35 ('5') */ +...... +..##.. +.#.... +#..... +#.##.. +##..#. +#...#. +.###.. +...... +...... +---- 0x36 ('6') */ +...... +#####. +....#. +...#.. +...#.. +..#... +.#.... +.#.... +...... +...... +---- 0x37 ('7') */ +...... +.###.. +#...#. +#...#. +.###.. +#...#. +#...#. +.###.. +...... +...... +---- 0x38 ('8') */ +...... +.###.. +#...#. +#..##. +.##.#. +....#. +...#.. +.##... +...... +...... +---- 0x39 ('9') */ +..... +..... +.##.. +.##.. +..... +..... +.##.. +.##.. +..... +..... +---- 0x3a (':') */ +..... +..... +.##.. +.##.. +..... +..... +.##.. +.#... +#.... +..... +---- 0x3b (';') */ +...... +....#. +...#.. +..#... +.#.... +..#... +...#.. +....#. +...... +...... +---- 0x3c ('<') */ +...... +...... +...... +#####. +...... +#####. +...... +...... +...... +...... +---- 0x3d ('=') */ +...... +.#.... +..#... +...#.. +....#. +...#.. +..#... +.#.... +...... +...... +---- 0x3e ('>') */ +...... +.###.. +#...#. +...#.. +..#... +..#... +...... +..#... +...... +...... +---- 0x3f ('?') */ +...... +.###.. +#...#. +#..##. +#.#.#. +#.##.. +#..... +.###.. +...... +...... +---- 0x40 ('@') */ +...... +..#... +.#.#.. +#...#. +#...#. +#####. +#...#. +#...#. +...... +...... +---- 0x41 ('A') */ +...... +####.. +.#..#. +.#..#. +.###.. +.#..#. +.#..#. +####.. +...... +...... +---- 0x42 ('B') */ +...... +.###.. +#...#. +#..... +#..... +#..... +#...#. +.###.. +...... +...... +---- 0x43 ('C') */ +...... +####.. +.#..#. +.#..#. +.#..#. +.#..#. +.#..#. +####.. +...... +...... +---- 0x44 ('D') */ +...... +#####. +#..... +#..... +####.. +#..... +#..... +#####. +...... +...... +---- 0x45 ('E') */ +...... +#####. +#..... +#..... +####.. +#..... +#..... +#..... +...... +...... +---- 0x46 ('F') */ +...... +.###.. +#...#. +#..... +#..... +#..##. +#...#. +.###.. +...... +...... +---- 0x47 ('G') */ +...... +#...#. +#...#. +#...#. +#####. +#...#. +#...#. +#...#. +...... +...... +---- 0x48 ('H') */ +.... +###. +.#.. +.#.. +.#.. +.#.. +.#.. +###. +.... +.... +---- 0x49 ('I') */ +...... +..###. +...#.. +...#.. +...#.. +...#.. +#..#.. +.##... +...... +...... +---- 0x4a ('J') */ +...... +#...#. +#..#.. +#.#... +##.... +#.#... +#..#.. +#...#. +...... +...... +---- 0x4b ('K') */ +...... +#..... +#..... +#..... +#..... +#..... +#..... +#####. +...... +...... +---- 0x4c ('L') */ +...... +#...#. +#...#. +##.##. +#.#.#. +#...#. +#...#. +#...#. +...... +...... +---- 0x4d ('M') */ +...... +#...#. +#...#. +##..#. +#.#.#. +#..##. +#...#. +#...#. +...... +...... +---- 0x4e ('N') */ +...... +.###.. +#...#. +#...#. +#...#. +#...#. +#...#. +.###.. +...... +...... +---- 0x4f ('O') */ +...... +####.. +#...#. +#...#. +####.. +#..... +#..... +#..... +...... +...... +---- 0x50 ('P') */ +...... +.###.. +#...#. +#...#. +#...#. +#...#. +#.#.#. +.###.. +....#. +...... +---- 0x51 ('Q') */ +...... +####.. +#...#. +#...#. +####.. +#.#... +#..#.. +#...#. +...... +...... +---- 0x52 ('R') */ +...... +.###.. +#...#. +#..... +.###.. +....#. +#...#. +.###.. +...... +...... +---- 0x53 ('S') */ +...... +#####. +..#... +..#... +..#... +..#... +..#... +..#... +...... +...... +---- 0x54 ('T') */ +...... +#...#. +#...#. +#...#. +#...#. +#...#. +#...#. +.###.. +...... +...... +---- 0x55 ('U') */ +...... +#...#. +#...#. +#...#. +.#.#.. +.#.#.. +.#.#.. +..#... +...... +...... +---- 0x56 ('V') */ +...... +#...#. +#...#. +#...#. +#.#.#. +#.#.#. +##.##. +#...#. +...... +...... +---- 0x57 ('W') */ +...... +#...#. +#...#. +.#.#.. +..#... +.#.#.. +#...#. +#...#. +...... +...... +---- 0x58 ('X') */ +...... +#...#. +#...#. +.#.#.. +..#... +..#... +..#... +..#... +...... +...... +---- 0x59 ('Y') */ +...... +#####. +....#. +...#.. +..#... +.#.... +#..... +#####. +...... +...... +---- 0x5a ('Z') */ +..... +.###. +.#... +.#... +.#... +.#... +.#... +.###. +..... +..... +---- 0x5b ('[') */ +....... +#...... +.#..... +..#.... +...#... +....#.. +.....#. +......# +....... +....... +---- 0x5c ('\') */ +..... +.###. +...#. +...#. +...#. +...#. +...#. +.###. +..... +..... +---- 0x5d (']') */ +...... +..#... +.#.#.. +#...#. +...... +...... +...... +...... +...... +...... +---- 0x5e ('^') */ +..... +..... +..... +..... +..... +..... +..... +..... +##### +..... +---- 0x5f ('_') */ +#.. +.#. +... +... +... +... +... +... +... +... +---- 0x60 ('`') */ +...... +...... +...... +.###.. +....#. +.####. +#...#. +.####. +...... +...... +---- 0x61 ('a') */ +...... +#..... +#..... +#.##.. +##..#. +#...#. +##..#. +#.##.. +...... +...... +---- 0x62 ('b') */ +...... +...... +...... +.###.. +#...#. +#..... +#...#. +.###.. +...... +...... +---- 0x63 ('c') */ +...... +....#. +....#. +.##.#. +#..##. +#...#. +#..##. +.##.#. +...... +...... +---- 0x64 ('d') */ +...... +...... +...... +.###.. +#...#. +#####. +#..... +.###.. +...... +...... +---- 0x65 ('e') */ +...... +..##.. +.#..#. +.#.... +####.. +.#.... +.#.... +.#.... +...... +...... +---- 0x66 ('f') */ +...... +...... +...... +.####. +#...#. +#...#. +.####. +....#. +#...#. +.###.. +---- 0x67 ('g') */ +...... +#..... +#..... +#.##.. +##..#. +#...#. +#...#. +#...#. +...... +...... +---- 0x68 ('h') */ +.... +.#.. +.... +##.. +.#.. +.#.. +.#.. +###. +.... +.... +---- 0x69 ('i') */ +..... +...#. +..... +..##. +...#. +...#. +...#. +#..#. +#..#. +.##.. +---- 0x6a ('j') */ +...... +#..... +#..... +#...#. +#..#.. +###... +#..#.. +#...#. +...... +...... +---- 0x6b ('k') */ +.... +##.. +.#.. +.#.. +.#.. +.#.. +.#.. +###. +.... +.... +---- 0x6c ('l') */ +...... +...... +...... +##.#.. +#.#.#. +#.#.#. +#.#.#. +#...#. +...... +...... +---- 0x6d ('m') */ +...... +...... +...... +#.##.. +##..#. +#...#. +#...#. +#...#. +...... +...... +---- 0x6e ('n') */ +...... +...... +...... +.###.. +#...#. +#...#. +#...#. +.###.. +...... +...... +---- 0x6f ('o') */ +...... +...... +...... +#.##.. +##..#. +#...#. +##..#. +#.##.. +#..... +#..... +---- 0x70 ('p') */ +...... +...... +...... +.##.#. +#..##. +#...#. +#..##. +.##.#. +....#. +....#. +---- 0x71 ('q') */ +...... +...... +...... +#.##.. +##..#. +#..... +#..... +#..... +...... +...... +---- 0x72 ('r') */ +...... +...... +...... +.###.. +#..... +.###.. +....#. +####.. +...... +...... +---- 0x73 ('s') */ +...... +.#.... +.#.... +####.. +.#.... +.#.... +.#..#. +..##.. +...... +...... +---- 0x74 ('t') */ +...... +...... +...... +#...#. +#...#. +#...#. +#..##. +.##.#. +...... +...... +---- 0x75 ('u') */ +...... +...... +...... +#...#. +#...#. +.#.#.. +.#.#.. +..#... +...... +...... +---- 0x76 ('v') */ +...... +...... +...... +#...#. +#...#. +#.#.#. +#.#.#. +.#.#.. +...... +...... +---- 0x77 ('w') */ +...... +...... +...... +#...#. +.#.#.. +..#... +.#.#.. +#...#. +...... +...... +---- 0x78 ('x') */ +...... +...... +...... +#...#. +#...#. +#..##. +.##.#. +....#. +#...#. +.###.. +---- 0x79 ('y') */ +...... +...... +...... +#####. +...#.. +..#... +.#.... +#####. +...... +...... +---- 0x7a ('z') */ +...... +...##. +..#... +...#.. +.##... +...#.. +..#... +...##. +...... +...... +---- 0x7b ('{') */ +... +.#. +.#. +.#. +.#. +.#. +.#. +.#. +... +... +---- 0x7c ('|') */ +...... +.##... +...#.. +..#... +...##. +..#... +...#.. +.##... +...... +...... +---- 0x7d ('}') */ +...... +.#..#. +#.#.#. +#..#.. +...... +...... +...... +...... +...... +...... +---- 0x7e ('~') */ +...... +...... +...... +...... +...... +...... +...... +...... +...... +...... +---- 0x7f ('.') */ +...... +..#... +...... +..#... +..#... +..#... +..#... +..#... +...... +...... +---- 0x80 ('.') */ +...... +...... +..#... +.####. +#.#... +#.#... +#.#... +.####. +..#... +...... +---- 0x81 ('.') */ +...... +..##.. +.#..#. +.#.... +###... +.#.... +.#..#. +#.##.. +...... +...... +---- 0x82 ('.') */ +...... +...... +...... +#...#. +.###.. +.#.#.. +.###.. +#...#. +...... +...... +---- 0x83 ('.') */ +...... +#...#. +#...#. +.#.#.. +..#... +#####. +..#... +..#... +..#... +...... +---- 0x84 ('.') */ +...... +..#... +..#... +..#... +...... +..#... +..#... +..#... +...... +...... +---- 0x85 ('.') */ +...... +.###.. +#..... +###... +#..#.. +.#..#. +..###. +....#. +.###.. +...... +---- 0x86 ('.') */ +.#.#.. +...... +...... +...... +...... +...... +...... +...... +...... +...... +---- 0x87 ('.') */ +...... +.###.. +#...#. +#.#.#. +##..#. +#.#.#. +#...#. +.###.. +...... +...... +---- 0x88 ('.') */ +...... +..###. +.#..#. +.#.##. +..#.#. +...... +.####. +...... +...... +...... +---- 0x89 ('.') */ +...... +...... +...... +..#..# +.#..#. +#..#.. +.#..#. +..#..# +...... +...... +---- 0x8a ('.') */ +...... +...... +...... +...... +.####. +....#. +...... +...... +...... +...... +---- 0x8b ('.') */ +...... +...... +...... +...... +.####. +...... +...... +...... +...... +...... +---- 0x8c ('.') */ +...... +.###.. +#...#. +###.#. +##..#. +##..#. +#...#. +.###.. +...... +...... +---- 0x8d ('.') */ +#####. +...... +...... +...... +...... +...... +...... +...... +...... +...... +---- 0x8e ('.') */ +...... +..#... +.#.#.. +..#... +...... +...... +...... +...... +...... +...... +---- 0x8f ('.') */ +...... +...... +..#... +..#... +#####. +..#... +..#... +#####. +...... +...... +---- 0x90 ('.') */ +..##.. +.#..#. +...#.. +..#... +.####. +...... +...... +...... +...... +...... +---- 0x91 ('.') */ +.###.. +....#. +..##.. +....#. +.###.. +...... +...... +...... +...... +...... +---- 0x92 ('.') */ +...#.. +..#... +...... +...... +...... +...... +...... +...... +...... +...... +---- 0x93 ('.') */ +...... +...... +...... +#...#. +#...#. +#...#. +##..#. +#.##.. +#..... +...... +---- 0x94 ('.') */ +...... +.####. +###.#. +###.#. +.##.#. +..#.#. +..#.#. +..#.#. +...... +...... +---- 0x95 ('.') */ +...... +...... +...... +...... +..#... +...... +...... +...... +...... +...... +---- 0x96 ('.') */ +...... +...... +...... +...... +...... +...... +...... +...... +...#.. +..#... +---- 0x97 ('.') */ +..#... +.##... +..#... +..#... +.###.. +...... +...... +...... +...... +...... +---- 0x98 ('.') */ +...... +..##.. +.#..#. +.#..#. +..##.. +...... +.####. +...... +...... +...... +---- 0x99 ('.') */ +...... +...... +...... +#..#.. +.#..#. +..#..# +.#..#. +#..#.. +...... +...... +---- 0x9a ('.') */ +.#.... +##.... +.#.... +.#.... +###..# +....## +...#.# +..#### +.....# +...... +---- 0x9b ('.') */ +.#.... +##.... +.#.... +.#.... +###.#. +...#.# +.....# +....#. +...### +...... +---- 0x9c ('.') */ +##.... +..#... +.#.... +..#... +##..#. +...##. +..#.#. +.####. +....#. +...... +---- 0x9d ('.') */ +...... +..#... +...... +..#... +..#... +.#.... +#...#. +.###.. +...... +...... +---- 0x9e ('.') */ +.#.... +..#... +.###.. +#...#. +#...#. +#####. +#...#. +#...#. +...... +...... +---- 0x9f ('.') */ +...#.. +..#... +.###.. +#...#. +#...#. +#####. +#...#. +#...#. +...... +...... +---- 0xa0 ('.') */ +..#... +.#.#.. +.###.. +#...#. +#...#. +#####. +#...#. +#...#. +...... +...... +---- 0xa1 ('.') */ +.#..#. +#.##.. +.###.. +#...#. +#...#. +#####. +#...#. +#...#. +...... +...... +---- 0xa2 ('.') */ +.#.#.. +...... +.###.. +#...#. +#...#. +#####. +#...#. +#...#. +...... +...... +---- 0xa3 ('.') */ +..#... +.#.#.. +.###.. +#...#. +#...#. +#####. +#...#. +#...#. +...... +...... +---- 0xa4 ('.') */ +...... +..#### +.#.#.. +#..#.. +#..### +####.. +#..#.. +#..### +...... +...... +---- 0xa5 ('.') */ +...... +.###.. +#...#. +#..... +#..... +#..... +#...#. +.###.. +..#... +.#.... +---- 0xa6 ('.') */ +.#.... +#####. +#..... +#..... +####.. +#..... +#..... +#####. +...... +...... +---- 0xa7 ('.') */ +...#.. +#####. +#..... +#..... +####.. +#..... +#..... +#####. +...... +...... +---- 0xa8 ('.') */ +..#... +#####. +#..... +#..... +####.. +#..... +#..... +#####. +...... +...... +---- 0xa9 ('.') */ +.#.#.. +#####. +#..... +#..... +####.. +#..... +#..... +#####. +...... +...... +---- 0xaa ('.') */ +.#.... +..#... +.###.. +..#... +..#... +..#... +..#... +.###.. +...... +...... +---- 0xab ('.') */ +...#.. +..#... +.###.. +..#... +..#... +..#... +..#... +.###.. +...... +...... +---- 0xac ('.') */ +..#... +.#.#.. +.###.. +..#... +..#... +..#... +..#... +.###.. +...... +...... +---- 0xad ('.') */ +.#.#.. +...... +.###.. +..#... +..#... +..#... +..#... +.###.. +...... +...... +---- 0xae ('.') */ +...... +####.. +.#..#. +.#..#. +###.#. +.#..#. +.#..#. +####.. +...... +...... +---- 0xaf ('.') */ +..#.#. +.#.#.. +#...#. +##..#. +#.#.#. +#..##. +#...#. +#...#. +...... +...... +---- 0xb0 ('.') */ +.#.... +..#... +.###.. +#...#. +#...#. +#...#. +#...#. +.###.. +...... +...... +---- 0xb1 ('.') */ +...#.. +..#... +.###.. +#...#. +#...#. +#...#. +#...#. +.###.. +...... +...... +---- 0xb2 ('.') */ +..#... +.#.#.. +.###.. +#...#. +#...#. +#...#. +#...#. +.###.. +...... +...... +---- 0xb3 ('.') */ +..#.#. +.#.#.. +.###.. +#...#. +#...#. +#...#. +#...#. +.###.. +...... +...... +---- 0xb4 ('.') */ +.#.#.. +...... +.###.. +#...#. +#...#. +#...#. +#...#. +.###.. +...... +...... +---- 0xb5 ('.') */ +...... +...... +...... +#...#. +.#.#.. +..#... +.#.#.. +#...#. +...... +...... +---- 0xb6 ('.') */ +...... +.###.. +#..##. +#..##. +#.#.#. +##..#. +##..#. +.###.. +...... +...... +---- 0xb7 ('.') */ +.#.... +..#... +#...#. +#...#. +#...#. +#...#. +#...#. +.###.. +...... +...... +---- 0xb8 ('.') */ +...#.. +..#... +#...#. +#...#. +#...#. +#...#. +#...#. +.###.. +...... +...... +---- 0xb9 ('.') */ +..#... +.#.#.. +...... +#...#. +#...#. +#...#. +#...#. +.###.. +...... +...... +---- 0xba ('.') */ +.#.#.. +...... +#...#. +#...#. +#...#. +#...#. +#...#. +.###.. +...... +...... +---- 0xbb ('.') */ +...#.. +..#... +#...#. +#...#. +.#.#.. +..#... +..#... +..#... +...... +...... +---- 0xbc ('.') */ +...... +#..... +####.. +#...#. +####.. +#..... +#..... +#..... +...... +...... +---- 0xbd ('.') */ +...... +.###.. +#...#. +#..#.. +#.#... +#..#.. +#...#. +#.##.. +...... +...... +---- 0xbe ('.') */ +.#.... +..#... +...... +.###.. +....#. +.####. +#...#. +.####. +...... +...... +---- 0xbf ('.') */ +...#.. +..#... +...... +.###.. +....#. +.####. +#...#. +.####. +...... +...... +---- 0xc0 ('.') */ +..#... +.#.#.. +...... +.###.. +....#. +.####. +#...#. +.####. +...... +...... +---- 0xc1 ('.') */ +..#.#. +.#.#.. +...... +.###.. +....#. +.####. +#...#. +.####. +...... +...... +---- 0xc2 ('.') */ +...... +.#.#.. +...... +.###.. +....#. +.####. +#...#. +.####. +...... +...... +---- 0xc3 ('.') */ +..#... +.#.#.. +..#... +.###.. +....#. +.####. +#...#. +.####. +...... +...... +---- 0xc4 ('.') */ +...... +...... +...... +.####. +...#.# +.##### +#..#.. +.##### +...... +...... +---- 0xc5 ('.') */ +...... +...... +...... +.###.. +#...#. +#..... +#...#. +.###.. +..#... +.#.... +---- 0xc6 ('.') */ +.#.... +..#... +...... +.###.. +#...#. +#####. +#..... +.###.. +...... +...... +---- 0xc7 ('.') */ +...#.. +..#... +...... +.###.. +#...#. +#####. +#..... +.###.. +...... +...... +---- 0xc8 ('.') */ +..#... +.#.#.. +...... +.###.. +#...#. +#####. +#..... +.###.. +...... +...... +---- 0xc9 ('.') */ +...... +.#.#.. +...... +.###.. +#...#. +#####. +#..... +.###.. +...... +...... +---- 0xca ('.') */ +.#.... +..#... +...... +.##... +..#... +..#... +..#... +.###.. +...... +...... +---- 0xcb ('.') */ +..#... +.#.... +...... +.##... +..#... +..#... +..#... +.###.. +...... +...... +---- 0xcc ('.') */ +..#... +.#.#.. +...... +.##... +..#... +..#... +..#... +.###.. +...... +...... +---- 0xcd ('.') */ +...... +.#.#.. +...... +.##... +..#... +..#... +..#... +.###.. +...... +...... +---- 0xce ('.') */ +...... +##.... +..##.. +.###.. +#...#. +#...#. +#...#. +.###.. +...... +...... +---- 0xcf ('.') */ +..#.#. +.#.#.. +...... +#.##.. +##..#. +#...#. +#...#. +#...#. +...... +...... +---- 0xd0 ('.') */ +.#.... +..#... +...... +.###.. +#...#. +#...#. +#...#. +.###.. +...... +...... +---- 0xd1 ('.') */ +...#.. +..#... +...... +.###.. +#...#. +#...#. +#...#. +.###.. +...... +...... +---- 0xd2 ('.') */ +..#... +.#.#.. +...... +.###.. +#...#. +#...#. +#...#. +.###.. +...... +...... +---- 0xd3 ('.') */ +..#.#. +.#.#.. +...... +.###.. +#...#. +#...#. +#...#. +.###.. +...... +...... +---- 0xd4 ('.') */ +...... +.#.#.. +...... +.###.. +#...#. +#...#. +#...#. +.###.. +...... +...... +---- 0xd5 ('.') */ +...... +...... +..#... +...... +#####. +...... +..#... +...... +...... +...... +---- 0xd6 ('.') */ +...... +...... +...... +.####. +#..##. +#.#.#. +##..#. +####.. +...... +...... +---- 0xd7 ('.') */ +.#.... +..#... +...... +#...#. +#...#. +#...#. +#..##. +.##.#. +...... +...... +---- 0xd8 ('.') */ +...#.. +..#... +...... +#...#. +#...#. +#...#. +#..##. +.##.#. +...... +...... +---- 0xd9 ('.') */ +..#... +.#.#.. +...... +#...#. +#...#. +#...#. +#..##. +.##.#. +...... +...... +---- 0xda ('.') */ +...... +.#.#.. +...... +#...#. +#...#. +#...#. +#..##. +.##.#. +...... +...... +---- 0xdb ('.') */ +...... +...#.. +..#... +#...#. +#...#. +#..##. +.##.#. +....#. +#...#. +.###.. +---- 0xdc ('.') */ +...... +...... +#..... +####.. +#...#. +#...#. +#...#. +####.. +#..... +#..... +---- 0xdd ('.') */ +...... +.#.#.. +...... +#...#. +#...#. +#..##. +.##.#. +....#. +#...#. +.###.. +---- 0xde ('.') */ +.###.. +...... +.###.. +#...#. +#...#. +#####. +#...#. +#...#. +...... +...... +---- 0xdf ('.') */ +...... +.###.. +...... +.###.. +....#. +.####. +#...#. +.####. +...... +...... +---- 0xe0 ('.') */ +#...#. +.###.. +.###.. +#...#. +#...#. +#####. +#...#. +#...#. +...... +...... +---- 0xe1 ('.') */ +#...#. +.###.. +...... +.###.. +....#. +.####. +#...#. +.####. +...... +...... +---- 0xe2 ('.') */ +...... +..#... +.#.#.. +#...#. +#...#. +#####. +#...#. +#...#. +...#.. +...##. +---- 0xe3 ('.') */ +...... +...... +...... +.###.. +....#. +.####. +#...#. +.####. +...#.. +...##. +---- 0xe4 ('.') */ +...#.. +..#... +.###.. +#...#. +#..... +#..... +#...#. +.###.. +...... +...... +---- 0xe5 ('.') */ +...#.. +..#... +...... +.###.. +#...#. +#..... +#...#. +.###.. +...... +...... +---- 0xe6 ('.') */ +..#... +.#.#.. +.###.. +#...#. +#..... +#..... +#...#. +.###.. +...... +...... +---- 0xe7 ('.') */ +..#... +.#.#.. +...... +.###.. +#...#. +#..... +#...#. +.###.. +...... +...... +---- 0xe8 ('.') */ +..#... +...... +.###.. +#...#. +#..... +#..... +#...#. +.###.. +...... +...... +---- 0xe9 ('.') */ +...... +..#... +...... +.###.. +#...#. +#..... +#...#. +.###.. +...... +...... +---- 0xea ('.') */ +.#.#.. +..#... +.###.. +#...#. +#..... +#..... +#...#. +.###.. +...... +...... +---- 0xeb ('.') */ +.#.#.. +..#... +...... +.###.. +#...#. +#..... +#...#. +.###.. +...... +...... +---- 0xec ('.') */ +.#.#.. +..#... +####.. +#...#. +#...#. +#...#. +#...#. +####.. +...... +...... +---- 0xed ('.') */ +.#.#.. +..#... +....#. +.##.#. +#..##. +#...#. +#..##. +.##.#. +...... +...... +---- 0xee ('.') */ +...... +.####. +.#...# +.#...# +###..# +.#...# +.#...# +.####. +...... +...... +---- 0xef ('.') */ +...... +...#.. +..###. +...#.. +.###.. +#..#.. +#..#.. +.###.. +...... +...... +---- 0xf0 ('.') */ +.###.. +...... +#####. +#..... +####.. +#..... +#..... +#####. +...... +...... +---- 0xf1 ('.') */ +...... +.###.. +...... +.###.. +#...#. +#####. +#..... +.###.. +...... +...... +---- 0xf2 ('.') */ +#...#. +.###.. +#####. +#..... +####.. +#..... +#..... +#####. +...... +...... +---- 0xf3 ('.') */ +#...#. +.###.. +...... +.###.. +#...#. +#####. +#..... +.###.. +...... +...... +---- 0xf4 ('.') */ +..#... +...... +#####. +#..... +####.. +#..... +#..... +#####. +...... +...... +---- 0xf5 ('.') */ +...... +..#... +...... +.###.. +#...#. +#####. +#..... +.###.. +...... +...... +---- 0xf6 ('.') */ +...... +#####. +#..... +#..... +####.. +#..... +#..... +#####. +..#... +..##.. +---- 0xf7 ('.') */ +...... +...... +...... +.###.. +#...#. +#####. +#..... +.###.. +..#... +..##.. +---- 0xf8 ('.') */ +.#.#.. +..#... +#####. +#..... +####.. +#..... +#..... +#####. +...... +...... +---- 0xf9 ('.') */ +.#.#.. +..#... +...... +.###.. +#...#. +#####. +#..... +.###.. +...... +...... +---- 0xfa ('.') */ +..#... +.#.#.. +.###.. +#...#. +#..... +#..##. +#...#. +.###.. +...... +...... +---- 0xfb ('.') */ +..#... +.#.#.. +...... +.##.#. +#..#.. +.##... +#..... +.###.. +#...#. +.###.. +---- 0xfc ('.') */ +#...#. +.###.. +.###.. +#...#. +#..... +#..##. +#...#. +.###.. +...... +...... +---- 0xfd ('.') */ +#...#. +.###.. +...... +.##.#. +#..#.. +.##... +#..... +.###.. +#...#. +.###.. +---- 0xfe ('.') */ +..#... +...... +.###.. +#...#. +#..... +#..##. +#...#. +.###.. +...... +...... +---- 0xff ('.') */ + + diff --git a/tools/sci/bdf.cpp b/tools/sci/bdf.cpp new file mode 100644 index 0000000000..8606688f8c --- /dev/null +++ b/tools/sci/bdf.cpp @@ -0,0 +1,7434 @@ +/* + * Copyright 2001 Computing Research Labs, New Mexico State University + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT + * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef lint +#ifdef __GNUC__ +static char rcsid[] __attribute__((unused)) = "$Id$"; +#else +static char rcsid[] = "$Id$"; +#endif +#endif + +#include "bdfP.h" + +#ifdef HAVE_HBF +#include "hbf.h" +#endif + +#undef MAX +#define MAX(h, i) ((h) > (i) ? (h) : (i)) + +#undef MIN +#define MIN(l, o) ((l) < (o) ? (l) : (o)) + +/************************************************************************** + * + * Masks used for checking different bits per pixel cases. + * + **************************************************************************/ + +unsigned char onebpp[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; +unsigned char twobpp[] = { 0xc0, 0x30, 0x0c, 0x03 }; +unsigned char fourbpp[] = { 0xf0, 0x0f }; +unsigned char eightbpp[] = { 0xff }; + +/************************************************************************** + * + * Default BDF font options. + * + **************************************************************************/ + +static bdf_options_t _bdf_opts = { + 1, /* Hint TTF glyphs. */ + 1, /* Correct metrics. */ + 1, /* Preserve unencoded glyphs. */ + 1, /* Preserve comments. */ + 1, /* Pad character-cells. */ + BDF_PROPORTIONAL, /* Default spacing. */ + 12, /* Default point size. */ + 0, /* Default horizontal resolution. */ + 0, /* Default vertical resolution. */ + 1, /* Bits per pixel. */ + BDF_UNIX_EOL, /* Line separator. */ +}; + +/************************************************************************** + * + * Builtin BDF font properties. + * + **************************************************************************/ + +/* + * List of most properties that might appear in a font. Doesn't include the + * RAW_* and AXIS_* properties in X11R6 polymorphic fonts. + */ +static bdf_property_t _bdf_properties[] = { + {"ADD_STYLE_NAME", BDF_ATOM, 1}, + {"AVERAGE_WIDTH", BDF_INTEGER, 1}, + {"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1}, + {"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1}, + {"CAP_HEIGHT", BDF_INTEGER, 1}, + {"CHARSET_COLLECTIONS", BDF_ATOM, 1}, + {"CHARSET_ENCODING", BDF_ATOM, 1}, + {"CHARSET_REGISTRY", BDF_ATOM, 1}, + {"COMMENT", BDF_ATOM, 1}, + {"COPYRIGHT", BDF_ATOM, 1}, + {"DEFAULT_CHAR", BDF_CARDINAL, 1}, + {"DESTINATION", BDF_CARDINAL, 1}, + {"DEVICE_FONT_NAME", BDF_ATOM, 1}, + {"END_SPACE", BDF_INTEGER, 1}, + {"FACE_NAME", BDF_ATOM, 1}, + {"FAMILY_NAME", BDF_ATOM, 1}, + {"FIGURE_WIDTH", BDF_INTEGER, 1}, + {"FONT", BDF_ATOM, 1}, + {"FONTNAME_REGISTRY", BDF_ATOM, 1}, + {"FONT_ASCENT", BDF_INTEGER, 1}, + {"FONT_DESCENT", BDF_INTEGER, 1}, + {"FOUNDRY", BDF_ATOM, 1}, + {"FULL_NAME", BDF_ATOM, 1}, + {"ITALIC_ANGLE", BDF_INTEGER, 1}, + {"MAX_SPACE", BDF_INTEGER, 1}, + {"MIN_SPACE", BDF_INTEGER, 1}, + {"NORM_SPACE", BDF_INTEGER, 1}, + {"NOTICE", BDF_ATOM, 1}, + {"PIXEL_SIZE", BDF_INTEGER, 1}, + {"POINT_SIZE", BDF_INTEGER, 1}, + {"QUAD_WIDTH", BDF_INTEGER, 1}, + {"RAW_ASCENT", BDF_INTEGER, 1}, + {"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1}, + {"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1}, + {"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1}, + {"RAW_CAP_HEIGHT", BDF_INTEGER, 1}, + {"RAW_DESCENT", BDF_INTEGER, 1}, + {"RAW_END_SPACE", BDF_INTEGER, 1}, + {"RAW_FIGURE_WIDTH", BDF_INTEGER, 1}, + {"RAW_MAX_SPACE", BDF_INTEGER, 1}, + {"RAW_MIN_SPACE", BDF_INTEGER, 1}, + {"RAW_NORM_SPACE", BDF_INTEGER, 1}, + {"RAW_PIXEL_SIZE", BDF_INTEGER, 1}, + {"RAW_POINT_SIZE", BDF_INTEGER, 1}, + {"RAW_PIXELSIZE", BDF_INTEGER, 1}, + {"RAW_POINTSIZE", BDF_INTEGER, 1}, + {"RAW_QUAD_WIDTH", BDF_INTEGER, 1}, + {"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1}, + {"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1}, + {"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1}, + {"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1}, + {"RAW_SUBSCRIPT_X", BDF_INTEGER, 1}, + {"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1}, + {"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1}, + {"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1}, + {"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1}, + {"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1}, + {"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1}, + {"RAW_X_HEIGHT", BDF_INTEGER, 1}, + {"RELATIVE_SETWIDTH", BDF_CARDINAL, 1}, + {"RELATIVE_WEIGHT", BDF_CARDINAL, 1}, + {"RESOLUTION", BDF_INTEGER, 1}, + {"RESOLUTION_X", BDF_CARDINAL, 1}, + {"RESOLUTION_Y", BDF_CARDINAL, 1}, + {"SETWIDTH_NAME", BDF_ATOM, 1}, + {"SLANT", BDF_ATOM, 1}, + {"SMALL_CAP_SIZE", BDF_INTEGER, 1}, + {"SPACING", BDF_ATOM, 1}, + {"STRIKEOUT_ASCENT", BDF_INTEGER, 1}, + {"STRIKEOUT_DESCENT", BDF_INTEGER, 1}, + {"SUBSCRIPT_SIZE", BDF_INTEGER, 1}, + {"SUBSCRIPT_X", BDF_INTEGER, 1}, + {"SUBSCRIPT_Y", BDF_INTEGER, 1}, + {"SUPERSCRIPT_SIZE", BDF_INTEGER, 1}, + {"SUPERSCRIPT_X", BDF_INTEGER, 1}, + {"SUPERSCRIPT_Y", BDF_INTEGER, 1}, + {"UNDERLINE_POSITION", BDF_INTEGER, 1}, + {"UNDERLINE_THICKNESS", BDF_INTEGER, 1}, + {"WEIGHT", BDF_CARDINAL, 1}, + {"WEIGHT_NAME", BDF_ATOM, 1}, + {"X_HEIGHT", BDF_INTEGER, 1}, + {"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1}, + {"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1}, +}; + +static unsigned long _num_bdf_properties = + sizeof(_bdf_properties) / sizeof(_bdf_properties[0]); + +/* + * User defined properties. + */ +static bdf_property_t *user_props; +static unsigned long nuser_props = 0; + +/************************************************************************** + * + * Hash table utilities for the properties. + * + **************************************************************************/ + +#define INITIAL_HT_SIZE 241 + +typedef struct { + char *key; + void *data; +} _hashnode, *hashnode; + +typedef struct { + int limit; + int size; + int used; + hashnode *table; +} hashtable; + +typedef void (*hash_free_func)( +#ifdef __STDC__ + hashnode node +#endif +); + +static hashnode * +#ifdef __STDC__ +hash_bucket(char *key, hashtable *ht) +#else +hash_bucket(key, ht) +char *key; +hashtable *ht; +#endif +{ + char *kp = key; + unsigned long res = 0; + hashnode *bp = ht->table, *ndp; + + /* + * Mocklisp hash function. + */ + while (*kp) + res = (res << 5) - res + *kp++; + + ndp = bp + (res % ht->size); + while (*ndp) { + kp = (*ndp)->key; + if (kp[0] == key[0] && strcmp(kp, key) == 0) + break; + ndp--; + if (ndp < bp) + ndp = bp + (ht->size - 1); + } + return ndp; +} + +static void +#ifdef __STDC__ +hash_rehash(hashtable *ht) +#else +hash_rehash(ht) +hashtable *ht; +#endif +{ + hashnode *obp = ht->table, *bp, *nbp; + int i, sz = ht->size; + + ht->size <<= 1; + ht->limit = ht->size / 3; + ht->table = (hashnode *) malloc(sizeof(hashnode) * ht->size); + (void) memset((char *) ht->table, 0, sizeof(hashnode) * ht->size); + + for (i = 0, bp = obp; i < sz; i++, bp++) { + if (*bp) { + nbp = hash_bucket((*bp)->key, ht); + *nbp = *bp; + } + } + free((char *) obp); +} + +static void +#ifdef __STDC__ +hash_init(hashtable *ht) +#else +hash_init(ht) +hashtable *ht; +#endif +{ + int sz = INITIAL_HT_SIZE; + + ht->size = sz; + ht->limit = sz / 3; + ht->used = 0; + ht->table = (hashnode *) malloc(sizeof(hashnode) * sz); + (void) memset((char *) ht->table, 0, sizeof(hashnode) * sz); +} + +static void +#ifdef __STDC__ +hash_free(hashtable *ht) +#else +hash_free(ht) +hashtable *ht; +#endif +{ + int i, sz = ht->size; + hashnode *bp = ht->table; + + for (i = 0; i < sz; i++, bp++) { + if (*bp) + free((char *) *bp); + } + if (sz > 0) + free((char *) ht->table); +} + +static void +#ifdef __STDC__ +hash_insert(char *key, void *data, hashtable *ht) +#else +hash_insert(key, data, ht) +char *key; +void *data; +hashtable *ht; +#endif +{ + hashnode nn, *bp = hash_bucket(key, ht); + + nn = *bp; + if (!nn) { + *bp = nn = (hashnode) malloc(sizeof(_hashnode)); + nn->key = key; + nn->data = data; + + if (ht->used >= ht->limit) + hash_rehash(ht); + ht->used++; + } else + nn->data = data; +} + +static hashnode +#ifdef __STDC__ +hash_lookup(char *key, hashtable *ht) +#else +hash_lookup(key, ht) +char *key; +hashtable *ht; +#endif +{ + hashnode *np = hash_bucket(key, ht); + return *np; +} + +static void +#ifdef __STDC__ +hash_delete(char *name, hashtable *ht) +#else +hash_delete(name, ht) +char *name; +hashtable *ht; +#endif +{ + hashnode *hp; + + hp = hash_bucket(name, ht); + if (*hp) { + free((char *) *hp); + *hp = 0; + } +} + +/* + * The builtin property table. + */ +static hashtable proptbl; + +/************************************************************************** + * + * Utility types and functions. + * + **************************************************************************/ + +/* + * Function type for parsing lines of a BDF font. + */ +typedef int (*_bdf_line_func_t)( +#ifdef __STDC__ + char *line, + unsigned long linelen, + unsigned long lineno, + void *call_data, + void *client_data +#endif +); + +/* + * List structure for splitting lines into fields. + */ +typedef struct { + char **field; + unsigned long size; + unsigned long used; + char *bfield; + unsigned long bsize; + unsigned long bused; +} _bdf_list_t; + +/* + * Structure used while loading BDF fonts. + */ +typedef struct { + unsigned long flags; + unsigned long cnt; + unsigned long row; + unsigned long bpr; + short minlb; + short maxlb; + short maxrb; + short maxas; + short maxds; + short rbearing; + char *glyph_name; + long glyph_enc; + bdf_font_t *font; + bdf_options_t *opts; + void *client_data; + bdf_callback_t callback; + bdf_callback_struct_t cb; + unsigned long have[2048]; + _bdf_list_t list; +} _bdf_parse_t; + +#define setsbit(m, cc) (m[(cc) >> 3] |= (1 << ((cc) & 7))) +#define sbitset(m, cc) (m[(cc) >> 3] & (1 << ((cc) & 7))) + +/* + * An empty string for empty fields. + */ +static char empty[1] = { 0 }; + +/* + * Assume the line is NULL terminated and that the `list' parameter was + * initialized the first time it was used. + */ +static void +#ifdef __STDC__ +_bdf_split(char *separators, char *line, unsigned long linelen, + _bdf_list_t *list) +#else +_bdf_split(separators, line, linelen, list) +char *separators, *line; +unsigned long linelen; +_bdf_list_t *list; +#endif +{ + int mult, final_empty; + char *sp, *ep, *end; + unsigned char seps[32]; + + /* + * Initialize the list. + */ + list->used = list->bused = 0; + + /* + * If the line is empty, then simply return. + */ + if (linelen == 0 || line[0] == 0) + return; + + /* + * If the `separators' parameter is NULL or empty, split the list into + * individual bytes. + */ + if (separators == 0 || *separators == 0) { + if (linelen > list->bsize) { + if (list->bsize) + list->bfield = (char *) malloc(linelen); + else + list->bfield = (char *) realloc(list->bfield, linelen); + list->bsize = linelen; + } + list->bused = linelen; + (void) memcpy(list->bfield, line, linelen); + return; + } + + /* + * Prepare the separator bitmap. + */ + (void) memset((char *) seps, 0, 32); + + /* + * If the very last character of the separator string is a plus, then set + * the `mult' flag to indicate that multiple separators should be + * collapsed into one. + */ + for (mult = 0, sp = separators; sp && *sp; sp++) { + if (*sp == '+' && *(sp + 1) == 0) + mult = 1; + else + setsbit(seps, *sp); + } + + /* + * Break the line up into fields. + */ + for (final_empty = 0, sp = ep = line, end = sp + linelen; + sp < end && *sp;) { + /* + * Collect everything that is not a separator. + */ + for (; *ep && !sbitset(seps, *ep); ep++) ; + + /* + * Resize the list if necessary. + */ + if (list->used == list->size) { + if (list->size == 0) + list->field = (char **) malloc(sizeof(char *) * 5); + else + list->field = (char **) + realloc((char *) list->field, + sizeof(char *) * (list->size + 5)); + + list->size += 5; + } + + /* + * Assign the field appropriately. + */ + list->field[list->used++] = (ep > sp) ? sp : empty; + + sp = ep; + if (mult) { + /* + * If multiple separators should be collapsed, do it now by + * setting all the separator characters to 0. + */ + for (; *ep && sbitset(seps, *ep); ep++) + *ep = 0; + } else if (*ep != 0) + /* + * Don't collapse multiple separators by making them 0, so just + * make the one encountered 0. + */ + *ep++ = 0; + final_empty = (ep > sp && *ep == 0); + sp = ep; + } + + /* + * Finally, NULL terminate the list. + */ + if (list->used + final_empty + 1 >= list->size) { + if (list->used == list->size) { + if (list->size == 0) + list->field = (char **) malloc(sizeof(char *) * 5); + else + list->field = (char **) + realloc((char *) list->field, + sizeof(char *) * (list->size + 5)); + list->size += 5; + } + } + if (final_empty) + list->field[list->used++] = empty; + + if (list->used == list->size) { + if (list->size == 0) + list->field = (char **) malloc(sizeof(char *) * 5); + else + list->field = (char **) + realloc((char *) list->field, + sizeof(char *) * (list->size + 5)); + list->size += 5; + } + list->field[list->used] = 0; +} + +static void +#ifdef __STDC__ +_bdf_shift(unsigned long n, _bdf_list_t *list) +#else +_bdf_shift(n, list) +unsigned long n; +_bdf_list_t *list; +#endif +{ + unsigned long i, u; + + if (list == 0 || list->used == 0 || n == 0) + return; + + if (n >= list->used) { + list->used = 0; + return; + } + for (u = n, i = 0; u < list->used; i++, u++) + list->field[i] = list->field[u]; + list->used -= n; +} + +static char * +#ifdef __STDC__ +_bdf_join(int c, unsigned long *len, _bdf_list_t *list) +#else +_bdf_join(c, len, list) +int c; +unsigned long *len; +_bdf_list_t *list; +#endif +{ + unsigned long i, j; + char *fp, *dp; + + if (list == 0 || list->used == 0) + return 0; + + *len = 0; + + dp = list->field[0]; + for (i = j = 0; i < list->used; i++) { + fp = list->field[i]; + while (*fp) + dp[j++] = *fp++; + if (i + 1 < list->used) + dp[j++] = c; + } + dp[j] = 0; + + *len = j; + return dp; +} + +/* + * High speed file reader that passes each line to a callback. + */ +static int +#ifdef __STDC__ +_bdf_readlines(int fd, _bdf_line_func_t callback, void *client_data, + unsigned long *lno) +#else +_bdf_readlines(fd, callback, client_data, lno) +int fd; +_bdf_line_func_t callback; +void *client_data; +unsigned long *lno; +#endif +{ + _bdf_line_func_t cb; + unsigned long lineno; + int n, res, done, refill, bytes, hold; + char *ls, *le, *pp, *pe, *hp; + char buf[65536]; + + if (callback == 0) + return -1; + + cb = callback; + lineno = 1; + buf[0] = 0; + res = done = 0; + pp = ls = le = buf; + bytes = 65536; + while (!done && (n = read(fd, pp, bytes)) > 0) { + /* + * Determine the new end of the buffer pages. + */ + pe = pp + n; + + for (refill = 0; done == 0 && refill == 0;) { + while (le < pe && *le != '\n' && *le != '\r') + le++; + + if (le == pe) { + /* + * Hit the end of the last page in the buffer. Need to find + * out how many pages to shift and how many pages need to be + * read in. Adjust the line start and end pointers down to + * point to the right places in the pages. + */ + pp = buf + (((ls - buf) >> 13) << 13); + n = pp - buf; + ls -= n; + le -= n; + n = pe - pp; + (void) memcpy(buf, pp, n); + pp = buf + n; + bytes = 65536 - n; + refill = 1; + } else { + /* + * Temporarily NULL terminate the line. + */ + hp = le; + hold = *le; + *le = 0; + + if (callback && *ls != '#' && *ls != 0x1a && le > ls && + (res = (*cb)(ls, le - ls, lineno, (void *) & cb, + client_data)) != 0) + done = 1; + else { + ls = ++le; + /* + * Handle the case of DOS crlf sequences. + */ + if (le < pe && hold == '\n' && *le == '\r') + ls = ++le; + } + + /* + * Increment the line number. + */ + lineno++; + + /* + * Restore the character at the end of the line. + */ + *hp = hold; + } + } + } + *lno = lineno; + return res; +} + +unsigned char * +#ifdef __STDC__ +_bdf_strdup(unsigned char *s, unsigned long len) +#else +_bdf_strdup(s, len) +unsigned char *s; +unsigned long len; +#endif +{ + unsigned char *ns; + + if (s == 0 || len == 0) + return 0; + + ns = (unsigned char *) malloc(len); + (void) memcpy((char *) ns, (char *) s, len); + return ns; +} + +void +_bdf_memmove(char *dest, char *src, unsigned long bytes) { + long i, j; + + i = (long) bytes; + j = i & 7; + i = (i + 7) >> 3; + + /* + * Do a memmove using Ye Olde Duff's Device for efficiency. + */ + if (src < dest) { + src += bytes; + dest += bytes; + + switch (j) { + case 0: + do { + *--dest = *--src; + case 7: + *--dest = *--src; + case 6: + *--dest = *--src; + case 5: + *--dest = *--src; + case 4: + *--dest = *--src; + case 3: + *--dest = *--src; + case 2: + *--dest = *--src; + case 1: + *--dest = *--src; + } while (--i > 0); + } + } else if (src > dest) { + switch (j) { + case 0: + do { + *dest++ = *src++; + case 7: + *dest++ = *src++; + case 6: + *dest++ = *src++; + case 5: + *dest++ = *src++; + case 4: + *dest++ = *src++; + case 3: + *dest++ = *src++; + case 2: + *dest++ = *src++; + case 1: + *dest++ = *src++; + } while (--i > 0); + } + } +} + +static unsigned char a2i[128] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static unsigned char odigits[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static unsigned char ddigits[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static unsigned char hdigits[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, + 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +#define isdigok(m, d) (m[(d) >> 3] & (1 << ((d) & 7))) + +/* + * Routine to convert an ASCII string into an unsigned long integer. + */ +unsigned long +#ifdef __STDC__ +_bdf_atoul(char *s, char **end, int base) +#else +_bdf_atoul(s, end, base) +char *s, **end; +int base; +#endif +{ + unsigned long v; + unsigned char *dmap; + + if (s == 0 || *s == 0) + return 0; + + /* + * Make sure the radix is something recognizable. Default to 10. + */ + switch (base) { + case 8: + dmap = odigits; + break; + case 16: + dmap = hdigits; + break; + default: + base = 10; + dmap = ddigits; + break; + } + + /* + * Check for the special hex prefix. + */ + if (*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')) { + base = 16; + dmap = hdigits; + s += 2; + } + + for (v = 0; isdigok(dmap, *s); s++) + v = (v * base) + a2i[(int) *s]; + + if (end != 0) + *end = s; + + return v; +} + +/* + * Routine to convert an ASCII string into an signed long integer. + */ +long +#ifdef __STDC__ +_bdf_atol(char *s, char **end, int base) +#else +_bdf_atol(s, end, base) +char *s, **end; +int base; +#endif +{ + long v, neg; + unsigned char *dmap; + + if (s == 0 || *s == 0) + return 0; + + /* + * Make sure the radix is something recognizable. Default to 10. + */ + switch (base) { + case 8: + dmap = odigits; + break; + case 16: + dmap = hdigits; + break; + default: + base = 10; + dmap = ddigits; + break; + } + + /* + * Check for a minus sign. + */ + neg = 0; + if (*s == '-') { + s++; + neg = 1; + } + + /* + * Check for the special hex prefix. + */ + if (*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')) { + base = 16; + dmap = hdigits; + s += 2; + } + + for (v = 0; isdigok(dmap, *s); s++) + v = (v * base) + a2i[(int) *s]; + + if (end != 0) + *end = s; + + return (!neg) ? v : -v; +} + +/* + * Routine to convert an ASCII string into an signed short integer. + */ +short +#ifdef __STDC__ +_bdf_atos(char *s, char **end, int base) +#else +_bdf_atos(s, end, base) +char *s, **end; +int base; +#endif +{ + short v, neg; + unsigned char *dmap; + + if (s == 0 || *s == 0) + return 0; + + /* + * Make sure the radix is something recognizable. Default to 10. + */ + switch (base) { + case 8: + dmap = odigits; + break; + case 16: + dmap = hdigits; + break; + default: + base = 10; + dmap = ddigits; + break; + } + + /* + * Check for a minus. + */ + neg = 0; + if (*s == '-') { + s++; + neg = 1; + } + + /* + * Check for the special hex prefix. + */ + if (*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')) { + base = 16; + dmap = hdigits; + s += 2; + } + + for (v = 0; isdigok(dmap, *s); s++) + v = (v * base) + a2i[(int) *s]; + + if (end != 0) + *end = s; + + return (!neg) ? v : -v; +} + +/* + * Routine to compare two glyphs by encoding so they can be sorted. + */ +static int +#ifdef __STDC__ +by_encoding(const void *a, const void *b) +#else +by_encoding(a, b) +char *a, *b; +#endif +{ + bdf_glyph_t *c1, *c2; + + c1 = (bdf_glyph_t *) a; + c2 = (bdf_glyph_t *) b; + if (c1->encoding < c2->encoding) + return -1; + else if (c1->encoding > c2->encoding) + return 1; + return 0; +} + +/************************************************************************** + * + * BDF font file parsing flags and functions. + * + **************************************************************************/ + +/* + * Parse flags. + */ +#define _BDF_START 0x0001 +#define _BDF_FONT_NAME 0x0002 +#define _BDF_SIZE 0x0004 +#define _BDF_FONT_BBX 0x0008 +#define _BDF_PROPS 0x0010 +#define _BDF_GLYPHS 0x0020 +#define _BDF_GLYPH 0x0040 +#define _BDF_ENCODING 0x0080 +#define _BDF_SWIDTH 0x0100 +#define _BDF_DWIDTH 0x0200 +#define _BDF_BBX 0x0400 +#define _BDF_BITMAP 0x0800 + +#define _BDF_SWIDTH_ADJ 0x1000 + +#define _BDF_GLYPH_BITS (_BDF_GLYPH|_BDF_ENCODING|_BDF_SWIDTH|\ + _BDF_DWIDTH|_BDF_BBX|_BDF_BITMAP) + +#define _BDF_GLYPH_WIDTH_CHECK 0x40000000 +#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000 + +/* + * Auto correction messages. + */ +#define ACMSG1 "FONT_ASCENT property missing. Added \"FONT_ASCENT %hd\"." +#define ACMSG2 "FONT_DESCENT property missing. Added \"FONT_DESCENT %hd\"." +#define ACMSG3 "Font width != actual width. Old: %hd New: %hd." +#define ACMSG4 "Font left bearing != actual left bearing. Old: %hd New: %hd." +#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd." +#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd." +#define ACMSG7 "Font height != actual height. Old: %hd New: %hd." +#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made." +#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically." +#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width." +#define ACMSG11 "SIZE bits per pixel field adjusted to %hd." +#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded." +#define ACMSG13 "Glyph %ld extra rows removed." +#define ACMSG14 "Glyph %ld extra columns removed." +#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found." + +/* + * Error messages. + */ +#define ERRMSG1 "[line %ld] Missing \"%s\" line." +#define ERRMSG2 "[line %ld] Font header corrupted or missing fields." +#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields." + +void +#ifdef __STDC__ +_bdf_add_acmsg(bdf_font_t *font, char *msg, unsigned long len) +#else +_bdf_add_acmsg(font, msg, len) +bdf_font_t *font; +char *msg; +unsigned long len; +#endif +{ + char *cp; + + if (font->acmsgs_len == 0) + font->acmsgs = (char *) malloc(len + 1); + else + font->acmsgs = (char *) realloc(font->acmsgs, + font->acmsgs_len + len + 1); + + cp = font->acmsgs + font->acmsgs_len; + (void) memcpy(cp, msg, len); + cp += len; + *cp++ = '\n'; + font->acmsgs_len += len + 1; +} + +void +#ifdef __STDC__ +_bdf_add_comment(bdf_font_t *font, char *comment, unsigned long len) +#else +_bdf_add_comment(font, comment, len) +bdf_font_t *font; +char *comment; +unsigned long len; +#endif +{ + char *cp; + + if (font->comments_len == 0) + font->comments = (char *) malloc(len + 1); + else + font->comments = (char *) realloc(font->comments, + font->comments_len + len + 1); + + cp = font->comments + font->comments_len; + (void) memcpy(cp, comment, len); + cp += len; + *cp++ = '\n'; + font->comments_len += len + 1; +} + +/* + * Set the spacing from the font name if it exists, or set it to the default + * specified in the options. + */ +static void +#ifdef __STDC__ +_bdf_set_default_spacing(bdf_font_t *font, bdf_options_t *opts) +#else +_bdf_set_default_spacing(font, opts) +bdf_font_t *font; +bdf_options_t *opts; +#endif +{ + unsigned long len; + char name[128]; + _bdf_list_t list; + + if (font == 0 || font->name == 0 || font->name[0] == 0) + return; + + font->spacing = opts->font_spacing; + + len = (unsigned long)(strlen(font->name) + 1); + (void) memcpy(name, font->name, len); + list.size = list.used = 0; + _bdf_split("-", name, len, &list); + if (list.used == 15) { + switch (list.field[11][0]) { + case 'C': + case 'c': + font->spacing = BDF_CHARCELL; + break; + case 'M': + case 'm': + font->spacing = BDF_MONOWIDTH; + break; + case 'P': + case 'p': + font->spacing = BDF_PROPORTIONAL; + break; + } + } + if (list.size > 0) + free((char *) list.field); +} + +/* + * Determine if the property is an atom or not. If it is, then clean it up so + * the double quotes are removed if they exist. + */ +static int +#ifdef __STDC__ +_bdf_is_atom(char *line, unsigned long linelen, char **name, char **value) +#else +_bdf_is_atom(line, linelen, name, value) +char *line; +unsigned long linelen; +char **name, **value; +#endif +{ + int hold; + char *sp, *ep; + bdf_property_t *p; + + *name = sp = ep = line; + while (*ep && *ep != ' ' && *ep != '\t') + ep++; + + hold = -1; + if (*ep) { + hold = *ep; + *ep = 0; + } + + p = bdf_get_property(sp); + + /* + * Restore the character that was saved before any return can happen. + */ + if (hold != -1) + *ep = hold; + + /* + * If the propert exists and is not an atom, just return here. + */ + if (p && p->format != BDF_ATOM) + return 0; + + /* + * The property is an atom. Trim all leading and trailing whitespace and + * double quotes for the atom value. + */ + sp = ep; + ep = line + linelen; + + /* + * Trim the leading whitespace if it exists. + */ + *sp++ = 0; + while (*sp && (*sp == ' ' || *sp == '\t')) + sp++; + + /* + * Trim the leading double quote if it exists. + */ + if (*sp == '"') + sp++; + *value = sp; + + /* + * Trim the trailing whitespace if it exists. + */ + while (ep > sp && (*(ep - 1) == ' ' || *(ep - 1) == '\t')) + *--ep = 0; + + /* + * Trim the trailing double quote if it exists. + */ + if (ep > sp && *(ep - 1) == '"') + *--ep = 0; + + return 1; +} + +static void +#ifdef __STDC__ +_bdf_add_property(bdf_font_t *font, char *name, char *value) +#else +_bdf_add_property(font, name, value) +bdf_font_t *font; +char *name, *value; +#endif +{ + unsigned long propid; + hashnode hn; + int len; + bdf_property_t *prop, *fp; + + /* + * First, check to see if the property already exists in the font. + */ + if ((hn = hash_lookup(name, (hashtable *) font->internal)) != 0) { + /* + * The property already exists in the font, so simply replace + * the value of the property with the current value. + */ + fp = font->props + (unsigned long) hn->data; + + switch (fp->format) { + case BDF_ATOM: + /* + * Delete the current atom if it exists. + */ + if (fp->value.atom != 0) + free(fp->value.atom); + + if (value == 0) + len = 1; + else + len = strlen(value) + 1; + if (len > 1) { + fp->value.atom = (char *) malloc(len); + (void) memcpy(fp->value.atom, value, len); + } else + fp->value.atom = 0; + break; + case BDF_INTEGER: + fp->value.int32 = _bdf_atol(value, 0, 10); + break; + case BDF_CARDINAL: + fp->value.card32 = _bdf_atoul(value, 0, 10); + break; + } + return; + } + + /* + * See if this property type exists yet or not. If not, create it. + */ + hn = hash_lookup(name, &proptbl); + if (hn == 0) { + bdf_create_property(name, BDF_ATOM); + hn = hash_lookup(name, &proptbl); + } + + /* + * Allocate another property if this is overflow. + */ + if (font->props_used == font->props_size) { + if (font->props_size == 0) + font->props = (bdf_property_t *) malloc(sizeof(bdf_property_t)); + else + font->props = (bdf_property_t *) + realloc((char *) font->props, sizeof(bdf_property_t) * + (font->props_size + 1)); + fp = font->props + font->props_size; + (void) memset((char *) fp, 0, sizeof(bdf_property_t)); + font->props_size++; + } + + propid = (unsigned long) hn->data; + if (propid >= _num_bdf_properties) + prop = user_props + (propid - _num_bdf_properties); + else + prop = _bdf_properties + propid; + + fp = font->props + font->props_used; + + fp->name = prop->name; + fp->format = prop->format; + fp->builtin = prop->builtin; + + switch (prop->format) { + case BDF_ATOM: + if (value == 0) + len = 1; + else + len = strlen(value) + 1; + if (len > 1) { + fp->value.atom = (char *) malloc(len); + (void) memcpy(fp->value.atom, value, len); + } else + fp->value.atom = 0; + break; + case BDF_INTEGER: + fp->value.int32 = _bdf_atol(value, 0, 10); + break; + case BDF_CARDINAL: + fp->value.card32 = _bdf_atoul(value, 0, 10); + break; + } + + /* + * If the property happens to be a comment, then it doesn't need + * to be added to the internal hash table. + */ + if (memcmp(name, "COMMENT", 7) != 0) + /* + * Add the property to the font property table. + */ + hash_insert(fp->name, (void *) font->props_used, + (hashtable *) font->internal); + + font->props_used++; + + /* + * Some special cases need to be handled here. The DEFAULT_CHAR property + * needs to be located if it exists in the property list, the FONT_ASCENT + * and FONT_DESCENT need to be assigned if they are present, and the + * SPACING property should override the default spacing. + */ + if (memcmp(name, "DEFAULT_CHAR", 12) == 0) + font->default_glyph = fp->value.int32; + else if (memcmp(name, "FONT_ASCENT", 11) == 0) + font->font_ascent = fp->value.int32; + else if (memcmp(name, "FONT_DESCENT", 12) == 0) + font->font_descent = fp->value.int32; + else if (memcmp(name, "SPACING", 7) == 0) { + if (fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P') + font->spacing = BDF_PROPORTIONAL; + else if (fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M') + font->spacing = BDF_MONOWIDTH; + else if (fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C') + font->spacing = BDF_CHARCELL; + } +} + +/* + * Actually parse the glyph info and bitmaps. + */ +static int +#ifdef __STDC__ +_bdf_parse_glyphs(char *line, unsigned long linelen, unsigned long lineno, + void *call_data, void *client_data) +#else +_bdf_parse_glyphs(line, linelen, lineno, call_data, client_data) +char *line; +unsigned long linelen, lineno; +void *call_data, *client_data; +#endif +{ + int c; + char *s; + unsigned char *bp; + unsigned long i, slen, nibbles; + double ps, rx, dw, sw; + _bdf_line_func_t *next; + _bdf_parse_t *p; + bdf_glyph_t *glyph; + bdf_font_t *font; + char nbuf[128]; + + next = (_bdf_line_func_t *) call_data; + p = (_bdf_parse_t *) client_data; + + font = p->font; + + /* + * Check for a comment. + */ + if (memcmp(line, "COMMENT", 7) == 0) { + linelen -= 7; + s = line + 7; + if (*s != 0) { + s++; + linelen--; + } + _bdf_add_comment(p->font, s, linelen); + return 0; + } + + /* + * The very first thing expected is the number of glyphs. + */ + if (!(p->flags & _BDF_GLYPHS)) { + if (memcmp(line, "CHARS", 5) != 0) { + sprintf(nbuf, ERRMSG1, lineno, "CHARS"); + _bdf_add_acmsg(p->font, nbuf, strlen(nbuf)); + return BDF_MISSING_CHARS; + } + _bdf_split(" +", line, linelen, &p->list); + p->cnt = font->glyphs_size = _bdf_atoul(p->list.field[1], 0, 10); + + /* + * Make sure the number of glyphs is non-zero. + */ + if (p->cnt == 0) + font->glyphs_size = 64; + + font->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * + font->glyphs_size); + + /* + * Set up the callback to indicate the glyph loading is about to + * begin. + */ + if (p->callback != 0) { + p->cb.reason = BDF_LOAD_START; + p->cb.total = p->cnt; + p->cb.current = 0; + (*p->callback)(&p->cb, p->client_data); + } + p->flags |= _BDF_GLYPHS; + return 0; + } + + /* + * Check for the ENDFONT field. + */ + if (memcmp(line, "ENDFONT", 7) == 0) { + /* + * Sort the glyphs by encoding. + */ + qsort((char *) font->glyphs, font->glyphs_used, sizeof(bdf_glyph_t), + by_encoding); + + p->flags &= ~_BDF_START; + return 0; + } + + /* + * Check for the ENDCHAR field. + */ + if (memcmp(line, "ENDCHAR", 7) == 0) { + /* + * Set up and call the callback if it was passed. + */ + if (p->callback != 0) { + p->cb.reason = BDF_LOADING; + p->cb.total = font->glyphs_size; + p->cb.current = font->glyphs_used; + (*p->callback)(&p->cb, p->client_data); + } + p->glyph_enc = 0; + p->flags &= ~_BDF_GLYPH_BITS; + return 0; + } + + /* + * Check to see if a glyph is being scanned but should be ignored + * because it is an unencoded glyph. + */ + if ((p->flags & _BDF_GLYPH) && + p->glyph_enc == -1 && p->opts->keep_unencoded == 0) + return 0; + + /* + * Check for the STARTCHAR field. + */ + if (memcmp(line, "STARTCHAR", 9) == 0) { + /* + * Set the character name in the parse info first until the + * encoding can be checked for an unencoded character. + */ + if (p->glyph_name != 0) + free(p->glyph_name); + _bdf_split(" +", line, linelen, &p->list); + _bdf_shift(1, &p->list); + s = _bdf_join(' ', &slen, &p->list); + p->glyph_name = (char *) malloc(slen + 1); + (void) memcpy(p->glyph_name, s, slen + 1); + p->flags |= _BDF_GLYPH; + return 0; + } + + /* + * Check for the ENCODING field. + */ + if (memcmp(line, "ENCODING", 8) == 0) { + if (!(p->flags & _BDF_GLYPH)) { + /* + * Missing STARTCHAR field. + */ + sprintf(nbuf, ERRMSG1, lineno, "STARTCHAR"); + _bdf_add_acmsg(font, nbuf, strlen(nbuf)); + return BDF_MISSING_STARTCHAR; + } + _bdf_split(" +", line, linelen, &p->list); + p->glyph_enc = _bdf_atol(p->list.field[1], 0, 10); + + /* + * Check to see if this encoding has already been encountered. If it + * has then change it to unencoded so it gets added if indicated. + */ + if (p->glyph_enc >= 0) { + if (_bdf_glyph_modified(p->have, p->glyph_enc)) { + /* + * Add a message saying a glyph has been moved to the + * unencoded area. + */ + sprintf(nbuf, ACMSG12, p->glyph_enc, p->glyph_name); + _bdf_add_acmsg(font, nbuf, strlen(nbuf)); + p->glyph_enc = -1; + font->modified = 1; + } else + _bdf_set_glyph_modified(p->have, p->glyph_enc); + } + + if (p->glyph_enc >= 0) { + /* + * Make sure there are enough glyphs allocated in case the + * number of characters happen to be wrong. + */ + if (font->glyphs_used == font->glyphs_size) { + font->glyphs = (bdf_glyph_t *) + realloc((char *) font->glyphs, + sizeof(bdf_glyph_t) * (font->glyphs_size + 64)); + (void) memset((char *)(font->glyphs + font->glyphs_size), + 0, sizeof(bdf_glyph_t) << 6); + font->glyphs_size += 64; + } + + glyph = font->glyphs + font->glyphs_used++; + glyph->name = p->glyph_name; + glyph->encoding = p->glyph_enc; + + /* + * Reset the initial glyph info. + */ + p->glyph_name = 0; + } else { + /* + * Unencoded glyph. Check to see if it should be added or not. + */ + if (p->opts->keep_unencoded != 0) { + /* + * Allocate the next unencoded glyph. + */ + if (font->unencoded_used == font->unencoded_size) { + if (font->unencoded_size == 0) + font->unencoded = (bdf_glyph_t *) + malloc(sizeof(bdf_glyph_t) << 2); + else + font->unencoded = (bdf_glyph_t *) + realloc((char *) font->unencoded, + sizeof(bdf_glyph_t) * + (font->unencoded_size + 4)); + font->unencoded_size += 4; + } + + glyph = font->unencoded + font->unencoded_used; + glyph->name = p->glyph_name; + glyph->encoding = font->unencoded_used++; + } else + /* + * Free up the glyph name if the unencoded shouldn't be + * kept. + */ + free(p->glyph_name); + + p->glyph_name = 0; + } + + /* + * Clear the flags that might be added when width and height are + * checked for consistency. + */ + p->flags &= ~(_BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK); + + p->flags |= _BDF_ENCODING; + return 0; + } + + /* + * Point at the glyph being constructed. + */ + if (p->glyph_enc == -1) + glyph = font->unencoded + (font->unencoded_used - 1); + else + glyph = font->glyphs + (font->glyphs_used - 1); + + /* + * Check to see if a bitmap is being constructed. + */ + if (p->flags & _BDF_BITMAP) { + /* + * If there are more rows than are specified in the glyph metrics, + * ignore the remaining lines. + */ + if (p->row >= glyph->bbx.height) { + if (!(p->flags & _BDF_GLYPH_HEIGHT_CHECK)) { + sprintf(nbuf, ACMSG13, glyph->encoding); + _bdf_add_acmsg(font, nbuf, strlen(nbuf)); + p->flags |= _BDF_GLYPH_HEIGHT_CHECK; + font->modified = 1; + } + return 0; + } + + /* + * Only collect the number of nibbles indicated by the glyph metrics. + * If there are more columns, they are simply ignored. + */ + nibbles = p->bpr << 1; + bp = glyph->bitmap + (p->row * p->bpr); + for (i = 0, *bp = 0; i < nibbles; i++) { + c = line[i]; + *bp = (*bp << 4) + a2i[c]; + if (i + 1 < nibbles && (i & 1)) + *++bp = 0; + } + + /* + * If any line has extra columns, indicate they have been removed. + */ + if ((line[nibbles] == '0' || a2i[(int) line[nibbles]] != 0) && + !(p->flags & _BDF_GLYPH_WIDTH_CHECK)) { + sprintf(nbuf, ACMSG14, glyph->encoding); + _bdf_add_acmsg(font, nbuf, strlen(nbuf)); + p->flags |= _BDF_GLYPH_WIDTH_CHECK; + font->modified = 1; + } + + p->row++; + return 0; + } + + /* + * Expect the SWIDTH (scalable width) field next. + */ + if (memcmp(line, "SWIDTH", 6) == 0) { + if (!(p->flags & _BDF_ENCODING)) { + /* + * Missing ENCODING field. + */ + sprintf(nbuf, ERRMSG1, lineno, "ENCODING"); + _bdf_add_acmsg(font, nbuf, strlen(nbuf)); + return BDF_MISSING_ENCODING; + } + _bdf_split(" +", line, linelen, &p->list); + glyph->swidth = _bdf_atoul(p->list.field[1], 0, 10); + p->flags |= _BDF_SWIDTH; + return 0; + } + + /* + * Expect the DWIDTH (scalable width) field next. + */ + if (memcmp(line, "DWIDTH", 6) == 0) { + _bdf_split(" +", line, linelen, &p->list); + glyph->dwidth = _bdf_atoul(p->list.field[1], 0, 10); + + if (!(p->flags & _BDF_SWIDTH)) { + /* + * Missing SWIDTH field. Add an auto correction message and set + * the scalable width from the device width. + */ + sprintf(nbuf, ACMSG9, lineno); + _bdf_add_acmsg(font, nbuf, strlen(nbuf)); + ps = (double) font->point_size; + rx = (double) font->resolution_x; + dw = (double) glyph->dwidth; + glyph->swidth = (unsigned short)((dw * 72000.0) / (ps * rx)); + } + + p->flags |= _BDF_DWIDTH; + return 0; + } + + /* + * Expect the BBX field next. + */ + if (memcmp(line, "BBX", 3) == 0) { + _bdf_split(" +", line, linelen, &p->list); + glyph->bbx.width = _bdf_atos(p->list.field[1], 0, 10); + glyph->bbx.height = _bdf_atos(p->list.field[2], 0, 10); + glyph->bbx.x_offset = _bdf_atos(p->list.field[3], 0, 10); + glyph->bbx.y_offset = _bdf_atos(p->list.field[4], 0, 10); + + /* + * Generate the ascent and descent of the character. + */ + glyph->bbx.ascent = glyph->bbx.height + glyph->bbx.y_offset; + glyph->bbx.descent = -glyph->bbx.y_offset; + + /* + * Determine the overall font bounding box as the characters are + * loaded so corrections can be done later if indicated. + */ + p->maxas = MAX(glyph->bbx.ascent, p->maxas); + p->maxds = MAX(glyph->bbx.descent, p->maxds); + p->rbearing = glyph->bbx.width + glyph->bbx.x_offset; + p->maxrb = MAX(p->rbearing, p->maxrb); + p->minlb = MIN(glyph->bbx.x_offset, p->minlb); + p->maxlb = MAX(glyph->bbx.x_offset, p->maxlb); + + if (!(p->flags & _BDF_DWIDTH)) { + /* + * Missing DWIDTH field. Add an auto correction message and set + * the device width to the glyph width. + */ + sprintf(nbuf, ACMSG10, lineno); + _bdf_add_acmsg(font, nbuf, strlen(nbuf)); + glyph->dwidth = glyph->bbx.width; + } + + /* + * If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH + * value if necessary. + */ + if (p->opts->correct_metrics != 0) { + /* + * Determine the point size of the glyph. + */ + ps = (double) font->point_size; + rx = (double) font->resolution_x; + dw = (double) glyph->dwidth; + sw = (unsigned short)((dw * 72000.0) / (ps * rx)); + + if (sw != glyph->swidth) { + glyph->swidth = (unsigned short) sw; + if (p->glyph_enc == -1) + _bdf_set_glyph_modified(font->umod, + font->unencoded_used - 1); + else + _bdf_set_glyph_modified(font->nmod, glyph->encoding); + p->flags |= _BDF_SWIDTH_ADJ; + font->modified = 1; + } + } + p->flags |= _BDF_BBX; + return 0; + } + + /* + * And finally, gather up the bitmap. + */ + if (memcmp(line, "BITMAP", 6) == 0) { + if (!(p->flags & _BDF_BBX)) { + /* + * Missing BBX field. + */ + sprintf(nbuf, ERRMSG1, lineno, "BBX"); + _bdf_add_acmsg(font, nbuf, strlen(nbuf)); + return BDF_MISSING_BBX; + } + /* + * Allocate enough space for the bitmap. + */ + p->bpr = ((glyph->bbx.width * p->font->bpp) + 7) >> 3; + glyph->bytes = p->bpr * glyph->bbx.height; + glyph->bitmap = (unsigned char *) malloc(glyph->bytes); + p->row = 0; + p->flags |= _BDF_BITMAP; + return 0; + } + + return BDF_INVALID_LINE; +} + +/* + * Load the font properties. + */ +static int +#ifdef __STDC__ +_bdf_parse_properties(char *line, unsigned long linelen, unsigned long lineno, + void *call_data, void *client_data) +#else +_bdf_parse_properties(line, linelen, lineno, call_data, client_data) +char *line; +unsigned long linelen, lineno; +void *call_data, *client_data; +#endif +{ + unsigned long vlen; + _bdf_line_func_t *next; + _bdf_parse_t *p; + char *name, *value, nbuf[128]; + + next = (_bdf_line_func_t *) call_data; + p = (_bdf_parse_t *) client_data; + + /* + * Check for the end of the properties. + */ + if (memcmp(line, "ENDPROPERTIES", 13) == 0) { + /* + * If the FONT_ASCENT or FONT_DESCENT properties have not been + * encountered yet, then make sure they are added as properties and + * make sure they are set from the font bounding box info. + * + * This is *always* done regardless of the options, because X11 + * requires these two fields to compile fonts. + */ + if (bdf_get_font_property(p->font, "FONT_ASCENT") == 0) { + p->font->font_ascent = p->font->bbx.ascent; + sprintf(nbuf, "%hd", p->font->bbx.ascent); + _bdf_add_property(p->font, "FONT_ASCENT", nbuf); + sprintf(nbuf, ACMSG1, p->font->bbx.ascent); + _bdf_add_acmsg(p->font, nbuf, strlen(nbuf)); + p->font->modified = 1; + } + if (bdf_get_font_property(p->font, "FONT_DESCENT") == 0) { + p->font->font_descent = p->font->bbx.descent; + sprintf(nbuf, "%hd", p->font->bbx.descent); + _bdf_add_property(p->font, "FONT_DESCENT", nbuf); + sprintf(nbuf, ACMSG2, p->font->bbx.descent); + _bdf_add_acmsg(p->font, nbuf, strlen(nbuf)); + p->font->modified = 1; + } + p->flags &= ~_BDF_PROPS; + *next = _bdf_parse_glyphs; + return 0; + } + + /* + * Ignore the _XFREE86_GLYPH_RANGES properties. + */ + if (memcmp(line, "_XFREE86_GLYPH_RANGES", 21) == 0) + return 0; + + /* + * Handle COMMENT fields and properties in a special way to preserve + * the spacing. + */ + if (memcmp(line, "COMMENT", 7) == 0) { + name = value = line; + value += 7; + if (*value) + *value++ = 0; + _bdf_add_property(p->font, name, value); + } else if (_bdf_is_atom(line, linelen, &name, &value)) + _bdf_add_property(p->font, name, value); + else { + _bdf_split(" +", line, linelen, &p->list); + name = p->list.field[0]; + _bdf_shift(1, &p->list); + value = _bdf_join(' ', &vlen, &p->list); + _bdf_add_property(p->font, name, value); + } + + return 0; +} + +/* + * Load the font header. + */ +static int +#ifdef __STDC__ +_bdf_parse_start(char *line, unsigned long linelen, unsigned long lineno, + void *call_data, void *client_data) +#else +_bdf_parse_start(line, linelen, lineno, call_data, client_data) +char *line; +unsigned long linelen, lineno; +void *call_data, *client_data; +#endif +{ + unsigned long slen; + _bdf_line_func_t *next; + _bdf_parse_t *p; + bdf_font_t *font; + char *s, nbuf[128]; + + next = (_bdf_line_func_t *) call_data; + p = (_bdf_parse_t *) client_data; + + /* + * Check for a comment. This is done to handle those fonts that have + * comments before the STARTFONT line for some reason. + */ + if (memcmp(line, "COMMENT", 7) == 0) { + if (p->opts->keep_comments != 0 && p->font != 0) { + linelen -= 7; + s = line + 7; + if (*s != 0) { + s++; + linelen--; + } + _bdf_add_comment(p->font, s, linelen); + } + return 0; + } + + if (!(p->flags & _BDF_START)) { + if (memcmp(line, "STARTFONT", 9) != 0) + /* + * No STARTFONT field is a good indication of a problem. + */ + return BDF_MISSING_START; + p->flags = _BDF_START; + p->font = font = (bdf_font_t *) calloc(1, sizeof(bdf_font_t)); + p->font->internal = (void *) malloc(sizeof(hashtable)); + hash_init((hashtable *) p->font->internal); + p->font->spacing = p->opts->font_spacing; + p->font->default_glyph = -1; + return 0; + } + + /* + * Check for the start of the properties. + */ + if (memcmp(line, "STARTPROPERTIES", 15) == 0) { + _bdf_split(" +", line, linelen, &p->list); + p->cnt = p->font->props_size = _bdf_atoul(p->list.field[1], 0, 10); + p->font->props = (bdf_property_t *) + malloc(sizeof(bdf_property_t) * p->cnt); + p->flags |= _BDF_PROPS; + *next = _bdf_parse_properties; + return 0; + } + + /* + * Check for the FONTBOUNDINGBOX field. + */ + if (memcmp(line, "FONTBOUNDINGBOX", 15) == 0) { + if (!(p->flags & _BDF_SIZE)) { + /* + * Missing the SIZE field. + */ + sprintf(nbuf, ERRMSG1, lineno, "SIZE"); + _bdf_add_acmsg(p->font, nbuf, strlen(nbuf)); + return BDF_MISSING_SIZE; + } + _bdf_split(" +", line, linelen, &p->list); + p->font->bbx.width = _bdf_atos(p->list.field[1], 0, 10); + p->font->bbx.height = _bdf_atos(p->list.field[2], 0, 10); + p->font->bbx.x_offset = _bdf_atos(p->list.field[3], 0, 10); + p->font->bbx.y_offset = _bdf_atos(p->list.field[4], 0, 10); + p->font->bbx.ascent = p->font->bbx.height + p->font->bbx.y_offset; + p->font->bbx.descent = -p->font->bbx.y_offset; + p->flags |= _BDF_FONT_BBX; + return 0; + } + + /* + * The next thing to check for is the FONT field. + */ + if (memcmp(line, "FONT", 4) == 0) { + _bdf_split(" +", line, linelen, &p->list); + _bdf_shift(1, &p->list); + s = _bdf_join(' ', &slen, &p->list); + p->font->name = (char *) malloc(slen + 1); + (void) memcpy(p->font->name, s, slen + 1); + /* + * If the font name is an XLFD name, set the spacing to the one in the + * font name. If there is no spacing fall back on the default. + */ + _bdf_set_default_spacing(p->font, p->opts); + p->flags |= _BDF_FONT_NAME; + return 0; + } + + /* + * Check for the SIZE field. + */ + if (memcmp(line, "SIZE", 4) == 0) { + if (!(p->flags & _BDF_FONT_NAME)) { + /* + * Missing the FONT field. + */ + sprintf(nbuf, ERRMSG1, lineno, "FONT"); + _bdf_add_acmsg(p->font, nbuf, strlen(nbuf)); + return BDF_MISSING_FONTNAME; + } + _bdf_split(" +", line, linelen, &p->list); + p->font->point_size = _bdf_atoul(p->list.field[1], 0, 10); + p->font->resolution_x = _bdf_atoul(p->list.field[2], 0, 10); + p->font->resolution_y = _bdf_atoul(p->list.field[3], 0, 10); + + /* + * Check for the bits per pixel field. + */ + if (p->list.used == 5) { + p->font->bpp = _bdf_atos(p->list.field[4], 0, 10); + if (p->font->bpp > 1 && (p->font->bpp & 1)) { + /* + * Move up to the next bits per pixel value if an odd number + * is encountered. + */ + p->font->bpp++; + if (p->font->bpp <= 4) { + sprintf(nbuf, ACMSG11, p->font->bpp); + _bdf_add_acmsg(p->font, nbuf, strlen(nbuf)); + } + } + if (p->font->bpp > 4) { + sprintf(nbuf, ACMSG11, p->font->bpp); + _bdf_add_acmsg(p->font, nbuf, strlen(nbuf)); + p->font->bpp = 4; + } + } else + p->font->bpp = 1; + + p->flags |= _BDF_SIZE; + return 0; + } + + return BDF_INVALID_LINE; +} + +/************************************************************************** + * + * API. + * + **************************************************************************/ + +void +#ifdef __STDC__ +bdf_setup(void) +#else +bdf_setup() +#endif +{ + unsigned long i; + bdf_property_t *prop; + + hash_init(&proptbl); + for (i = 0, prop = _bdf_properties; i < _num_bdf_properties; i++, prop++) + hash_insert(prop->name, (void *) i, &proptbl); +} + +void +#ifdef __STDC__ +bdf_cleanup(void) +#else +bdf_cleanup() +#endif +{ + unsigned long i; + bdf_property_t *prop; + + hash_free(&proptbl); + + /* + * Free up the user defined properties. + */ + for (prop = user_props, i = 0; i < nuser_props; i++, prop++) { + free(prop->name); + if (prop->format == BDF_ATOM && prop->value.atom != 0) + free(prop->value.atom); + } + if (nuser_props > 0) + free((char *) user_props); + + _bdf_glyph_name_cleanup(); +} + +bdf_font_t * +#ifdef __STDC__ +bdf_load_font(FILE *in, bdf_options_t *opts, bdf_callback_t callback, + void *data) +#else +bdf_load_font(in, opts, callback, data) +FILE *in; +bdf_options_t *opts; +bdf_callback_t callback; +void *data; +#endif +{ + int n; + unsigned long lineno; + char msgbuf[128]; + _bdf_parse_t p; + + (void) memset((char *) &p, 0, sizeof(_bdf_parse_t)); + p.opts = (opts != 0) ? opts : &_bdf_opts; + p.minlb = 32767; + p.callback = callback; + p.client_data = data; + n = _bdf_readlines(fileno(in), _bdf_parse_start, (void *) & p, &lineno); + + if (p.font != 0) { + /* + * If the font is not proportional, set the fonts monowidth + * field to the width of the font bounding box. + */ + if (p.font->spacing != BDF_PROPORTIONAL) + p.font->monowidth = p.font->bbx.width; + + /* + * If the number of glyphs loaded is not that of the original count, + * indicate the difference. + */ + if (p.cnt != p.font->glyphs_used + p.font->unencoded_used) { + sprintf(msgbuf, ACMSG15, p.cnt, + p.font->glyphs_used + p.font->unencoded_used); + _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf)); + p.font->modified = 1; + } + + /* + * Once the font has been loaded, adjust the overall font metrics if + * necessary. + */ + if (p.opts->correct_metrics != 0 && + (p.font->glyphs_used > 0 || p.font->unencoded_used > 0)) { + if (p.maxrb - p.minlb != p.font->bbx.width) { + sprintf(msgbuf, ACMSG3, p.font->bbx.width, p.maxrb - p.minlb); + _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf)); + p.font->bbx.width = p.maxrb - p.minlb; + p.font->modified = 1; + } + if (p.font->bbx.x_offset != p.minlb) { + sprintf(msgbuf, ACMSG4, p.font->bbx.x_offset, p.minlb); + _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf)); + p.font->bbx.x_offset = p.minlb; + p.font->modified = 1; + } + if (p.font->bbx.ascent != p.maxas) { + sprintf(msgbuf, ACMSG5, p.font->bbx.ascent, p.maxas); + _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf)); + p.font->bbx.ascent = p.maxas; + p.font->modified = 1; + } + if (p.font->bbx.descent != p.maxds) { + sprintf(msgbuf, ACMSG6, p.font->bbx.descent, p.maxds); + _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf)); + p.font->bbx.descent = p.maxds; + p.font->bbx.y_offset = -p.maxds; + p.font->modified = 1; + } + if (p.maxas + p.maxds != p.font->bbx.height) { + sprintf(msgbuf, ACMSG7, p.font->bbx.height, p.maxas + p.maxds); + _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf)); + } + p.font->bbx.height = p.maxas + p.maxds; + + if (p.flags & _BDF_SWIDTH_ADJ) + _bdf_add_acmsg(p.font, ACMSG8, strlen(ACMSG8)); + } + } + + /* + * Last, if an error happened during loading, handle the messages. + */ + if (n < 0 && callback != 0) { + /* + * An error was returned. Alert the client. + */ + p.cb.reason = BDF_ERROR; + p.cb.errlineno = lineno; + (*callback)(&p.cb, data); + } else if (p.flags & _BDF_START) { + if (p.font != 0) { + /* + * The ENDFONT field was never reached or did not exist. + */ + if (!(p.flags & _BDF_GLYPHS)) + /* + * Error happened while parsing header. + */ + sprintf(msgbuf, ERRMSG2, lineno); + else + /* + * Error happened when parsing glyphs. + */ + sprintf(msgbuf, ERRMSG3, lineno); + + _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf)); + } + + if (callback != 0) { + p.cb.reason = BDF_ERROR; + p.cb.errlineno = lineno; + (*callback)(&p.cb, data); + } + } else if (callback != 0) { + /* + * This forces the progress bar to always finish. + */ + p.cb.current = p.cb.total; + (*p.callback)(&p.cb, p.client_data); + } + + /* + * Free up the list used during the parsing. + */ + if (p.list.size > 0) + free((char *) p.list.field); + + if (p.font != 0) { + /* + * Make sure the comments are NULL terminated if they exist. + */ + if (p.font->comments_len > 0) { + p.font->comments = (char *) realloc(p.font->comments, + p.font->comments_len + 1); + p.font->comments[p.font->comments_len] = 0; + } + + /* + * Make sure the auto-correct messages are NULL terminated if they + * exist. + */ + if (p.font->acmsgs_len > 0) { + p.font->acmsgs = (char *) realloc(p.font->acmsgs, + p.font->acmsgs_len + 1); + p.font->acmsgs[p.font->acmsgs_len] = 0; + } + } + + return p.font; +} + +#ifdef HAVE_HBF +static int +#ifdef __STDC__ +_bdf_parse_hbf_header(char *line, unsigned long linelen, unsigned long lineno, + void *call_data, void *client_data) +#else +_bdf_parse_hbf_header(line, linelen, lineno, call_data, client_data) +char *line; +unsigned long linelen, lineno; +void *call_data, *client_data; +#endif +{ + unsigned long vlen; + char *name, *value; + _bdf_parse_t *p; + _bdf_line_func_t *next; + char nbuf[24]; + + next = (_bdf_line_func_t *) call_data; + p = (_bdf_parse_t *) client_data; + + /* + * Check for comments. + */ + if (memcmp(line, "COMMENT", 7) == 0) { + if (p->opts->keep_comments != 0 && p->font != 0) { + name = line; + value = name + 7; + vlen = linelen - 7; + if (*value) { + *value++ = 0; + vlen--; + } + /* + * If the properties are being parsed, add the comment as a + * property. Otherwise, simply add the comment in the normal + * fashion. + */ + if (p->flags & _BDF_PROPS) + _bdf_add_property(p->font, name, value); + else + _bdf_add_comment(p->font, value, vlen); + } + return 0; + } + + if (!(p->flags & _BDF_START)) { + if (memcmp(line, "HBF_START_FONT", 14) != 0) + return -1; + p->flags = _BDF_START; + p->font = (bdf_font_t *) calloc(1, sizeof(bdf_font_t)); + /* + * HBF fonts are always assumed to be 1 bit per pixel. + */ + p->font->bpp = 1; + p->font->internal = (void *) malloc(sizeof(hashtable)); + hash_init((hashtable *) p->font->internal); + p->font->hbf = 1; + p->font->spacing = p->opts->font_spacing; + p->font->default_glyph = -1; + return 0; + } + + /* + * Check for the HBF_END_FONT field. + */ + if (memcmp(line, "HBF_END_FONT", 12) == 0) + /* + * Need to perform some checks here to see whether some fields are + * missing or not. + */ + return 0; + + /* + * Check for HBF keywords which will be added as comments. These should + * never occur in the properties list. Assume they won't. + */ + if (memcmp(line, "HBF_", 4) == 0) { + if (p->opts->keep_comments != 0) + _bdf_add_comment(p->font, line, linelen); + return 0; + } + + if (!(p->flags & _BDF_PROPS)) { + /* + * Check for the start of the properties. + */ + if (memcmp(line, "STARTPROPERTIES", 15) == 0) { + _bdf_split(" +", line, linelen, &p->list); + p->cnt = p->font->props_size = _bdf_atoul(p->list.field[1], 0, 10); + p->font->props = (bdf_property_t *) + malloc(sizeof(bdf_property_t) * p->cnt); + p->flags |= _BDF_PROPS; + return 0; + } + + /* + * Check for the CHARS field. + */ + if (memcmp(line, "CHARS", 5) == 0) { + _bdf_split(" +", line, linelen, &p->list); + p->cnt = p->font->glyphs_size = + _bdf_atoul(p->list.field[1], 0, 10); + p->font->glyphs = (bdf_glyph_t *) + malloc(sizeof(bdf_glyph_t) * p->cnt); + return 0; + } + + /* + * Check for the FONTBOUNDINGBOX field. + */ + if (memcmp(line, "FONTBOUNDINGBOX", 15) == 0) { + if (!(p->flags & (_BDF_START | _BDF_FONT_NAME | _BDF_SIZE))) + return -1; + _bdf_split(" +", line, linelen, &p->list); + p->font->bbx.width = _bdf_atos(p->list.field[1], 0, 10); + p->font->bbx.height = _bdf_atos(p->list.field[2], 0, 10); + p->font->bbx.x_offset = _bdf_atos(p->list.field[3], 0, 10); + p->font->bbx.y_offset = _bdf_atos(p->list.field[4], 0, 10); + p->font->bbx.ascent = p->font->bbx.height + p->font->bbx.y_offset; + p->font->bbx.descent = -p->font->bbx.y_offset; + p->flags |= _BDF_FONT_BBX; + return 0; + } + + /* + * The next thing to check for is the FONT field. + */ + if (memcmp(line, "FONT", 4) == 0) { + if (!(p->flags & _BDF_START)) + return -1; + _bdf_split(" +", line, linelen, &p->list); + _bdf_shift(1, &p->list); + value = _bdf_join(' ', &vlen, &p->list); + p->font->name = (char *) malloc(vlen + 1); + (void) memcpy(p->font->name, value, vlen + 1); + /* + * If the font name is an XLFD name, set the spacing to the one in + * the font name. If there is no spacing fall back on the + * default. + */ + _bdf_set_default_spacing(p->font, p->opts); + p->flags |= _BDF_FONT_NAME; + return 0; + } + + /* + * Check for the SIZE field. + */ + if (memcmp(line, "SIZE", 4) == 0) { + if (!(p->flags & (_BDF_START | _BDF_FONT_NAME))) + return -1; + _bdf_split(" +", line, linelen, &p->list); + p->font->point_size = _bdf_atoul(p->list.field[1], 0, 10); + p->font->resolution_x = _bdf_atoul(p->list.field[2], 0, 10); + p->font->resolution_y = _bdf_atoul(p->list.field[3], 0, 10); + p->flags |= _BDF_SIZE; + return 0; + } + } else { + /* + * Check for the end of the properties. + */ + if (memcmp(line, "ENDPROPERTIES", 13) == 0) { + /* + * If the FONT_ASCENT or FONT_DESCENT properties have not been + * encountered yet, then make sure they are added as properties and + * make sure they are set from the font bounding box info. + * + * This is *always* done regardless of the options, because X11 + * requires these two fields to compile fonts. + */ + if (bdf_get_font_property(p->font, "FONT_ASCENT") == 0) { + p->font->font_ascent = p->font->bbx.ascent; + sprintf(nbuf, "%hd", p->font->bbx.ascent); + _bdf_add_property(p->font, "FONT_ASCENT", nbuf); + sprintf(nbuf, ACMSG1, p->font->bbx.ascent); + _bdf_add_acmsg(p->font, nbuf, strlen(nbuf)); + p->font->modified = 1; + } + if (bdf_get_font_property(p->font, "FONT_DESCENT") == 0) { + p->font->font_descent = p->font->bbx.descent; + sprintf(nbuf, "%hd", p->font->bbx.descent); + _bdf_add_property(p->font, "FONT_DESCENT", nbuf); + sprintf(nbuf, ACMSG2, p->font->bbx.descent); + _bdf_add_acmsg(p->font, nbuf, strlen(nbuf)); + p->font->modified = 1; + } + p->flags &= ~_BDF_PROPS; + return 0; + } + + /* + * Handle the next thing in the usual property fashion. + */ + if (_bdf_is_atom(line, linelen, &name, &value)) + _bdf_add_property(p->font, name, value); + else { + _bdf_split(" +", line, linelen, &p->list); + name = p->list.field[0]; + _bdf_shift(1, &p->list); + value = _bdf_join(' ', &vlen, &p->list); + _bdf_add_property(p->font, name, value); + } + return 0; + } + + /* + * Anything else is an error. + */ + return -1; +} + +#ifdef __STDC__ +#define CONST const +#else +#define CONST +#endif + +static void +#ifdef __STDC__ +_bdf_add_hbf_glyph(HBF *hbf, unsigned int code, void *callback_data) +#else +_bdf_add_hbf_glyph(hbf, code, callback_data) +HBF *hbf; +unsigned int code; +void *callback_data; +#endif +{ + CONST unsigned char *bmap; + unsigned long n; + bdf_glyph_t *gp; + bdf_font_t *font; + _bdf_parse_t *p; + HBF_BBOX *fbbx; + double ps, rx, dw; + char nbuf[24]; + + /* + * Attempt to get the bitmap. + */ + if ((bmap = hbfGetBitmap(hbf, code)) == 0) + /* + * Need some sort of error handling here. + */ + return; + + p = (_bdf_parse_t *) callback_data; + + fbbx = hbfFontBBox(hbf); + + font = p->font; + + /* + * Check to make sure there is enough space to hold this glyph. If not, + * allocate 10 more just in case. + */ + if (font->glyphs_used == font->glyphs_size) { + if (font->glyphs_size == 0) + font->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * 16); + else + font->glyphs = (bdf_glyph_t *) + realloc((char *) font->glyphs, + sizeof(bdf_glyph_t) * (font->glyphs_used + 16)); + gp = font->glyphs + font->glyphs_size; + (void) memset((char *) gp, 0, sizeof(bdf_glyph_t) * 16); + font->glyphs_size += 16; + } + + gp = font->glyphs + font->glyphs_used++; + + /* + * Set the glyph name. + */ + sprintf(nbuf, "char%d", code); + n = (unsigned long) strlen(nbuf); + gp->name = (char *) malloc(n + 1); + (void) memcpy(gp->name, nbuf, n + 1); + + /* + * Set encoding. + */ + gp->encoding = (long) code; + + /* + * Set the device width. + */ + gp->dwidth = (unsigned short) fbbx->hbf_width; + + /* + * Set the scalable width. + */ + ps = (double) font->point_size; + rx = (double) font->resolution_x; + dw = (double) gp->dwidth; + gp->swidth = (unsigned short)((dw * 72000.0) / (ps * rx)); + + /* + * Set the glyph bounding box. + */ + gp->bbx.width = fbbx->hbf_width; + gp->bbx.height = fbbx->hbf_height; + gp->bbx.x_offset = fbbx->hbf_xDisplacement; + gp->bbx.y_offset = fbbx->hbf_yDisplacement; + gp->bbx.ascent = gp->bbx.height + gp->bbx.y_offset; + gp->bbx.descent = -gp->bbx.y_offset; + + /* + * Add the bitmap by making a copy. Assumes the font bbx is OK for + * determining the number of bytes needed for the glyph bitmap. + */ + gp->bytes = ((gp->bbx.width + 7) >> 3) * gp->bbx.height; + gp->bitmap = (unsigned char *) malloc(gp->bytes); + (void) memcpy((char *) gp->bitmap, (char *) bmap, gp->bytes); + + /* + * Call the callback if it was provided. + */ + if (p->callback != 0) { + p->cb.reason = BDF_LOADING; + p->cb.total = font->glyphs_size; + p->cb.current = font->glyphs_used; + (*p->callback)(&p->cb, p->client_data); + } +} + +bdf_font_t * +#ifdef __STDC__ +bdf_load_hbf_font(char *filename, bdf_options_t *opts, bdf_callback_t callback, + void *data) +#else +bdf_load_hbf_font(filename, opts, callback, data) +char *filename; +bdf_options_t *opts; +bdf_callback_t callback; +void *data; +#endif +{ + int n, diff; + unsigned long lineno; + FILE *in; + HBF *hbf; + bdf_property_t *pp; + char *name; + _bdf_parse_t p; + + if ((hbf = hbfOpen(filename)) == 0) + return 0; + + if ((in = fopen(hbfFileName(hbf), "r")) == 0) { + hbfClose(hbf); + return 0; + } + + /* + * Parse the HBF header for properties and other things. + */ + (void) memset((char *) &p, 0, sizeof(_bdf_parse_t)); + p.opts = (opts != 0) ? opts : &_bdf_opts; + p.minlb = 32767; + p.callback = callback; + p.client_data = data; + + n = _bdf_readlines(fileno(in), _bdf_parse_hbf_header, (void *) & p, + &lineno); + + fclose(in); + + /* + * Determine what spacing the font has so the monowidth field can be set + * if necessary. + */ + if ((pp = bdf_get_font_property(p.font, "SPACING")) != 0) { + switch (pp->value.atom[0]) { + case 'p': + case 'P': + p.font->spacing = BDF_PROPORTIONAL; + break; + case 'm': + case 'M': + p.font->spacing = BDF_MONOWIDTH; + break; + case 'c': + case 'C': + p.font->spacing = BDF_CHARCELL; + break; + } + } + + /* + * Set the monowidth field if necessary. + */ + if (p.font->spacing != BDF_PROPORTIONAL) + p.font->monowidth = p.font->bbx.width; + + /* + * Before loading the glyphs, check to see if any glyph structures have + * been added. If not, check the HBF font for the number of characters. + * Dynamically increasing glyph storage causes memory fragmentation on + * some machines and crashes. This takes care of the cases where the HBF + * file does not provide a "CHARS n" line. + */ + if (p.font->glyphs_size < hbfChars(hbf)) { + if (p.font->glyphs_size == 0) + p.font->glyphs = (bdf_glyph_t *) + malloc(sizeof(bdf_glyph_t) * hbfChars(hbf)); + else + p.font->glyphs = (bdf_glyph_t *) + realloc((char *) p.font->glyphs, + sizeof(bdf_glyph_t) * hbfChars(hbf)); + diff = hbfChars(hbf) - p.font->glyphs_size; + (void) memset((char *)(p.font->glyphs + p.font->glyphs_size), 0, + diff); + p.font->glyphs_size = hbfChars(hbf); + } + + /* + * Call the callback initially to set things up. + */ + if (p.callback != 0) { + p.cb.reason = BDF_LOAD_START; + p.cb.total = p.font->glyphs_size; + p.cb.current = 0; + (*p.callback)(&p.cb, p.client_data); + } + + /* + * Now load the glyphs. + */ + hbfForEach(hbf, _bdf_add_hbf_glyph, (void *) &p); + + /* + * Close the HBF font. + */ + hbfClose(hbf); + + /* + * Sort the glyphs by encoding. + */ + qsort((char *) p.font->glyphs, p.font->glyphs_used, sizeof(bdf_glyph_t), + by_encoding); + + /* + * After loading the HBF header, create an XLFD name. If the XLFD name + * cannot be made then preserve the name found in the HBF file. + */ + if ((name = bdf_make_xlfd_name(p.font, "HBF", "Unknown")) != 0) { + if (p.font->name != 0) + /* + * If a name already exists in the font, free it up. + */ + free(p.font->name); + + /* + * Replace the old name with the XLFD name. + */ + p.font->name = name; + } + + /* + * Mark the font as being modified and generate a message that says + * something about the font being converted from HBF format. + */ + p.font->modified = 1; + _bdf_add_acmsg(p.font, "Font converted from HBF to BDF.", 31); + + return p.font; +} +#endif /* HAVE_HBF */ + +/* + * Crop the glyph bitmap to the minimum rectangle needed to hold the bits that + * are set. Adjust the metrics based on the provided bounding box. + */ +static void +#ifdef __STDC__ +_bdf_crop_glyph(bdf_font_t *font, bdf_glyph_t *glyph) +#else +_bdf_crop_glyph(font, glyph) +bdf_font_t *font; +bdf_glyph_t *glyph; +#endif +{ + int byte; + unsigned short x, y, bpr, nbpr, col, colx, si, di; + unsigned short minx, maxx, miny, maxy; + unsigned long bytes; + unsigned char *bmap, *masks; + bdf_bbx_t nbbx; + + if (glyph == 0) + return; + + (void) memcpy((char *) &nbbx, (char *) &glyph->bbx, sizeof(bdf_bbx_t)); + + bpr = ((glyph->bbx.width * font->bpp) + 7) >> 3; + + maxx = maxy = 0; + minx = miny = 32767; + + masks = 0; + switch (font->bpp) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + for (y = 0; y < glyph->bbx.height; y++) { + for (col = x = 0; x < glyph->bbx.width; x++, col += font->bpp) { + si = (col & 7) / font->bpp; + if (glyph->bitmap[(y * bpr) + (col >> 3)] & masks[si]) { + minx = MIN(minx, x); + maxx = MAX(maxx, x); + miny = MIN(miny, y); + maxy = MAX(maxy, y); + } + } + } + + /* + * Handle an empty bitmap as a special case. + */ + if (minx == 32767) { + if (glyph->bytes > 0) + free((char *) glyph->bitmap); + glyph->bytes = 0; + (void) memset((char *) &glyph->bbx, 0, sizeof(bdf_bbx_t)); + return; + } + + /* + * Increment the max points so width and height calculations won't go + * wrong. + */ + maxx++; + maxy++; + + if (minx > 0) + nbbx.x_offset += minx; + if (maxx - minx != nbbx.width) + nbbx.width = maxx - minx; + + if (miny > 0) + nbbx.ascent -= miny; + if (maxy - miny != nbbx.height) + nbbx.height = maxy - miny; + nbbx.descent = nbbx.height - nbbx.ascent; + nbbx.y_offset = -nbbx.descent; + + nbpr = ((nbbx.width * font->bpp) + 7) >> 3; + + /* + * If nothing changed, then the glyph is already contained in the + * minimum rectangle. + */ + if (memcmp((char *) &nbbx, (char *) &glyph->bbx, + sizeof(bdf_bbx_t)) == 0 || + (nbpr == bpr && nbbx.height == glyph->bbx.height)) + return; + + /* + * The metrics changed, so a new bitmap is needed. + */ + bytes = nbpr * nbbx.height; + bmap = (unsigned char *) malloc(bytes); + (void) memset((char *) bmap, 0, bytes); + + colx = minx * font->bpp; + for (y = miny; y < maxy; y++) { + for (col = x = minx; x < maxx; x++, col += font->bpp) { + si = (col & 7) / font->bpp; + byte = glyph->bitmap[(y * bpr) + (col >> 3)] & masks[si]; + if (byte) { + /* + * Position the pixel in the byte if necessary. + */ + di = ((col - colx) & 7) / font->bpp; + if (di < si) + byte <<= (si - di) * font->bpp; + else if (di > si) + byte >>= (di - si) * font->bpp; + bmap[((y - miny) * nbpr) + ((col - colx) >> 3)] |= byte; + } + } + } + + if (glyph->bytes > 0) + free((char *) glyph->bitmap); + glyph->bytes = bytes; + glyph->bitmap = bmap; + + (void) memcpy((char *) &glyph->bbx, (char *) &nbbx, sizeof(bdf_bbx_t)); +} + +/* + * Pad a character-cell font glyph to match the bounds specified in the + * provided bounding box. + */ +static void +#ifdef __STDC__ +_bdf_pad_cell(bdf_font_t *font, bdf_glyph_t *glyph, bdf_glyph_t *cell) +#else +_bdf_pad_cell(font, glyph, cell) +bdf_font_t *font; +bdf_glyph_t *glyph, *cell; +#endif +{ + bdf_bbx_t *bbx; + unsigned short si, di, sx, byte; + unsigned short x, y, dx, dy, bx, by, bpr, nbpr; + unsigned char *bmap, *masks; + + masks = 0; + switch (font->bpp) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + bbx = &font->bbx; + + if (glyph->bbx.width == bbx->width && glyph->bbx.height == bbx->height) { + /* + * The glyph is already positioned in the cell. Copy the bitmap + * and return. + */ + (void) memcpy((char *) cell->bitmap, (char *) glyph->bitmap, + cell->bytes); + return; + } + + /* + * Determine the X and Y location of the baseline. + */ + bx = MYABS(bbx->x_offset - glyph->bbx.x_offset); + by = (bbx->ascent + bbx->descent) + bbx->y_offset; + + bpr = ((glyph->bbx.width * font->bpp) + 7) >> 3; + nbpr = ((bbx->width * font->bpp) + 7) >> 3; + + /* + * Set various cell values and clear the cell bitmap. + */ + bmap = cell->bitmap; + (void) memset((char *) bmap, 0, cell->bytes); + + for (dy = by - glyph->bbx.ascent, y = 0; y < glyph->bbx.height; + y++, dy++) { + for (dx = bx * font->bpp, sx = x = 0; x < glyph->bbx.width; + x++, dx += font->bpp, sx += font->bpp) { + si = (sx & 7) / font->bpp; + byte = glyph->bitmap[(y * bpr) + (sx >> 3)] & masks[si]; + if (byte) { + di = (dx & 7) / font->bpp; + if (di < si) + byte <<= (si - di) * font->bpp; + else if (di > si) + byte >>= (di - si) * font->bpp; + bmap[(dy * nbpr) + (dx >> 3)] |= byte; + } + } + } +} + +static char *unix_eol = "\n"; +static char *dos_eol = "\r\n"; +static char *mac_eol = "\r"; + +void +#ifdef __STDC__ +bdf_save_font(FILE *out, bdf_font_t *font, bdf_options_t *opts, + bdf_callback_t callback, void *data) +#else +bdf_save_font(out, font, opts, callback, data) +FILE *out; +bdf_font_t *font; +bdf_options_t *opts; +bdf_callback_t callback; +void *data; +#endif +{ + unsigned long i, j, bpr, pcnt; + double dw, ps, rx; + char *sp, *ep, *eol; + bdf_property_t *p; + bdf_glyph_t *c, *cp, cell; + bdf_callback_struct_t cb; + + if (font == 0) + return; + + eol = 0; + switch (opts->eol) { + case BDF_UNIX_EOL: + eol = unix_eol; + break; + case BDF_DOS_EOL: + eol = dos_eol; + break; + case BDF_MAC_EOL: + eol = mac_eol; + break; + } + + /* + * If the font is a character cell font, allocate some space for the + * bitmap. + */ + if (font->spacing == BDF_CHARCELL && opts->pad_cells != 0) { + bpr = ((font->bbx.width * font->bpp) + 7) >> 3; + cell.bytes = bpr * font->bbx.height; + cell.bitmap = (unsigned char *) malloc(cell.bytes); + } + + /* + * Emit the header. + */ + fprintf(out, "STARTFONT 2.1%s", eol); + + /* + * Emit the comments. + */ + if (font->comments_len > 0) { + for (sp = font->comments; *sp; sp++) { + ep = sp; + while (*ep && *ep != '\n') + ep++; + fprintf(out, "COMMENT %.*s%s", ep - sp, sp, eol); + sp = ep; + } + } + + /* + * Emit the font name. + */ + fprintf(out, "FONT %s%s", font->name, eol); + + /* + * Emit the size info. + */ + if (font->bpp == 1) + fprintf(out, "SIZE %ld %ld %ld%s", font->point_size, + font->resolution_x, font->resolution_y, eol); + else + fprintf(out, "SIZE %ld %ld %ld %hd%s", font->point_size, + font->resolution_x, font->resolution_y, font->bpp, eol); + + /* + * Emit the bounding box. + */ + fprintf(out, "FONTBOUNDINGBOX %hd %hd %hd %hd%s", + font->bbx.width, font->bbx.height, font->bbx.x_offset, + font->bbx.y_offset, eol); + + /* + * Emit the properties after counting how many are properties and + * how many are comments. + */ + for (i = pcnt = 0, p = font->props; i < font->props_used; i++, p++) { + if (memcmp(p->name, "COMMENT", 7) != 0) + pcnt++; + } + + fprintf(out, "STARTPROPERTIES %ld%s", pcnt, eol); + for (i = 0, p = font->props; i < font->props_used; i++, p++) { + fprintf(out, "%s ", p->name); + if (p->format == BDF_ATOM) { + if (p->value.atom == 0) + fprintf(out, "\"\"%s", eol); + else + fprintf(out, "\"%s\"%s", p->value.atom, eol); + } else + fprintf(out, "%ld%s", p->value.int32, eol); + } + + fprintf(out, "ENDPROPERTIES%s", eol); + + /* + * Emit the number of bitmaps in the font. + */ + fprintf(out, "CHARS %ld%s", font->unencoded_used + font->glyphs_used, eol); + + /* + * Call the callback if it was passed to start the save. + */ + if (callback != 0) { + cb.reason = BDF_SAVE_START; + cb.total = font->unencoded_used + font->glyphs_used; + cb.current = 0; + (*callback)(&cb, data); + } + + /* + * Emit the unencoded bitmaps. + */ + for (i = 0, cp = font->unencoded; i < font->unencoded_used; i++, cp++) { + /* + * If the font has character-cell spacing and the option to pad the + * glyphs to the size of the font bbx is set, then pad the glyph. + * Otherwise, crop the glyph to the minimum rectangle needed to hold + * the bitmap. + */ + if (font->spacing == BDF_CHARCELL && opts->pad_cells != 0) { + /* + * Point at the temporary glyph structure and copy the necessary + * glyph info into it. + */ + c = &cell; + c->name = cp->name; + c->encoding = cp->encoding; + c->swidth = cp->swidth; + c->dwidth = cp->dwidth; + (void) memcpy((char *) &c->bbx, (char *) &font->bbx, + sizeof(bdf_bbx_t)); + _bdf_pad_cell(font, cp, c); + } else { + c = cp; + _bdf_crop_glyph(font, c); + } + + /* + * If the font has monowidth or character-cell spacing, then assign + * the font monowidth field to the device width and recalculate the + * scalable width. + */ + if (font->spacing != BDF_PROPORTIONAL) { + c->dwidth = font->monowidth; + ps = (double) font->point_size; + rx = (double) font->resolution_x; + dw = (double) c->dwidth; + c->swidth = (unsigned short)((dw * 72000.0) / (ps * rx)); + } + if (c->name == 0) + fprintf(out, "STARTCHAR unencoded%ld%sENCODING -1%s", i, eol, eol); + else + fprintf(out, "STARTCHAR %s%sENCODING -1%s", c->name, eol, eol); + fprintf(out, "SWIDTH %hd 0%sDWIDTH %hd 0%s", + c->swidth, eol, c->dwidth, eol); + fprintf(out, "BBX %hd %hd %hd %hd%s", c->bbx.width, c->bbx.height, + c->bbx.x_offset, c->bbx.y_offset, eol); + fprintf(out, "BITMAP%s", eol); + bpr = ((c->bbx.width * font->bpp) + 7) >> 3; + for (j = 0; bpr != 0 && j < c->bytes; j++) { + if (j && j % bpr == 0) + fprintf(out, eol); + fprintf(out, "%02X", c->bitmap[j]); + } + /* + * Handle empty bitmaps like this. + */ + if (c->bbx.height > 0) + fprintf(out, eol); + fprintf(out, "ENDCHAR%s", eol); + + /* + * Call the callback if supplied. + */ + if (callback != 0) { + cb.reason = BDF_SAVING; + cb.current++; + (*callback)(&cb, data); + } + } + + /* + * Emit the other bitmaps. + */ + for (i = 0, cp = font->glyphs; i < font->glyphs_used; i++, cp++) { + /* + * If the font has character-cell spacing and the option to pad the + * glyphs to the size of the font bbx is set, then pad the glyph. + * Otherwise, crop the glyph to the minimum rectangle needed to hold + * the bitmap. + */ + if (font->spacing == BDF_CHARCELL && opts->pad_cells != 0) { + /* + * Point at the temporary glyph structure and copy the necessary + * glyph info into it. + */ + c = &cell; + c->name = cp->name; + c->encoding = cp->encoding; + c->swidth = cp->swidth; + c->dwidth = cp->dwidth; + (void) memcpy((char *) &c->bbx, (char *) &font->bbx, + sizeof(bdf_bbx_t)); + _bdf_pad_cell(font, cp, c); + } else { + c = cp; + _bdf_crop_glyph(font, c); + } + + /* + * If the font has monowidth or character-cell spacing, then assign + * the font monowidth field to the device width and recalculate the + * scalable width. + */ + if (font->spacing != BDF_PROPORTIONAL) { + c->dwidth = font->monowidth; + ps = (double) font->point_size; + rx = (double) font->resolution_x; + dw = (double) c->dwidth; + c->swidth = (unsigned short)((dw * 72000.0) / (ps * rx)); + } + if (c->name == 0) + fprintf(out, "STARTCHAR char%ld%sENCODING %ld%s", + c->encoding, eol, c->encoding, eol); + else + fprintf(out, "STARTCHAR %s%sENCODING %ld%s", + c->name, eol, c->encoding, eol); + fprintf(out, "SWIDTH %hd 0%sDWIDTH %hd 0%s", + c->swidth, eol, c->dwidth, eol); + fprintf(out, "BBX %hd %hd %hd %hd%s", c->bbx.width, c->bbx.height, + c->bbx.x_offset, c->bbx.y_offset, eol); + fprintf(out, "BITMAP%s", eol); + bpr = ((c->bbx.width * font->bpp) + 7) >> 3; + for (j = 0; bpr != 0 && j < c->bytes; j++) { + if (j && j % bpr == 0) + fprintf(out, eol); + fprintf(out, "%02X", c->bitmap[j]); + } + /* + * Handle empty bitmaps like this. + */ + if (c->bbx.height > 0) + fprintf(out, eol); + fprintf(out, "ENDCHAR%s", eol); + + /* + * Call the callback if supplied. + */ + if (callback != 0) { + cb.reason = BDF_SAVING; + cb.current++; + (*callback)(&cb, data); + } + } + + /* + * Emit the trailer. + */ + fprintf(out, "ENDFONT%s", eol); + + /* + * Always force a final call to the callback to make sure things + * get cleaned up. + */ + if (callback != 0) { + cb.reason = BDF_SAVING; + cb.current = cb.total; + (*callback)(&cb, data); + } + + /* + * If the font is a character cell font, clean up the temporary glyph. + */ + if (font->spacing == BDF_CHARCELL && opts->pad_cells != 0) + free((char *) cell.bitmap); +} + +/* + * Routine to write a single set of SBIT metrics. + */ +void +#ifdef __STDC__ +bdf_save_sbit_metrics(FILE *out, bdf_font_t *font, bdf_options_t *opts, + char *appname) +#else +bdf_save_sbit_metrics(out, font, opts, appname) +bdf_font_t *font; +bdf_options_t *opts; +char *appname; +#endif +{ + char *eol; + + eol = 0; + switch (opts->eol) { + case BDF_UNIX_EOL: + eol = unix_eol; + break; + case BDF_DOS_EOL: + eol = dos_eol; + break; + case BDF_MAC_EOL: + eol = mac_eol; + break; + } + + /* + * Throw a simple header in. + */ + if (appname) + fprintf(out, ";%s; SBIT metrics file generated by \"%s\".%s;%s%s", eol, + appname, eol, eol, eol); + + /* + * Save PPEM. + */ + fprintf(out, ";%s; Pixels Per Em.%s;%s", eol, eol, eol); + fprintf(out, "PPEM %ld%s%s", font->point_size, eol, eol); + + /* + * If the font is character cell or monowidth, set this boolean. + */ + if (font->spacing != BDF_PROPORTIONAL) { + fprintf(out, + ";%s; Font is not proportional, so use mono advance.%s;%s", + eol, eol, eol); + fprintf(out, "FORCECONSTANTMETRICS TRUE%s%s", eol, eol); + } else { + fprintf(out, + ";%s; Font is proportional, so do not use mono advance.%s;%s", + eol, eol, eol); + fprintf(out, "FORCECONSTANTMETRICS FALSE%s%s", eol, eol); + } + + /* + * Do the horizontal line metrics only. + */ + fprintf(out, ";%s; Horizontal line metrics.%s;%s", eol, eol, eol); + + fprintf(out, "H_ASCENDER %ld%sH_DESCENDER %ld%s", font->font_ascent, eol, + font->font_descent, eol); + fprintf(out, "H_WIDTHMAX %hd%s", font->bbx.width, eol); + fprintf(out, "H_MINORIGINSB %hd%sH_MINADVANCEBL %hd%s", + font->bbx.x_offset, eol, + font->bbx.width + font->bbx.x_offset, eol); + fprintf(out, "H_MAXBEFOREBL %hd%sH_MINAFTERBL %hd%s%s", + font->bbx.ascent, eol, font->bbx.y_offset, eol, eol); + + /* + * Write the default caret info. + */ + fprintf(out, ";%s; Caret slope and offset info.%s;%s", eol, eol, eol); + fprintf(out, "CARETSLOPENUMERATOR 1%sCARETSLOPEDENOMINATOR 0%s", eol, eol); + fprintf(out, "CARETOFFSET 0%s%s", eol, eol); + + /* + * Write the bitmap options. + */ + fprintf(out, ";%s; Bitmap options.%s;%s", eol, eol, eol); + fprintf(out, "DIRECTION H%sSTORAGE FAST%s%s", eol, eol, eol); + + /* + * Scaled bitmaps not implemented yet. + */ + fprintf(out, ";%s; Scaled bitmap info (Not Yet Implemented).%s;%s", + eol, eol, eol); +} + +/* + * Special routine to dump the font in the Roman Czyborra's hex format. It + * only dumps the encoded glyphs and assumes the bitmaps have the correct + * sizes. + */ +void +#ifdef __STDC__ +bdf_export_hex(FILE *out, bdf_font_t *font, bdf_callback_t callback, + void *data) +#else +bdf_export_hex(out, font, callback, data) +FILE *out; +bdf_font_t *font; +bdf_callback_t callback; +void *data; +#endif +{ + int bpr, fbpr, j, k; + unsigned long i, ng; + bdf_glyph_t *gp, cell; + bdf_callback_struct_t cb; + + if (font == 0 || out == 0) + return; + + if (font->glyphs_used == 0) + return; + + /* + * Call the callback if it was passed to start the export. + */ + if (callback != 0) { + cb.reason = BDF_EXPORT_START; + cb.total = font->glyphs_used; + cb.current = 0; + (*callback)(&cb, data); + } + + fbpr = ((font->bbx.width * font->bpp) + 7) >> 3; + bpr = (((font->bbx.width >> 1) * font->bpp) + 7) >> 3; + cell.bytes = fbpr * font->bbx.height; + cell.bitmap = (unsigned char *) malloc(cell.bytes); + + for (i = 0, ng = font->glyphs_used, gp = font->glyphs; i < ng; i++, gp++) { + _bdf_pad_cell(font, gp, &cell); + fprintf(out, "%04lX:", gp->encoding & 0xffff); + if (gp->bbx.width <= (font->bbx.width >> 1)) { + for (j = 0; j < cell.bytes; j += fbpr) { + for (k = 0; k < bpr; k++) + fprintf(out, "%02X", cell.bitmap[j + k]); + } + } else { + for (j = 0; j < cell.bytes; j++) + fprintf(out, "%02X", cell.bitmap[j]); + } + if (cell.bytes > 0) + putc('\n', out); + + /* + * Call the callback if supplied. + */ + if (callback != 0) { + cb.reason = BDF_EXPORTING; + cb.current++; + (*callback)(&cb, data); + } + } + + /* + * Clean up the cell. + */ + free((char *) cell.bitmap); + + /* + * Always call a final callback to make sure the client gets a chance to + * clean things up. + */ + if (callback != 0) { + cb.reason = BDF_EXPORTING; + cb.current = cb.total; + (*callback)(&cb, data); + } +} + +void +#ifdef __STDC__ +bdf_free_font(bdf_font_t *font) +#else +bdf_free_font(font) +bdf_font_t *font; +#endif +{ + unsigned long i; + bdf_glyph_t *glyphs; + + if (font == 0) + return; + + if (font->name != 0) + free(font->name); + + /* + * Free up the internal hash table of property names. + */ + hash_free((hashtable *) font->internal); + free((char *) font->internal); + + /* + * Free up the comment info. + */ + if (font->comments_len > 0) + free(font->comments); + + /* + * Free up the auto-correction messages. + */ + if (font->acmsgs_len > 0) + free(font->acmsgs); + + /* + * Free up the properties. + */ + for (i = 0; i < font->props_size; i++) { + if (font->props[i].format == BDF_ATOM && font->props[i].value.atom) + free(font->props[i].value.atom); + } + + if (font->props_size > 0 && font->props != 0) + free((char *) font->props); + + /* + * Free up the character info. + */ + for (i = 0, glyphs = font->glyphs; i < font->glyphs_used; i++, glyphs++) { + if (glyphs->name) + free(glyphs->name); + if (glyphs->bytes > 0 && glyphs->bitmap != 0) + free((char *) glyphs->bitmap); + } + + for (i = 0, glyphs = font->unencoded; i < font->unencoded_used; + i++, glyphs++) { + if (glyphs->name) + free(glyphs->name); + if (glyphs->bytes > 0) + free((char *) glyphs->bitmap); + } + + if (font->glyphs_size > 0) + free((char *) font->glyphs); + + if (font->unencoded_size > 0) + free((char *) font->unencoded); + + /* + * Free up the overflow storage if it was used. + */ + for (i = 0, glyphs = font->overflow.glyphs; i < font->overflow.glyphs_used; + i++, glyphs++) { + if (glyphs->name != 0) + free(glyphs->name); + if (glyphs->bytes > 0) + free((char *) glyphs->bitmap);; + } + if (font->overflow.glyphs_size > 0) + free((char *) font->overflow.glyphs); + + free((char *) font); +} + +void +#ifdef __STDC__ +bdf_create_property(char *name, int format) +#else +bdf_create_property(name, format) +char *name; +int format; +#endif +{ + unsigned long n; + bdf_property_t *p; + + /* + * First check to see if the property has + * already been added or not. If it has, then + * simply ignore it. + */ + + if (hash_lookup(name, &proptbl)) + return; + + if (nuser_props == 0) + user_props = (bdf_property_t *) malloc(sizeof(bdf_property_t)); + else + user_props = (bdf_property_t *) realloc((char *) user_props, + sizeof(bdf_property_t) * + (nuser_props + 1)); + + p = user_props + nuser_props; + (void) memset((char *) p, 0, sizeof(bdf_property_t)); + n = (unsigned long)(strlen(name) + 1); + p->name = (char *) malloc(n); + (void) memcpy(p->name, name, n); + p->format = format; + p->builtin = 0; + + n = _num_bdf_properties + nuser_props; + hash_insert(p->name, (void *) n, &proptbl); + + nuser_props++; +} + +bdf_property_t * +#ifdef __STDC__ +bdf_get_property(char *name) +#else +bdf_get_property(name) +char *name; +#endif +{ + hashnode hn; + unsigned long propid; + + if (name == 0 || *name == 0) + return 0; + + if ((hn = hash_lookup(name, &proptbl)) == 0) + return 0; + + propid = (unsigned long) hn->data; + if (propid >= _num_bdf_properties) + return user_props + (propid - _num_bdf_properties); + return _bdf_properties + propid; +} + +/* + * Routine to compare two property names. + */ +static int +#ifdef __STDC__ +by_prop_name(const void *a, const void *b) +#else +by_prop_name(a, b) +char *a, *b; +#endif +{ + bdf_property_t *p1, *p2; + + p1 = (bdf_property_t *) a; + p2 = (bdf_property_t *) b; + + return strcmp(p1->name, p2->name); +} + +unsigned long +#ifdef __STDC__ +bdf_property_list(bdf_property_t **props) +#else +bdf_property_list(props) +bdf_property_t **props; +#endif +{ + unsigned long n; + bdf_property_t *p; + + n = _num_bdf_properties + nuser_props; + if (props != 0 && n != 0) { + p = (bdf_property_t *) malloc(sizeof(bdf_property_t) * n); + (void) memcpy((char *) p, (char *) _bdf_properties, + sizeof(bdf_property_t) * _num_bdf_properties); + (void) memcpy((char *)(p + _num_bdf_properties), (char *) user_props, + sizeof(bdf_property_t) * nuser_props); + qsort((char *) p, n, sizeof(bdf_property_t), by_prop_name); + *props = p; + } + return n; +} + +int +#ifdef __STDC__ +bdf_replace_comments(bdf_font_t *font, char *comments, + unsigned long comments_len) +#else +bdf_replace_comments(font, comments, comments_len) +bdf_font_t *font; +char *comments; +unsigned long comments_len; +#endif +{ + if (font == 0 || comments_len == 0) + return 0; + + if (font->comments_len > 0) + free(font->comments); + + font->comments = (char *) malloc(comments_len + 1); + (void) memcpy(font->comments, comments, comments_len); + font->comments[comments_len] = 0; + font->comments_len = comments_len; + font->modified = 1; + return 1; +} + +unsigned long +#ifdef __STDC__ +bdf_font_property_list(bdf_font_t *font, bdf_property_t **props) +#else +bdf_font_property_list(font, props) +bdf_font_t *font; +bdf_property_t **props; +#endif +{ + bdf_property_t *p; + + if (font == 0 || font->props_used == 0) + return 0; + + if (props != 0) { + p = (bdf_property_t *) malloc(sizeof(bdf_property_t) * + font->props_used); + (void) memcpy((char *) p, (char *) font->props, + sizeof(bdf_property_t) * font->props_used); + qsort((char *) p, font->props_used, sizeof(bdf_property_t), + by_prop_name); + *props = p; + } + + return font->props_used; +} + +void +#ifdef __STDC__ +bdf_add_font_property(bdf_font_t *font, bdf_property_t *property) +#else +bdf_add_font_property(font, property) +bdf_font_t *font; +bdf_property_t *property; +#endif +{ + int len; + unsigned long propid; + hashnode hn; + bdf_property_t *p, *ip; + + if (property == 0 || property->name == 0 || property->name[0] == 0) + return; + + /* + * If the font does not have a property hash table yet, make + * sure it is allocated. + */ + if (font->internal == 0) { + font->internal = (void *) malloc(sizeof(hashtable)); + hash_init((hashtable *) font->internal); + } + + /* + * See if the property is in the general property table yet. + * If it isn't, then add it. + */ + if ((hn = hash_lookup(property->name, &proptbl)) == 0) + bdf_create_property(property->name, property->format); + else { + /* + * If the property exists and is a user defined property, make sure + * its format is updated to match the property being added. + */ + propid = (unsigned long) hn->data; + if (propid >= _num_bdf_properties) { + p = user_props + (propid - _num_bdf_properties); + if (p->format != property->format) + p->format = property->format; + } + } + + /* + * If the font already has this property, then change the existing one. + */ + hn = hash_lookup(property->name, (hashtable *) font->internal); + if (hn != 0) { + /* + * Changing an existing property value. + */ + p = font->props + ((unsigned long) hn->data); + + /* + * If the format changed, then free the atom value if the original + * format was an atom. + */ + if (p->format == BDF_ATOM && property->format != BDF_ATOM && + p->value.atom != 0) + free((char *) p->value.atom); + p->format = property->format; + + switch (p->format) { + case BDF_ATOM: + /* + * If the property value is the same, then just return. + */ + if (property->value.atom == p->value.atom || + (property->value.atom && p->value.atom && + strcmp(property->value.atom, p->value.atom) == 0)) + return; + if (property->value.atom == 0) + len = 1; + else + len = strlen(property->value.atom) + 1; + if (len > 1) { + p->value.atom = (char *) malloc(len); + (void) memcpy(p->value.atom, property->value.atom, len); + } else + p->value.atom = 0; + break; + case BDF_INTEGER: + /* + * If the property value is the same, then just return. + */ + if (p->value.int32 == property->value.int32) + return; + p->value.int32 = property->value.int32; + break; + case BDF_CARDINAL: + /* + * If the property value is the same, then just return. + */ + if (p->value.card32 == property->value.card32) + return; + p->value.card32 = property->value.card32; + break; + } + } else { + /* + * New property being added. + */ + + /* + * Get the internal table entry for a pointer to the + * name of the property. + */ + hn = hash_lookup(property->name, &proptbl); + propid = (unsigned long) hn->data; + if (propid >= _num_bdf_properties) + ip = user_props + (propid - _num_bdf_properties); + else + ip = _bdf_properties + propid; + + /* + * Add it to the property list first. + */ + if (font->props_used == font->props_size) { + if (font->props_size == 0) + font->props = (bdf_property_t *) malloc(sizeof(bdf_property_t)); + else + font->props = (bdf_property_t *) + realloc((char *) font->props, sizeof(bdf_property_t) * + (font->props_size + 1)); + font->props_size++; + } + p = font->props + font->props_used; + + p->name = ip->name; + p->format = ip->format; + p->builtin = ip->builtin; + + switch (p->format) { + case BDF_ATOM: + if (property->value.atom == 0) + len = 1; + else + len = strlen(property->value.atom) + 1; + if (len > 1) { + p->value.atom = (char *) malloc(len); + (void) memcpy(p->value.atom, property->value.atom, len); + } else + p->value.atom = 0; + break; + case BDF_INTEGER: + p->value.int32 = property->value.int32; + break; + case BDF_CARDINAL: + p->value.card32 = property->value.card32; + break; + } + + /* + * Now insert it into the internal hash table. + */ + hash_insert(p->name, (void *) font->props_used, + (hashtable *) font->internal); + font->props_used++; + } + + if (memcmp(property->name, "DEFAULT_CHAR", 12) == 0) + /* + * If the property just added is DEFAULT_CHAR, then make sure the + * default_glyph field is set. + */ + font->default_glyph = p->value.card32; + else if (memcmp(property->name, "FONT_ASCENT", 11) == 0) + /* + * If the property just added is FONT_ASCENT, then adjust the + * font_ascent field. + */ + font->font_ascent = p->value.int32; + else if (memcmp(property->name, "FONT_DESCENT", 12) == 0) + /* + * If the property just added is FONT_DESCENT, then adjust the + * font_descent field. + */ + font->font_descent = p->value.int32; + else if (memcmp(property->name, "RESOLUTION_X", 12) == 0) + /* + * If the property just added is RESOLUTION_X, then adjust the + * resolution_x field. + */ + font->resolution_x = p->value.card32; + else if (memcmp(property->name, "RESOLUTION_Y", 12) == 0) + /* + * If the property just added is RESOLUTION_Y, then adjust the + * resolution_y field. + */ + font->resolution_y = p->value.card32; + else if (memcmp(property->name, "POINT_SIZE", 10) == 0) + /* + * If the property just added is POINT_SIZE, then adjust the + * point_size field. + */ + font->point_size = p->value.int32 / 10; + else if (memcmp(property->name, "SPACING", 7) == 0) { + /* + * Make sure the font spacing is kept in synch if the property + * changes. If the spacing changes from proportional to one + * of the others, force the monowidth to be set. + */ + switch (p->value.atom[0]) { + case 'C': + case 'c': + if (font->spacing == BDF_PROPORTIONAL) + font->monowidth = font->bbx.width + font->bbx.x_offset; + font->spacing = BDF_CHARCELL; + break; + case 'M': + case 'm': + if (font->spacing == BDF_PROPORTIONAL) + font->monowidth = font->bbx.width + font->bbx.x_offset; + font->spacing = BDF_MONOWIDTH; + break; + case 'P': + case 'p': + font->spacing = BDF_PROPORTIONAL; + break; + } + } + + /* + * Make sure the font is marked as modified. + */ + font->modified = 1; +} + +void +#ifdef __STDC__ +bdf_delete_font_property(bdf_font_t *font, char *name) +#else +bdf_delete_font_property(font, name) +bdf_font_t *font; +char *name; +#endif +{ + hashnode hn; + unsigned long off; + bdf_property_t *p; + + if (font == 0 || name == 0 || *name == 0 || font->props_used == 0) + return; + + if ((hn = hash_lookup(name, (hashtable *) font->internal)) == 0) + return; + + off = (unsigned long) hn->data; + p = font->props + off; + + /* + * Delete the ATOM value if appropriate. + */ + if (p->format == BDF_ATOM && p->value.atom != 0) + free(p->value.atom); + + /* + * The property exists. Two things needs to be done: + * 1. Remove the property from the hash table. + * 2. Remove the property from the font's list of properties. + */ + hash_delete(name, (hashtable *) font->internal); + + /* + * Locate its offset in the font property list. + */ + if (off < font->props_used - 1) + /* + * We have to shift the property list down. + */ + _bdf_memmove((char *) p, (char *)(p + 1), + sizeof(bdf_property_t) * ((font->props_used - 1) - off)); + font->props_used--; + + /* + * If the font property happens to be DEFAULT_CHAR, then make sure the + * default_glyph field is reset. + */ + if (strncmp(name, "DEFAULT_CHAR", 12) == 0) + font->default_glyph = -1; + + /* + * Update the hash table with the correct indexes. + */ + for (off = 0, p = font->props; off < font->props_used; off++, p++) + hash_insert(p->name, (void *) off, (hashtable *) font->internal); + + /* + * Mark the font as being modified. + */ + font->modified = 1; +} + +bdf_property_t * +#ifdef __STDC__ +bdf_get_font_property(bdf_font_t *font, const char *name) +#else +bdf_get_font_property(font, name) +bdf_font_t *font; +const char *name; +#endif +{ + hashnode hn; + + if (font == 0 || font->props_size == 0 || name == 0 || *name == 0) + return 0; + + hn = hash_lookup((char*)name, (hashtable *) font->internal); + return (hn) ? (font->props + ((unsigned long) hn->data)) : 0; +} + +typedef struct { + bdf_options_t *opts; + bdf_options_callback_t callback; + void *client_data; + _bdf_list_t list; +} _bdf_opts_parse_t; + +static int +#ifdef __STDC__ +_bdf_get_boolean(char *val) +#else +_bdf_get_boolean(val) +char *val; +#endif +{ + int ok; + + ok = 0; + if (val == 0 || *val == 0) + return ok; + + switch (val[0]) { + case '0': + case 'F': + case 'f': + case 'N': + case 'n': + ok = 0; + break; + case '1': + case 'T': + case 't': + case 'Y': + case 'y': + ok = 1; + break; + } + return ok; +} + +static int +#ifdef __STDC__ +_bdf_parse_options(char *line, unsigned long linelen, unsigned long lineno, + void *call_data, void *client_data) +#else +_bdf_parse_options(line, linelen, lineno, call_data, client_data) +char *line; +unsigned long linelen, lineno; +void *call_data, *client_data; +#endif +{ + _bdf_list_t *lp; + _bdf_opts_parse_t *p; + long bpp; + + p = (_bdf_opts_parse_t *) client_data; + lp = &p->list; + + /* + * Split the line into fields. + */ + _bdf_split(" \t+", line, linelen, lp); + + if (lp->field[0][0] == 'b' && + memcmp(lp->field[0], "bits_per_pixel", 14) == 0) { + if (lp->used < 2) { + fprintf(stderr, + "bdf: warning: %ld: incorrect number of fields %ld.\n", + lineno, lp->used); + fprintf(stderr, + "bdf: warning: %ld: bits_per_pixel <1, 2, or 4>.\n", + lineno); + } else { + bpp = _bdf_atol(lp->field[1], 0, 10); + if (!(bpp == 1 || bpp == 2 || bpp == 4)) { + fprintf(stderr, + "bdf: warning: %ld: invalid bits per pixel %ld.\n", + lineno, bpp); + fprintf(stderr, + "bdf: warning: %ld: bits_per_pixel <1, 2, or 4>.\n", + lineno); + } else + p->opts->bits_per_pixel = bpp; + } + return 0; + } + + if (lp->field[0][0] == 'e' && memcmp(lp->field[0], "eol", 3) == 0) { + if (lp->used < 2) { + fprintf(stderr, + "bdf: warning: %ld: incorrect number of fields %ld.\n", + lineno, lp->used); + fprintf(stderr, + "bdf: warning: %ld: eol <eolname>.\n", lineno); + } else { + switch (lp->field[1][0]) { + case 'u': + case 'U': + p->opts->eol = BDF_UNIX_EOL; + break; + case 'd': + case 'D': + p->opts->eol = BDF_DOS_EOL; + break; + case 'm': + case 'M': + p->opts->eol = BDF_MAC_EOL; + break; + } + } + return 0; + } + + if (lp->field[0][0] == 'c' && + memcmp(lp->field[0], "correct_metrics", 15) == 0) { + if (lp->used < 2) { + fprintf(stderr, + "bdf: warning: %ld: incorrect number of fields %ld.\n", + lineno, lp->used); + fprintf(stderr, + "bdf: warning: %ld: correct_metrics <boolean>.\n", lineno); + } else + p->opts->correct_metrics = _bdf_get_boolean(lp->field[1]); + + return 0; + } + + if (lp->field[0][0] == 'k' && + memcmp(lp->field[0], "keep_unencoded", 14) == 0) { + if (lp->used < 2) { + fprintf(stderr, + "bdf: warning: %ld: incorrect number of fields %ld.\n", + lineno, lp->used); + fprintf(stderr, + "bdf: warning: %ld: keep_unencoded <boolean>.\n", lineno); + } else + p->opts->keep_unencoded = _bdf_get_boolean(lp->field[1]); + + return 0; + } + + if (lp->field[0][0] == 'k' && + memcmp(lp->field[0], "keep_comments", 13) == 0) { + if (lp->used < 2) { + fprintf(stderr, + "bdf: warning: %ld: incorrect number of fields %ld.\n", + lineno, lp->used); + fprintf(stderr, + "bdf: warning: %ld: keep_comments <boolean>.\n", lineno); + } else + p->opts->keep_comments = _bdf_get_boolean(lp->field[1]); + + return 0; + } + + if (lp->field[0][0] == 'p' && + memcmp(lp->field[0], "pad_character_cells", 19) == 0) { + if (lp->used < 2) { + fprintf(stderr, + "bdf: warning: %ld: incorrect number of fields %ld.\n", + lineno, lp->used); + fprintf(stderr, + "bdf: warning: %ld: pad_character_cells <boolean>.\n", + lineno); + } else + p->opts->pad_cells = _bdf_get_boolean(lp->field[1]); + + return 0; + } + + if (lp->field[0][0] == 'p' && + memcmp(lp->field[0], "point_size", 10) == 0) { + if (lp->used < 2) { + fprintf(stderr, + "bdf: warning: %ld: incorrect number of fields %ld.\n", + lineno, lp->used); + fprintf(stderr, + "bdf: warning: %ld: point_size <integer>.\n", lineno); + } else + p->opts->point_size = _bdf_atol(lp->field[1], 0, 10); + return 0; + } + + if (lp->field[0][0] == 'h' && + memcmp(lp->field[0], "horizontal_resolution", 21) == 0) { + if (lp->used < 2) { + fprintf(stderr, + "bdf: warning: %ld: incorrect number of fields %ld.\n", + lineno, lp->used); + fprintf(stderr, + "bdf: warning: %ld: horizontal_resolution <cardinal>.\n", + lineno); + } else + p->opts->resolution_x = _bdf_atoul(lp->field[1], 0, 10); + return 0; + } + + if (lp->field[0][0] == 'v' && + memcmp(lp->field[0], "vertical_resolution", 19) == 0) { + if (lp->used < 2) { + fprintf(stderr, + "bdf: warning: %ld: incorrect number of fields %ld.\n", + lineno, lp->used); + fprintf(stderr, + "bdf: warning: %ld: vertical_resolution <cardinal>.\n", + lineno); + } else + p->opts->resolution_y = _bdf_atoul(lp->field[1], 0, 10); + return 0; + } + + if (lp->field[0][0] == 'f' && + memcmp(lp->field[0], "font_spacing", 12) == 0) { + if (lp->used < 2) { + fprintf(stderr, + "bdf: warning: %ld: incorrect number of fields %ld.\n", + lineno, lp->used); + fprintf(stderr, + "bdf: warning: %ld: font_spacing <spacing name>.\n", + lineno); + } else { + switch (lp->field[1][0]) { + case 'P': + case 'p': + p->opts->font_spacing = BDF_PROPORTIONAL; + break; + case 'M': + case 'm': + p->opts->font_spacing = BDF_MONOWIDTH; + break; + case 'C': + case 'c': + p->opts->font_spacing = BDF_CHARCELL; + break; + default: + fprintf(stderr, + "bdf: warning: %ld: unknown font spacing '%s'.\n", + lineno, lp->field[1]); + } + } + return 0; + } + + if (lp->field[0][0] == 'p' && + memcmp(lp->field[0], "property", 8) == 0) { + if (lp->used < 3) { + fprintf(stderr, + "bdf: warning: %ld: incorrect number of fields %ld.\n", + lineno, lp->used); + fprintf(stderr, + "bdf: warning: %ld: property <name> <type>.\n", + lineno); + } else { + switch (lp->field[2][0]) { + case 'A': + case 'a': + bdf_create_property(lp->field[1], BDF_ATOM); + break; + case 'C': + case 'c': + bdf_create_property(lp->field[1], BDF_CARDINAL); + break; + case 'I': + case 'i': + bdf_create_property(lp->field[1], BDF_INTEGER); + break; + default: + fprintf(stderr, + "bdf: warning: %ld: unknown property type '%s'.\n", + lineno, lp->field[2]); + } + } + return 0; + } + + if (lp->field[0][0] == 'h' && + memcmp(lp->field[0], "hint_truetype_glyphs", 20) == 0) { + if (lp->used < 2) { + fprintf(stderr, + "bdf: warning: %ld: incorrect number of fields %ld.\n", + lineno, lp->used); + fprintf(stderr, + "bdf: warning: %ld: hint_truetype_glyphs <boolean>.\n", + lineno); + } else + p->opts->ttf_hint = _bdf_get_boolean(lp->field[1]); + + return 0; + } + + if (lp->field[0][0] == 'g' && + memcmp(lp->field[0], "generate_ranges", 15) == 0) + /* + * Simply ignore the glyph ranges entry in the config file. + */ + return 0; + + /* + * If the callback returns a non-zero value, the caller has handled the + * unknown option found in the file. + */ + if (p->callback != 0 && + (*p->callback)(p->opts, lp->field, lp->used, p->client_data) != 0) + return 0; + + fprintf(stderr, "bdf: warning: %ld: unknown configuration option '%s'.\n", + lineno, lp->field[0]); + return 0; +} + +void +#ifdef __STDC__ +bdf_load_options(FILE *in, bdf_options_t *opts, + bdf_options_callback_t callback, void *client_data) +#else +bdf_load_options(in, opts, callback, client_data) +FILE *in; +bdf_options_t *opts; +bdf_options_callback_t callback; +void *client_data; +#endif +{ + unsigned long lineno; + _bdf_opts_parse_t p; + + /* + * Don't bother loading the options if the file or options structure + * is NULL. + */ + if (in == 0 || opts == 0) + return; + + (void *) memset((char *) &p, 0, sizeof(_bdf_opts_parse_t)); + p.opts = opts; + p.callback = callback; + p.client_data = client_data; + (void) _bdf_readlines(fileno(in), _bdf_parse_options, (void *) &p, + &lineno); + + /* + * Free up the list if there is any space allocated. + */ + if (p.list.size > 0) + free((char *) p.list.field); +} + +void +#ifdef __STDC__ +bdf_save_options(FILE *out, bdf_options_t *opts) +#else +bdf_save_options(out, opts) +FILE *out; +bdf_options_t *opts; +#endif +{ + unsigned long i; + + if (out == 0 || opts == 0) + return; + + fprintf(out, "#\n# Metrics corrections.\n#\ncorrect_metrics "); + if (opts->correct_metrics) + fprintf(out, "true\n\n"); + else + fprintf(out, "false\n\n"); + + fprintf(out, "#\n# Preserve unencoded glyphs.\n#\nkeep_unencoded "); + if (opts->keep_unencoded) + fprintf(out, "true\n\n"); + else + fprintf(out, "false\n\n"); + + fprintf(out, "#\n# Preserve comments.\n#\nkeep_comments "); + if (opts->keep_comments) + fprintf(out, "true\n\n"); + else + fprintf(out, "false\n\n"); + + fprintf(out, "#\n# Pad character cells.\n#\npad_character_cells "); + if (opts->pad_cells) + fprintf(out, "true\n\n"); + else + fprintf(out, "false\n\n"); + + fprintf(out, "#\n# Font spacing.\n#\nfont_spacing "); + switch (opts->font_spacing) { + case BDF_PROPORTIONAL: + fprintf(out, "proportional\n\n"); + break; + case BDF_MONOWIDTH: + fprintf(out, "monowidth\n\n"); + break; + case BDF_CHARCELL: + fprintf(out, "charactercell\n\n"); + break; + } + + fprintf(out, "#\n# Point size.\n#\npoint_size %ld\n\n", opts->point_size); + + fprintf(out, + "#\n# Horizontal resolution.\n#\nhorizontal_resolution %ld\n\n", + opts->resolution_x); + + fprintf(out, + "#\n# Vertical resolution.\n#\nvertical_resolution %ld\n\n", + opts->resolution_x); + + fprintf(out, + "#\n# Bits per pixel.\n#\nbits_per_pixel %d\n\n", + opts->bits_per_pixel); + + fprintf(out, "#\n# Hint TrueType glyphs.\n#\nhint_truetype_glyphs "); + if (opts->ttf_hint) + fprintf(out, "true\n\n"); + else + fprintf(out, "false\n\n"); + + fprintf(out, "#\n# Set the EOL used when writing BDF fonts.\n#\neol "); + switch (opts->eol) { + case BDF_UNIX_EOL: + fprintf(out, "unix\n\n"); + break; + case BDF_DOS_EOL: + fprintf(out, "dos\n\n"); + break; + case BDF_MAC_EOL: + fprintf(out, "mac\n\n"); + break; + } + + /* + * Write out the user defined properties if they exist. + */ + if (nuser_props == 0) + return; + + fprintf(out, "#\n# User defined properties.\n#\n"); + + for (i = 0; i < nuser_props; i++) { + fprintf(out, "property %s ", user_props[i].name); + switch (user_props[i].format) { + case BDF_ATOM: + fprintf(out, "atom\n"); + break; + case BDF_CARDINAL: + fprintf(out, "cardinal\n"); + break; + case BDF_INTEGER: + fprintf(out, "integer\n"); + break; + } + } +} + +void +#ifdef __STDC__ +bdf_default_options(bdf_options_t *opts) +#else +bdf_default_options(opts) +bdf_options_t *opts; +#endif +{ + if (opts == 0) + return; + + (void) memcpy((char *) opts, (char *) &_bdf_opts, sizeof(bdf_options_t)); +} + +bdf_font_t * +#ifdef __STDC__ +bdf_new_font(char *name, long point_size, long resolution_x, long resolution_y, + long spacing, int bpp) +#else +bdf_new_font(name, point_size, resolution_x, resolution_y, spacing, bpp) +char *name; +long point_size, resolution_x, resolution_y, spacing; +int bpp; +#endif +{ + long psize; + char sp[2]; + bdf_font_t *font; + double dp, dr; + bdf_property_t prop; + + font = (bdf_font_t *) calloc(1, sizeof(bdf_font_t)); + if (name != 0 && *name != 0) { + font->name = (char *) malloc(strlen(name) + 1); + (void) strcpy(font->name, name); + } + + font->bpp = bpp; + font->point_size = point_size; + font->resolution_x = resolution_x; + font->resolution_y = resolution_y; + + /* + * Determine the pixel size of the new font based on the + * point size and resolution. + */ + dr = (double) resolution_y; + dp = (double)(point_size * 10); + psize = (long)(((dp * dr) / 722.7) + 0.5); + + /* + * Make the default width about 1.5 smaller than the height. + */ + font->bbx.height = psize; + font->bbx.width = (unsigned short)((double) psize) / 1.5; + + /* + * Now determine the default ascent and descent assuming a + * the descent is about 1/4 the ascent. + */ + font->bbx.descent = psize >> 2; + font->bbx.ascent = psize - font->bbx.descent; + + font->bbx.y_offset = -font->bbx.descent; + + /* + * Allocation the internal hash tables. + */ + font->internal = (void *) malloc(sizeof(hashtable)); + hash_init((hashtable *) font->internal); + + font->default_glyph = -1; + font->spacing = spacing; + + /* + * Add various useful properties. + */ + prop.name = "POINT_SIZE"; + prop.format = BDF_INTEGER; + prop.value.int32 = font->point_size * 10; + bdf_add_font_property(font, &prop); + + prop.name = "PIXEL_SIZE"; + prop.format = BDF_INTEGER; + prop.value.int32 = psize; + bdf_add_font_property(font, &prop); + + prop.name = "RESOLUTION_X"; + prop.format = BDF_CARDINAL; + prop.value.card32 = (unsigned long) font->resolution_x; + bdf_add_font_property(font, &prop); + + prop.name = "RESOLUTION_Y"; + prop.format = BDF_CARDINAL; + prop.value.card32 = (unsigned long) font->resolution_y; + bdf_add_font_property(font, &prop); + + prop.name = "FONT_ASCENT"; + prop.format = BDF_INTEGER; + prop.value.int32 = (long) font->bbx.ascent; + bdf_add_font_property(font, &prop); + + prop.name = "FONT_DESCENT"; + prop.format = BDF_INTEGER; + prop.value.int32 = (long) font->bbx.descent; + bdf_add_font_property(font, &prop); + + prop.name = "AVERAGE_WIDTH"; + prop.format = BDF_INTEGER; + prop.value.int32 = font->bbx.width * 10; + bdf_add_font_property(font, &prop); + + sp[0] = 'P'; + sp[1] = 0; + switch (spacing) { + case BDF_PROPORTIONAL: + sp[0] = 'P'; + break; + case BDF_MONOWIDTH: + sp[0] = 'M'; + break; + case BDF_CHARCELL: + sp[0] = 'C'; + break; + } + prop.name = "SPACING"; + prop.format = BDF_ATOM; + prop.value.atom = sp; + bdf_add_font_property(font, &prop); + + /* + * Mark the font as unmodified. + */ + font->modified = 0; + + return font; +} + +void +#ifdef __STDC__ +bdf_set_default_metrics(bdf_font_t *font) +#else +bdf_set_default_metrics(font) +bdf_font_t *font; +#endif +{ + long psize; + double dp, dr; + bdf_property_t prop; + + /* + * Determine the pixel size of the new font based on the + * point size and resolution. + */ + dr = (double) font->resolution_y; + dp = (double)(font->point_size * 10); + psize = (long)(((dp * dr) / 722.7) + 0.5); + + /* + * Make the default width about 1.5 smaller than the height. + */ + font->bbx.height = psize; + font->bbx.width = (unsigned short)((double) psize) / 1.5; + + /* + * Now determine the default ascent and descent assuming a + * the descent is about 1/4 the ascent. + */ + font->bbx.descent = psize >> 2; + font->bbx.ascent = psize - font->bbx.descent; + + font->bbx.y_offset = -font->bbx.descent; + + font->default_glyph = -1; + + /* + * Add various useful properties. + */ + prop.name = "FONT_ASCENT"; + prop.format = BDF_INTEGER; + prop.value.int32 = (long) font->bbx.ascent; + bdf_add_font_property(font, &prop); + + prop.name = "FONT_DESCENT"; + prop.format = BDF_INTEGER; + prop.value.int32 = (long) font->bbx.descent; + bdf_add_font_property(font, &prop); + + prop.name = "AVERAGE_WIDTH"; + prop.format = BDF_INTEGER; + prop.value.int32 = font->bbx.width * 10; + bdf_add_font_property(font, &prop); +} + +int +#ifdef __STDC__ +bdf_glyph_modified(bdf_font_t *font, long which, int unencoded) +#else +bdf_glyph_modified(font, which, unencoded) +bdf_font_t *font; +long which; +int unencoded; +#endif +{ + if (font == 0 || which < 0) + return 0; + + if (unencoded) + return _bdf_glyph_modified(font->umod, which); + else + return _bdf_glyph_modified(font->nmod, which); +} + +void +#ifdef __STDC__ +bdf_copy_glyphs(bdf_font_t *font, long start, long end, + bdf_glyphlist_t *glyphs, int unencoded) +#else +bdf_copy_glyphs(font, start, end, glyphs, unencoded) +bdf_font_t *font; +long start, end; +bdf_glyphlist_t *glyphs; +int unencoded; +#endif +{ + long tmp, i, nc; + bdf_glyph_t *cp, *dp; + short maxas, maxds, maxrb, minlb, maxlb, rb; + + if (start > end) { + tmp = end; + end = start; + start = tmp; + } + + glyphs->bpp = font->bpp; + glyphs->start = start; + glyphs->end = end; + glyphs->glyphs_used = 0; + + tmp = (end - start) + 1; + if (tmp > glyphs->glyphs_size) { + if (glyphs->glyphs_size == 0) + glyphs->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * tmp); + else + glyphs->glyphs = (bdf_glyph_t *) realloc((char *) glyphs->glyphs, + sizeof(bdf_glyph_t) * tmp); + cp = glyphs->glyphs + glyphs->glyphs_size; + (void) memset((char *) cp, 0, + sizeof(bdf_glyph_t) * (tmp - glyphs->glyphs_size)); + glyphs->glyphs_size = tmp; + } + + /* + * Clear out bitmaps and names in the existing entries. + */ + for (cp = glyphs->glyphs, i = 0; i < glyphs->glyphs_size; i++, cp++) { + if (cp->name != 0) + free(cp->name); + if (cp->bytes > 0) + free((char *) cp->bitmap); + } + + /* + * Zero out everything. + */ + (void) memset((char *) &glyphs->bbx, 0, sizeof(bdf_bbx_t)); + (void) memset((char *) glyphs->glyphs, 0, + sizeof(bdf_glyph_t) * glyphs->glyphs_size); + + /* + * Initialize the bounds used to generate the overall bounding box for the + * set of glyphs being copied. + */ + minlb = font->bbx.width; + maxlb = maxrb = maxas = maxds = 0; + + /* + * Do the copy. + */ + nc = (unencoded == 0) ? font->glyphs_used : font->unencoded_used; + cp = (unencoded == 0) ? font->glyphs : font->unencoded; + dp = glyphs->glyphs; + + for (i = 0; + i < nc && ((unencoded && i <= end) || cp->encoding <= end); + i++, cp++) { + if ((unencoded && i >= start) || cp->encoding >= start) { + (void) memcpy((char *) dp, (char *) cp, sizeof(bdf_glyph_t)); + if (cp->name != 0) { + dp->name = (char *) malloc(strlen(cp->name) + 1); + (void) strcpy(dp->name, cp->name); + } + if (cp->bytes > 0) { + dp->bytes = cp->bytes; + dp->bitmap = (unsigned char *) malloc(cp->bytes); + (void) memcpy((char *) dp->bitmap, (char *) cp->bitmap, + cp->bytes); + } + + /* + * Determine the overall metrics for the group of characters being + * copied. + */ + maxas = MAX(cp->bbx.ascent, maxas); + maxds = MAX(cp->bbx.descent, maxds); + rb = cp->bbx.width + cp->bbx.x_offset; + maxrb = MAX(rb, maxrb); + minlb = MIN(cp->bbx.x_offset, minlb); + maxlb = MAX(cp->bbx.x_offset, maxlb); + + glyphs->glyphs_used++; + dp++; + } + } + + /* + * Set the overall metrics for this set of glyphs. + */ + glyphs->bbx.width = maxrb - minlb; + glyphs->bbx.x_offset = minlb; + + glyphs->bbx.height = maxas + maxds; + glyphs->bbx.ascent = maxas; + glyphs->bbx.descent = maxds; + glyphs->bbx.y_offset = -maxds; +} + +void +#ifdef __STDC__ +bdf_delete_glyphs(bdf_font_t *font, long start, long end, int unencoded) +#else +bdf_delete_glyphs(font, start, end, unencoded) +bdf_font_t *font; +long start, end; +int unencoded; +#endif +{ + long i, n, nc, cnt; + bdf_glyph_t *cp, *sp, *ep; + + if (font == 0) + return; + + if (start > end) { + cnt = end; + end = start; + start = cnt; + } + + nc = (unencoded == 0) ? font->glyphs_used : font->unencoded_used; + cp = (unencoded == 0) ? font->glyphs : font->unencoded; + sp = ep = 0; + + for (i = 0; i < nc && cp->encoding <= end; i++, cp++) { + if (cp->encoding >= start && sp == 0) + sp = cp; + } + ep = cp; + if (sp == 0) + sp = ep; + + if (ep > sp) { + /* + * There are some glyphs to delete. + * 1. Free the name and bitmap fields of the glyphs being deleted. + * 2. Move the end range down if necessary. + * 3. Clear the glyphs on the end if a move was done. + */ + + /* + * Mark the font as being modified. + */ + font->modified = 1; + + cnt = ep - sp; + + for (cp = sp; cp < ep; cp++) { + /* + * Mark the glyphs being deleted as also being modified so the + * empty cells can be shown correctly by the client programs. + */ + if (unencoded) + _bdf_set_glyph_modified(font->umod, cp->encoding); + else + _bdf_set_glyph_modified(font->nmod, cp->encoding); + + if (cp->name != 0) + free(cp->name); + if (cp->bytes > 0) + free((char *) cp->bitmap); + } + + cp = (unencoded == 0) ? font->glyphs : font->unencoded; + + /* + * Check to see if there are some glyphs that need to + * be moved down. + */ + if (ep - cp < nc) { + /* + * Shift the glyphs down. + */ + n = nc - (ep - cp); + _bdf_memmove((char *) sp, (char *) ep, sizeof(bdf_glyph_t) * n); + + /* + * Set the starting point for the clear. + */ + ep = sp + n; + } else + /* + * Set the starting point for the clear. + */ + ep = sp; + + /* + * Clear the glyph space just moved. + */ + n = nc - (ep - cp); + (void) memset((char *) ep, 0, sizeof(bdf_glyph_t) * n); + + /* + * Adjust the number of glyphs used. + */ + if (unencoded == 0) + font->glyphs_used -= cnt; + else + font->unencoded_used -= cnt; + + /* + * If unencoded glyphs were deleted, re-encode all + * of them to cause a shift when everything is redrawn. + */ + if (unencoded != 0) { + for (i = 0, cp = font->unencoded; i < font->unencoded_used; + i++, cp++) { + if (_bdf_glyph_modified(font->umod, cp->encoding)) { + _bdf_clear_glyph_modified(font->umod, cp->encoding); + _bdf_set_glyph_modified(font->umod, i); + } + cp->encoding = i; + } + } + } +} + +/* + * Routines for quick and dirty dithering. + */ +static void +#ifdef __STDC__ +_bdf_one_to_n(bdf_glyphlist_t *gl, int n) +#else +_bdf_one_to_n(gl, n) +bdf_glyphlist_t *gl; +int n; +#endif +{ + long i; + unsigned short bpr, sbpr, bytes, col, sx, sy; + unsigned char *nbmap, *masks; + bdf_glyph_t *gp; + + if (gl == 0 || gl->glyphs_used == 0) + return; + + masks = 0; + switch (n) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + gl->bpp = n; + for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) { + if (gp->bbx.width == 0 || gp->bbx.height == 0) + continue; + sbpr = (gp->bbx.width + 7) >> 3; + bpr = ((gp->bbx.width * n) + 7) >> 3; + bytes = bpr * gp->bbx.height; + nbmap = (unsigned char *) malloc(bytes); + (void) memset((char *) nbmap, 0, bytes); + + for (sy = 0; sy < gp->bbx.height; sy++) { + for (col = sx = 0; sx < gp->bbx.width; sx++, col += n) { + if (gp->bitmap[(sy * sbpr) + (sx >> 3)] & (0x80 >> (sx & 7))) + nbmap[(sy * bpr) + (col >> 3)] |= masks[(col & 7) / n]; + } + } + free((char *) gp->bitmap); + gp->bytes = bytes; + gp->bitmap = nbmap; + } +} + +static void +#ifdef __STDC__ +_bdf_n_to_one(bdf_glyphlist_t *gl) +#else +_bdf_n_to_one(gl) +bdf_glyphlist_t *gl; +#endif +{ + long i; + unsigned short bpr, sbpr, bytes, col, sx, sy; + unsigned char *nbmap, *masks; + bdf_glyph_t *gp; + + if (gl == 0 || gl->glyphs_used == 0) + return; + + masks = 0; + switch (gl->bpp) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) { + if (gp->bbx.width == 0 || gp->bbx.height == 0) + continue; + sbpr = ((gp->bbx.width * gl->bpp) + 7) >> 3; + bpr = (gp->bbx.width + 7) >> 3; + bytes = bpr * gp->bbx.height; + nbmap = (unsigned char *) malloc(bytes); + (void) memset((char *) nbmap, 0, bytes); + + for (sy = 0; sy < gp->bbx.height; sy++) { + for (col = sx = 0; sx < gp->bbx.width; sx++, col += gl->bpp) { + if (gp->bitmap[(sy * sbpr) + (col >> 3)] & + masks[(col & 7) / gl->bpp]) + nbmap[(sy * bpr) + (sx >> 3)] |= (0x80 >> (sx & 7)); + } + } + free((char *) gp->bitmap); + gp->bytes = bytes; + gp->bitmap = nbmap; + } + gl->bpp = 1; +} + +static void +#ifdef __STDC__ +_bdf_two_to_four(bdf_glyphlist_t *gl) +#else +_bdf_two_to_four(gl) +bdf_glyphlist_t *gl; +#endif +{ + long i; + unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy; + unsigned char *nbmap, *masks; + bdf_glyph_t *gp; + + if (gl == 0 || gl->glyphs_used == 0) + return; + + masks = twobpp; + + for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) { + if (gp->bbx.width == 0 || gp->bbx.height == 0) + continue; + sbpr = ((gp->bbx.width << 1) + 7) >> 3; + bpr = ((gp->bbx.width << 2) + 7) >> 3; + bytes = bpr * gp->bbx.height; + nbmap = (unsigned char *) malloc(bytes); + (void) memset((char *) nbmap, 0, bytes); + + for (sy = 0; sy < gp->bbx.height; sy++) { + for (col = sx = 0; sx < gp->bbx.width; sx++, col += 2) { + si = (col & 7) >> 1; + byte = gp->bitmap[(sy * sbpr) + (col >> 3)] & masks[si]; + if (byte) { + /* + * Shift the byte down to make an index. + */ + if (si < 3) + byte >>= (3 - si) * gl->bpp; + + /* + * Scale the index to four bits per pixel and shift it into + * place before adding it. + */ + byte = (byte << 2) + 3; + if ((sx & 1) == 0) + byte <<= 4; + nbmap[(sy * bpr) + ((sx << 2) >> 3)] |= byte; + } + } + } + free((char *) gp->bitmap); + gp->bytes = bytes; + gp->bitmap = nbmap; + } + gl->bpp = 4; +} + +static void +#ifdef __STDC__ +_bdf_four_to_two(bdf_glyphlist_t *gl) +#else +_bdf_four_to_two(gl) +bdf_glyphlist_t *gl; +#endif +{ + long i; + unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy; + unsigned char *nbmap, *masks; + bdf_glyph_t *gp; + + if (gl == 0 || gl->glyphs_used == 0) + return; + + masks = fourbpp; + + gl->bpp = 2; + for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) { + sbpr = ((gp->bbx.width << 2) + 7) >> 3; + bpr = ((gp->bbx.width << 1) + 7) >> 3; + bytes = bpr * gp->bbx.height; + nbmap = (unsigned char *) malloc(bytes); + (void) memset((char *) nbmap, 0, bytes); + + for (sy = 0; sy < gp->bbx.height; sy++) { + for (col = sx = 0; sx < gp->bbx.width; sx++, col += 4) { + si = (col & 7) >> 2; + byte = gp->bitmap[(sy * sbpr) + (col >> 3)] & masks[si]; + if (byte) { + /* + * Shift the byte down to make an index. + */ + if (si == 0) + byte >>= 4; + + /* + * Scale the index to two bits per pixel and shift it into + * place if necessary. + */ + byte >>= 2; + + si = ((sx << 1) & 7) >> 1; + if (si < 3) + byte <<= (3 - si) << 1; + + nbmap[(sy * bpr) + ((sx << 1) >> 3)] |= byte; + } + } + } + free((char *) gp->bitmap); + gp->bytes = bytes; + gp->bitmap = nbmap; + } +} + +int +#ifdef __STDC__ +bdf_replace_glyphs(bdf_font_t *font, long start, bdf_glyphlist_t *glyphs, + int unencoded) +#else +bdf_replace_glyphs(font, start, glyphs, unencoded) +bdf_font_t *font; +long start; +bdf_glyphlist_t *glyphs; +int unencoded; +#endif +{ + int resize, appending; + long i, n, ng, end, del, remaining, off[2]; + bdf_glyph_t *sgp, *gp, *dgp; + short maxas, maxds, maxrb, minlb, maxlb, rb; + double ps, rx, dw; + bdf_bbx_t nbbx; + + resize = 0; + + if (font == 0) + return resize; + + /* + * Dither the incoming bitmaps so they match the same bits per pixel as + * the font. + */ + if (glyphs->bpp != font->bpp) { + if (glyphs->bpp == 1) + _bdf_one_to_n(glyphs, font->bpp); + else if (font->bpp == 1) + _bdf_n_to_one(glyphs); + else if (glyphs->bpp == 2) + _bdf_two_to_four(glyphs); + else + _bdf_four_to_two(glyphs); + } + + /* + * Set the point size and horizontal resolution so the scalable width can + * be determined. + */ + ps = (double) font->point_size; + rx = (double) font->resolution_x; + + /* + * Determine if a resize is needed. + */ + + /* + * Determine the bounding box for the font without the characters being + * replaced. + */ + minlb = 32767; + maxlb = maxrb = maxas = maxds = 0; + + /* + * Get the font bounds. + */ + maxas = MAX(font->bbx.ascent, maxas); + maxds = MAX(font->bbx.descent, maxds); + rb = font->bbx.width + font->bbx.x_offset; + maxrb = MAX(rb, maxrb); + minlb = MIN(font->bbx.x_offset, minlb); + maxlb = MAX(font->bbx.x_offset, maxlb); + + /* + * Get the bounds of the incoming glyphs. + */ + maxas = MAX(glyphs->bbx.ascent, maxas); + maxds = MAX(glyphs->bbx.descent, maxds); + rb = glyphs->bbx.width + glyphs->bbx.x_offset; + maxrb = MAX(rb, maxrb); + minlb = MIN(glyphs->bbx.x_offset, minlb); + maxlb = MAX(glyphs->bbx.x_offset, maxlb); + + /* + * Set up the new font bounding box, minus the characters that are being + * removed and with the new characters added. + */ + nbbx.width = maxrb - minlb; + nbbx.x_offset = minlb; + + nbbx.height = maxas + maxds; + nbbx.ascent = maxas; + nbbx.descent = maxds; + nbbx.y_offset = -maxds; + + /* + * Now determine if the combination of the glyphs removed and the new + * glyphs cause the font bounding box to be changed. + */ + resize = (nbbx.width > font->bbx.width || + nbbx.height > font->bbx.height) ? 1 : 0; + + /* + * Set the pointers to the glyphs. + */ + ng = (unencoded == 0) ? font->glyphs_used : font->unencoded_used; + sgp = gp = (unencoded == 0) ? font->glyphs : font->unencoded; + + /* + * Locate the closest glyph on or following `start'. + */ + for (i = 0; i < ng && gp->encoding < start; i++, gp++) ; + + appending = (i == ng); + + /* + * Set the starting point for copying the incoming glyphs. + */ + dgp = gp; + + n = glyphs->end - glyphs->start; + end = start + n; + + /* + * Delete all the glyphs between `start' and `end'. + */ + for (del = 0, i = start; i <= end; i++) { + /* + * Mark the character as being modified. + */ + if (ng > 0 && !appending && gp->encoding == i) { + if (unencoded == 0) + _bdf_set_glyph_modified(font->nmod, i); + else + _bdf_set_glyph_modified(font->umod, i); + + if (gp->name != 0) + free(gp->name); + if (gp->bytes > 0) + free((char *) gp->bitmap); + del++; + gp++; + } + } + + /* + * Determine how many glyphs remain following the last one deleted. + */ + remaining = ng - (gp - sgp); + + if (glyphs->glyphs_used == 0) { + /* + * If the glyph list is empty, then shift any remaining glyphs down + * to the destination. + */ + _bdf_memmove((char *) dgp, (char *) gp, + sizeof(bdf_glyph_t) * remaining); + if (unencoded == 0) + font->glyphs_used -= del; + else + font->unencoded_used -= del; + } else { + /* + * Insert the glyph list after making sure there is enough space to + * hold them. Also adjust the encoding and scalable width values + * after copying the glyphs. + */ + if (unencoded == 0) { + n = (font->glyphs_used - del) + glyphs->glyphs_used; + if (n > font->glyphs_size) { + off[0] = gp - sgp; + off[1] = dgp - sgp; + if (font->glyphs_size == 0) + font->glyphs = sgp = + (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * n); + else + font->glyphs = sgp = + (bdf_glyph_t *) realloc((char *) font->glyphs, + sizeof(bdf_glyph_t) * n); + gp = sgp + off[0]; + dgp = sgp + off[1]; + font->glyphs_size = n; + } + + /* + * Calculate how many will need to be shifted. + */ + if ((n = glyphs->glyphs_used - del) >= font->glyphs_used) + n = 0; + } else { + n = (font->unencoded_used - del) + glyphs->glyphs_used; + if (n > font->unencoded_size) { + off[0] = gp - sgp; + off[1] = dgp - sgp; + if (font->unencoded_size == 0) + font->unencoded = sgp = + (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * n); + else + font->unencoded = sgp = + (bdf_glyph_t *) realloc((char *) font->unencoded, + sizeof(bdf_glyph_t) * n); + gp = sgp + off[0]; + dgp = sgp + off[1]; + font->unencoded_size = n; + } + + /* + * Calculate how many will need to be shifted. + */ + if ((n = glyphs->glyphs_used - del) >= font->unencoded_used) + n = 0; + } + + /* + * Shift any following glyphs up or down if needed. + */ + if (n) + _bdf_memmove((char *)(gp + n), (char *) gp, + sizeof(bdf_glyph_t) * remaining); + + /* + * Copy the incoming glyphs, copy their names and bitmaps, + * set their encodings, and set their scalable widths. + */ + (void) memcpy((char *) dgp, (char *) glyphs->glyphs, + sizeof(bdf_glyph_t) * glyphs->glyphs_used); + for (i = 0; i < glyphs->glyphs_used; i++, dgp++) { + if (dgp->name != 0) + dgp->name = (char *) _bdf_strdup((unsigned char *) dgp->name, + strlen(dgp->name) + 1); + + if (dgp->bytes > 0) + dgp->bitmap = _bdf_strdup(dgp->bitmap, dgp->bytes); + + dgp->encoding = start + (dgp->encoding - glyphs->start); + + /* + * Mark the glyph as being modified in case it fills a cell that + * was empty before. + */ + _bdf_set_glyph_modified(font->nmod, dgp->encoding); + + dw = (double) dgp->dwidth; + dgp->swidth = (unsigned short)((dw * 72000.0) / (ps * rx)); + } + + /* + * Adjust the count of glyphs. + */ + ng = (ng - del) + glyphs->glyphs_used; + if (unencoded == 0) + font->glyphs_used = ng; + else + font->unencoded_used = ng; + } + + /* + * Last, if the replacement was done in the unencoded section, + * reencode all the glyphs so they show up properly. + */ + if (unencoded != 0) { + for (i = 0; i < ng; i++, sgp++) { + if (_bdf_glyph_modified(font->umod, sgp->encoding)) { + _bdf_clear_glyph_modified(font->umod, sgp->encoding); + _bdf_set_glyph_modified(font->umod, i); + } + sgp->encoding = i; + } + } + + if (resize) + (void) memcpy((char *) &font->bbx, (char *) &nbbx, sizeof(bdf_bbx_t)); + + font->modified = 1; + + return resize; +} + +int +#ifdef __STDC__ +bdf_insert_glyphs(bdf_font_t *font, long start, bdf_glyphlist_t *glyphs) +#else +bdf_insert_glyphs(font, start, glyphs) +bdf_font_t *font; +long start; +bdf_glyphlist_t *glyphs; +#endif +{ + int resize; + unsigned long i, ng, n, which; + bdf_glyph_t *gp; + + resize = 0; + + if (font == 0) + return resize; + + /* + * Dither the incoming bitmaps so they match the same bits per pixel as + * the font. + */ + if (glyphs->bpp != font->bpp) { + if (glyphs->bpp == 1) + _bdf_one_to_n(glyphs, font->bpp); + else if (font->bpp == 1) + _bdf_n_to_one(glyphs); + else if (glyphs->bpp == 2) + _bdf_two_to_four(glyphs); + else + _bdf_four_to_two(glyphs); + } + + /* + * Locate the starting glyph. + */ + gp = font->glyphs; + ng = font->glyphs_used; + for (i = 0; i < ng && gp->encoding < start; i++, gp++) ; + + /* + * If there are no glyphs at the starting point, then simply do a replace. + */ + if (i == ng) + return bdf_replace_glyphs(font, start, glyphs, 0); + + /* + * Go through the glyphs that would be shifted due to the insertion and + * determine if some of them will overflow the 0xffff boundary. + */ + n = (glyphs->end - glyphs->start) + 1; + for (which = i; i < ng; i++, gp++) { + if (gp->encoding + n > 0xffff) + break; + } + + if (i < ng) { + /* + * Some glyphs have to be moved to the unencoded area because they + * would overflow the 0xffff boundary if they were moved up. + */ + bdf_copy_glyphs(font, gp->encoding, font->glyphs[ng - 1].encoding, + &font->overflow, 0); + bdf_delete_glyphs(font, gp->encoding, font->glyphs[ng - 1].encoding, + 0); + resize += bdf_replace_glyphs(font, font->unencoded_used, + &font->overflow, 1); + } + + /* + * Go back to the insertion point and shift the remaining glyph encodings + * up by `n'. + */ + for (gp = font->glyphs + which; which < font->glyphs_used; which++, gp++) { + /* + * Mark the new glyph locations as being modified. + */ + gp->encoding += n; + _bdf_set_glyph_modified(font->nmod, gp->encoding); + } + + /* + * Finally, mark the font as being modified and insert the new glyphs. + */ + font->modified = 1; + + return resize + bdf_replace_glyphs(font, start, glyphs, 0); +} + +static void +#ifdef __STDC__ +_bdf_combine_glyphs(bdf_font_t *font, bdf_glyph_t *f, bdf_glyph_t *g) +#else +_bdf_combine_glyphs(font, f, g) +bdf_font_t *font; +bdf_glyph_t *f, *g; +#endif +{ + unsigned short x, sx, sy, si, dx, dy, di, byte, dbpr, fbpr, gbpr; + short maxas, maxds, maxrb, minlb, maxlb, rb; + unsigned char *masks; + bdf_bbx_t nbbx; + bdf_glyph_t tmp; + + /* + * Determine the max bounding box for the two glyphs. + */ + minlb = 32767; + maxlb = maxrb = maxas = maxds = 0; + + /* + * Get the font glyph bounds. + */ + maxas = MAX(f->bbx.ascent, maxas); + maxds = MAX(f->bbx.descent, maxds); + rb = f->bbx.width + f->bbx.x_offset; + maxrb = MAX(rb, maxrb); + minlb = MIN(f->bbx.x_offset, minlb); + maxlb = MAX(f->bbx.x_offset, maxlb); + + /* + * Get the bounds of the incoming glyph. + */ + maxas = MAX(g->bbx.ascent, maxas); + maxds = MAX(g->bbx.descent, maxds); + rb = g->bbx.width + g->bbx.x_offset; + maxrb = MAX(rb, maxrb); + minlb = MIN(g->bbx.x_offset, minlb); + maxlb = MAX(g->bbx.x_offset, maxlb); + + /* + * Set up the new glyph bounding box. + */ + nbbx.width = maxrb - minlb; + nbbx.x_offset = minlb; + nbbx.height = maxas + maxds; + nbbx.ascent = maxas; + nbbx.descent = maxds; + nbbx.y_offset = -maxds; + + masks = 0; + switch (font->bpp) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + fbpr = ((f->bbx.width * font->bpp) + 7) >> 3; + gbpr = ((g->bbx.width * font->bpp) + 7) >> 3; + dbpr = ((nbbx.width * font->bpp) + 7) >> 3; + + if (memcmp((char *) &nbbx, (char *) &f->bbx, sizeof(bdf_bbx_t)) == 0) { + /* + * The largest is the first, so merge the second in with it. + */ + dy = f->bbx.ascent - g->bbx.ascent; + for (sy = 0; sy < g->bbx.height; sy++, dy++) { + for (x = sx = 0; x < g->bbx.width; x++, sx += font->bpp) { + si = (sx & 7) / font->bpp; + if ((byte = g->bitmap[(sy * gbpr) + (sx >> 3)] & masks[si])) + /* + * No shifting of the byte is needed because the x offset + * is the same for both glyphs. + */ + f->bitmap[(dy * fbpr) + (sx >> 3)] |= byte; + } + } + } else if (memcmp((char *) &nbbx, (char *) &g->bbx, + sizeof(bdf_bbx_t)) == 0) { + /* + * The largest is the incoming glyph, so merge into that one and swap + * it with the font glyph. + */ + dy = g->bbx.ascent - f->bbx.ascent; + for (sy = 0; sy < f->bbx.height; sy++, dy++) { + for (x = sx = 0; x < f->bbx.width; x++, sx += font->bpp) { + si = (sx & 7) / font->bpp; + if ((byte = f->bitmap[(sy * gbpr) + (sx >> 3)] & masks[si])) + /* + * No shifting of the byte is needed because the x offset + * is the same for both glyphs. + */ + g->bitmap[(dy * fbpr) + (sx >> 3)] |= byte; + } + } + + /* + * Now swap the two glyphs while preserving the name and encoding of + * the first glyph. + */ + tmp.swidth = g->swidth; + tmp.dwidth = g->dwidth; + tmp.bytes = g->bytes; + tmp.bitmap = g->bitmap; + (void) memcpy((char *) &tmp.bbx, (char *) &g->bbx, sizeof(bdf_bbx_t)); + + g->swidth = f->swidth; + g->dwidth = f->dwidth; + g->bytes = f->bytes; + g->bitmap = f->bitmap; + (void) memcpy((char *) &g->bbx, (char *) &f->bbx, sizeof(bdf_bbx_t)); + + f->swidth = tmp.swidth; + f->dwidth = tmp.dwidth; + f->bytes = tmp.bytes; + f->bitmap = tmp.bitmap; + (void) memcpy((char *) &f->bbx, (char *) &tmp.bbx, sizeof(bdf_bbx_t)); + } else { + /* + * Need a new bitmap for the combination of the two. + */ + tmp.bytes = nbbx.height * dbpr; + tmp.bitmap = (unsigned char *) malloc(tmp.bytes); + (void) memset((char *) tmp.bitmap, 0, tmp.bytes); + + /* + * Merge the first glyph. + */ + dy = nbbx.ascent - f->bbx.ascent; + for (sy = 0; sy < f->bbx.height; sy++, dy++) { + dx = MYABS(nbbx.x_offset - f->bbx.x_offset) * font->bpp; + for (x = sx = 0; x < f->bbx.width; x++, + sx += font->bpp, dx += font->bpp) { + si = (sx & 7) / font->bpp; + if ((byte = f->bitmap[(sy * fbpr) + (sx >> 3)] & masks[si])) { + di = (dx & 7) / font->bpp; + if (di < si) + byte <<= (si - di) * font->bpp; + else if (di > si) + byte >>= (di - si) * font->bpp; + tmp.bitmap[(dy * dbpr) + (dx >> 3)] |= byte; + } + } + } + + /* + * Merge the second glyph. + */ + dy = nbbx.ascent - g->bbx.ascent; + for (sy = 0; sy < g->bbx.height; sy++, dy++) { + dx = MYABS(nbbx.x_offset - g->bbx.x_offset) * font->bpp; + for (x = sx = 0; x < g->bbx.width; x++, + sx += font->bpp, dx += font->bpp) { + si = (sx & 7) / font->bpp; + if ((byte = g->bitmap[(sy * gbpr) + (sx >> 3)] & masks[si])) { + di = (dx & 7) / font->bpp; + if (di < si) + byte <<= (si - di) * font->bpp; + else if (di > si) + byte >>= (di - si) * font->bpp; + tmp.bitmap[(dy * dbpr) + (dx >> 3)] |= byte; + } + } + } + + /* + * Now clear the font glyph and copy the temp glyph to it. + */ + if (f->bytes > 0) + free((char *) f->bitmap); + f->bytes = tmp.bytes; + f->bitmap = tmp.bitmap; + (void) memcpy((char *) &f->bbx, (char *) &nbbx, sizeof(bdf_bbx_t)); + + /* + * Set the device width. Pay attention to whether the font is + * monowidth or character cell. + */ + if (font->spacing != BDF_PROPORTIONAL) + f->dwidth = font->monowidth; + else + f->dwidth = MAX(f->dwidth, g->dwidth); + } +} + +int +#ifdef __STDC__ +bdf_merge_glyphs(bdf_font_t *font, long start, bdf_glyphlist_t *glyphs, + int unencoded) +#else +bdf_merge_glyphs(font, start, glyphs, unencoded) +bdf_font_t *font; +long start; +bdf_glyphlist_t *glyphs; +int unencoded; +#endif +{ + int resize; + long i, n, ng, end, add, enc, off; + bdf_glyph_t *sgp, *gp, *dgp, *base; + short maxas, maxds, maxrb, minlb, maxlb, rb; + double ps, rx, dw; + bdf_bbx_t nbbx; + + resize = 0; + + if (font == 0) + return resize; + + /* + * If the glyphs are being merged in the unencoded area, simply append + * them. The unencoded area is simply storage. + */ + if (unencoded) + return bdf_replace_glyphs(font, font->unencoded_used, glyphs, unencoded); + + /* + * Dither the incoming bitmaps so they match the same bits per pixel as + * the font. + */ + if (glyphs->bpp != font->bpp) { + if (glyphs->bpp == 1) + _bdf_one_to_n(glyphs, font->bpp); + else if (font->bpp == 1) + _bdf_n_to_one(glyphs); + else if (glyphs->bpp == 2) + _bdf_two_to_four(glyphs); + else + _bdf_four_to_two(glyphs); + } + + /* + * Set the point size and horizontal resolution so the scalable width can + * be determined. + */ + ps = (double) font->point_size; + rx = (double) font->resolution_x; + + /* + * Determine if a resize is needed. + */ + + /* + * Determine the bounding box for the font without the characters being + * replaced. + */ + minlb = 32767; + maxlb = maxrb = maxas = maxds = 0; + + /* + * Get the font bounds. + */ + maxas = MAX(font->bbx.ascent, maxas); + maxds = MAX(font->bbx.descent, maxds); + rb = font->bbx.width + font->bbx.x_offset; + maxrb = MAX(rb, maxrb); + minlb = MIN(font->bbx.x_offset, minlb); + maxlb = MAX(font->bbx.x_offset, maxlb); + + /* + * Get the bounds of the incoming glyphs. + */ + maxas = MAX(glyphs->bbx.ascent, maxas); + maxds = MAX(glyphs->bbx.descent, maxds); + rb = glyphs->bbx.width + glyphs->bbx.x_offset; + maxrb = MAX(rb, maxrb); + minlb = MIN(glyphs->bbx.x_offset, minlb); + maxlb = MAX(glyphs->bbx.x_offset, maxlb); + + /* + * Set up the new font bounding box, minus the characters that are being + * removed and with the new characters added. + */ + nbbx.width = maxrb - minlb; + nbbx.x_offset = minlb; + + nbbx.height = maxas + maxds; + nbbx.ascent = maxas; + nbbx.descent = maxds; + nbbx.y_offset = -maxds; + + /* + * Now determine if the combination of the glyphs removed and the new + * glyphs cause the font bounding box to be changed. + */ + resize = (nbbx.width > font->bbx.width || + nbbx.height > font->bbx.height) ? 1 : 0; + + /* + * Set the pointers to the glyphs. + */ + ng = (unencoded == 0) ? font->glyphs_used : font->unencoded_used; + gp = (unencoded == 0) ? font->glyphs : font->unencoded; + + /* + * Locate the closest glyph on or following `start'. + */ + for (i = 0; i < ng && gp->encoding < start; i++, gp++) ; + + if (i == ng) + /* + * If the gylphs are being added off the end of the list, simply insert + * them so any overflows can be handled. + */ + return bdf_insert_glyphs(font, start, glyphs); + + /* + * Set the starting point for copying the incoming glyphs. + */ + dgp = gp; + + n = glyphs->end - glyphs->start; + end = start + n; + + /* + * Count the number of glyphs that will be added and mark all the + * glyphs that will be modified. + */ + for (sgp = glyphs->glyphs, add = 0, i = start; i <= end; i++) { + enc = (sgp->encoding - glyphs->start) + start; + + /* + * Mark the glyph as being modified. + */ + if (unencoded == 0) + _bdf_set_glyph_modified(font->nmod, enc); + else + _bdf_set_glyph_modified(font->umod, enc); + + if (enc == gp->encoding) + sgp++; + else if (enc < gp->encoding) { + add++; + sgp++; + } + + if (gp->encoding == i) + gp++; + } + + if (add > 0) { + ng += add; + + /* + * Need to make room for some glyphs that will be added. + */ + if (unencoded) { + off = dgp - font->unencoded; + if (font->unencoded_used == 0) + font->unencoded = + (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * ng); + else + font->unencoded = + (bdf_glyph_t *) realloc((char *) font->unencoded, + sizeof(bdf_glyph_t) * ng); + dgp = font->unencoded + off; + font->unencoded_used = ng; + } else { + off = dgp - font->glyphs; + if (font->glyphs_used == 0) + font->glyphs = + (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * ng); + else + font->glyphs = + (bdf_glyph_t *) realloc((char *) font->glyphs, + sizeof(bdf_glyph_t) * ng); + dgp = font->glyphs + off; + font->glyphs_used = ng; + } + } + + /* + * Now go through and do two things: + * 1. Insert new incoming glyphs. + * 2. Combine two glyphs at the same location. + */ + base = (!unencoded) ? font->glyphs : font->unencoded; + for (gp = dgp, sgp = glyphs->glyphs, i = start; i <= end; i++) { + enc = (sgp->encoding - glyphs->start) + start; + if (enc < gp->encoding) { + /* + * Shift the glyphs up by one and add this one. + */ + if (gp - base < ng) + _bdf_memmove((char *)(gp + 1), (char *) gp, + sizeof(bdf_glyph_t) * (ng - (gp - base))); + (void) memcpy((char *) gp, (char *) sgp, sizeof(bdf_glyph_t)); + gp->name = (char *) _bdf_strdup((unsigned char *) gp->name, + strlen(gp->name) + 1); + if (gp->bytes > 0) + gp->bitmap = _bdf_strdup(gp->bitmap, gp->bytes); + gp->encoding = i; + sgp++; + dw = (double) gp->dwidth; + gp->swidth = (unsigned short)((dw * 72000.0) / (ps * rx)); + } else if (enc == gp->encoding) { + _bdf_combine_glyphs(font, gp, sgp); + dw = (double) gp->dwidth; + gp->swidth = (unsigned short)((dw * 72000.0) / (ps * rx)); + sgp++; + } + if (gp->encoding == i) + gp++; + } + + if (resize) + (void) memcpy((char *) &font->bbx, (char *) &nbbx, sizeof(bdf_bbx_t)); + + font->modified = 1; + + return resize; +} + +void +#ifdef __STDC__ +bdf_set_modified(bdf_font_t *font, int modified) +#else +bdf_set_modified(font, modified) +bdf_font_t *font; +int modified; +#endif +{ + if (font == 0 || font->modified == modified) + return; + + if (modified == 0) { + /* + * Clear out the modified bitmaps. + */ + (void) memset((char *) font->nmod, 0, sizeof(unsigned long) * 2048); + (void) memset((char *) font->umod, 0, sizeof(unsigned long) * 2048); + } + font->modified = modified; +} + +/************************************************************************** + * + * XLFD font name functions. + * + **************************************************************************/ + +static char *xlfdfields[] = { + "FOUNDRY", + "FAMILY_NAME", + "WEIGHT_NAME", + "SLANT", + "SETWIDTH_NAME", + "ADD_STYLE_NAME", + "PIXEL_SIZE", + "POINT_SIZE", + "RESOLUTION_X", + "RESOLUTION_Y", + "SPACING", + "AVERAGE_WIDTH", + "CHARSET_REGISTRY", + "CHARSET_ENCODING", +}; + +int +#ifdef __STDC__ +bdf_has_xlfd_name(bdf_font_t *font) +#else +bdf_has_xlfd_name(font) +bdf_font_t *font; +#endif +{ + unsigned long len; + char name[256]; + _bdf_list_t list; + + if (font == 0 || font->name == 0 || font->name[0] == 0) + return 0; + + len = (unsigned long)(strlen(font->name) + 1); + (void) memcpy(name, font->name, len); + list.size = list.used = 0; + _bdf_split("-", name, len, &list); + if (list.size > 0) + free((char *) list.field); + + return (list.used == 15); +} + +char * +#ifdef __STDC__ +bdf_make_xlfd_name(bdf_font_t *font, char *foundry, char *family) +#else +bdf_make_xlfd_name(font, foundry, family) +bdf_font_t *font; +char *foundry, *family; +#endif +{ + int len; + double dp, dr; + unsigned long i, width, used; + unsigned short awidth, pxsize; + bdf_property_t *pp; + bdf_glyph_t *gp; + char spacing, nbuf[256], *np, *name; + const char *val; + + if (font == 0 || bdf_has_xlfd_name(font)) + return 0; + + np = nbuf; + + /* + * Add the FOUNDRY field. + */ + if ((pp = bdf_get_font_property(font, "FOUNDRY")) != 0) + foundry = pp->value.atom; + sprintf(np, "-%s", foundry); + np += strlen(np); + + /* + * Add the FAMILY_NAME field. + */ + if ((pp = bdf_get_font_property(font, "FAMILY_NAME")) != 0) + family = pp->value.atom; + sprintf(np, "-%s", family); + np += strlen(np); + + /* + * Add the WEIGHT_NAME field. + */ + val = ((pp = bdf_get_font_property(font, "WEIGHT_NAME")) != 0) ? + pp->value.atom : "Medium"; + if (val == 0) + val = "Medium"; + sprintf(np, "-%s", val); + np += strlen(np); + + /* + * Add the SLANT field. + */ + val = ((pp = bdf_get_font_property(font, "SLANT")) != 0) ? + pp->value.atom : "R"; + if (val == 0) + val = "R"; + sprintf(np, "-%s", val); + np += strlen(np); + + /* + * Add the SETWIDTH_NAME field. + */ + val = ((pp = bdf_get_font_property(font, "SETWIDTH_NAME")) != 0) ? + pp->value.atom : "Normal"; + if (val == 0) + val = "Normal"; + sprintf(np, "-%s", val); + np += strlen(np); + + /* + * Add the ADD_STYLE_NAME field. + */ + val = ((pp = bdf_get_font_property(font, "ADD_STYLE_NAME")) != 0) ? + pp->value.atom : ""; + if (val == 0) + val = ""; + sprintf(np, "-%s", val); + np += strlen(np); + + /* + * Add the PIXEL_SIZE field. + */ + if ((pp = bdf_get_font_property(font, "PIXEL_SIZE")) != 0) + sprintf(np, "-%ld", pp->value.int32); + else { + /* + * Determine the pixel size. + */ + dp = (double)(font->point_size * 10); + dr = (double) font->resolution_y; + pxsize = (unsigned short)(((dp * dr) / 722.7) + 0.5); + sprintf(np, "-%hd", pxsize); + } + np += strlen(np); + + /* + * Add the POINT_SIZE field. + */ + if ((pp = bdf_get_font_property(font, "POINT_SIZE")) != 0) + sprintf(np, "-%ld", pp->value.int32); + else + sprintf(np, "-%ld", font->point_size * 10); + np += strlen(np); + + /* + * Add the RESOLUTION_X field. + */ + if ((pp = bdf_get_font_property(font, "RESOLUTION_X")) != 0) + sprintf(np, "-%ld", pp->value.card32); + else + sprintf(np, "-%ld", font->resolution_x); + np += strlen(np); + + /* + * Add the RESOLUTION_Y field. + */ + if ((pp = bdf_get_font_property(font, "RESOLUTION_Y")) != 0) + sprintf(np, "-%ld", pp->value.card32); + else + sprintf(np, "-%ld", font->resolution_y); + np += strlen(np); + + /* + * Add the SPACING field. + */ + if ((pp = bdf_get_font_property(font, "SPACING")) != 0) + spacing = pp->value.atom[0]; + else { + spacing = 'P'; + switch (font->spacing) { + case BDF_PROPORTIONAL: + spacing = 'P'; + break; + case BDF_MONOWIDTH: + spacing = 'M'; + break; + case BDF_CHARCELL: + spacing = 'C'; + break; + } + } + sprintf(np, "-%c", spacing); + np += strlen(np); + + /* + * Add the AVERAGE_WIDTH field. + */ + if ((pp = bdf_get_font_property(font, "AVERAGE_WIDTH")) != 0) + sprintf(np, "-%ld", pp->value.int32); + else { + /* + * Determine the average width of all the glyphs in the font. + */ + width = 0; + for (i = 0, gp = font->unencoded; i < font->unencoded_used; i++, gp++) + width += gp->dwidth; + for (i = 0, gp = font->glyphs; i < font->glyphs_used; i++, gp++) + width += gp->dwidth; + + used = font->unencoded_used + font->glyphs_used; + if (used == 0) + awidth = font->bbx.width * 10; + else + awidth = (unsigned short)((((float) width) / + ((float) used)) * 10.0); + sprintf(np, "-%hd", awidth); + } + np += strlen(np); + + /* + * Add the CHARSET_REGISTRY field. + */ + val = ((pp = bdf_get_font_property(font, "CHARSET_REGISTRY")) != 0) ? + pp->value.atom : "FontSpecific"; + sprintf(np, "-%s", val); + np += strlen(np); + + /* + * Add the CHARSET_ENCODING field. + */ + val = ((pp = bdf_get_font_property(font, "CHARSET_ENCODING")) != 0) ? + pp->value.atom : "0"; + sprintf(np, "-%s", val); + np += strlen(np); + + len = (np - nbuf) + 1; + name = (char *) malloc(len); + (void) memcpy(name, nbuf, len); + return name; +} + +void +#ifdef __STDC__ +bdf_update_name_from_properties(bdf_font_t *font) +#else +bdf_update_name_from_properties(font) +bdf_font_t *font; +#endif +{ + unsigned long i; + bdf_property_t *p; + _bdf_list_t list; + char *np, name[128], nname[128]; + + if (font == 0 || bdf_has_xlfd_name(font) == 0) + return; + + (void) memset((char *) &list, 0, sizeof(_bdf_list_t)); + + /* + * Split the name into fields and shift out the first empty field. + * This assumes that the font has a name. + */ + i = (unsigned long) strlen(font->name); + (void) memcpy(name, font->name, i + 1); + _bdf_split("-", name, i, &list); + _bdf_shift(1, &list); + + /* + * Initialize the pointer to the new name and add the '-' prefix. + */ + np = nname; + *np++ = '-'; + *np = 0; + + for (i = 0; i < 14; i++) { + if ((p = bdf_get_font_property(font, xlfdfields[i])) != 0) { + /* + * The property exists, so add it to the new font name. + */ + switch (p->format) { + case BDF_ATOM: + if (p->value.atom != 0) + sprintf(np, "%s", p->value.atom); + break; + case BDF_CARDINAL: + sprintf(np, "%ld", p->value.card32); + break; + case BDF_INTEGER: + sprintf(np, "%ld", p->value.int32); + break; + } + } else + /* + * The property does not exist, so add the original value to the + * new font name. + */ + sprintf(np, "%s", list.field[i]); + np += strlen(np); + if (i + 1 < 14) { + *np++ = '-'; + *np = 0; + } + } + + /* + * Replace the existing font name with the new one. + */ + free(font->name); + i = (unsigned long)(strlen(nname) + 1); + font->name = (char *) malloc(i); + (void) memcpy(font->name, nname, i); + + /* + * Free up the list. + */ + if (list.size > 0) + free((char *) list.field); + + font->modified = 1; +} + +void +#ifdef __STDC__ +bdf_update_properties_from_name(bdf_font_t *font) +#else +bdf_update_properties_from_name(font) +bdf_font_t *font; +#endif +{ + unsigned long i; + bdf_property_t *p, prop; + _bdf_list_t list; + char name[128]; + + if (font == 0 || font->name == 0 || bdf_has_xlfd_name(font) == 0) + return; + + (void) memset((char *) &list, 0, sizeof(_bdf_list_t)); + + /* + * Split the name into fields and shift out the first empty field. + */ + i = (unsigned long) strlen(font->name); + (void) memcpy(name, font->name, i + 1); + _bdf_split("-", name, i, &list); + _bdf_shift(1, &list); + + for (i = 0; i < 14; i++) { + p = bdf_get_property(xlfdfields[i]); + prop.name = p->name; + prop.format = p->format; + switch (prop.format) { + case BDF_ATOM: + prop.value.atom = list.field[i]; + break; + case BDF_CARDINAL: + prop.value.card32 = _bdf_atoul(list.field[i], 0, 10); + break; + case BDF_INTEGER: + prop.value.int32 = _bdf_atol(list.field[i], 0, 10); + break; + } + bdf_add_font_property(font, &prop); + } + + /* + * Free up the list. + */ + if (list.size > 0) + free((char *) list.field); + + font->modified = 1; +} + +int +#ifdef __STDC__ +bdf_update_average_width(bdf_font_t *font) +#else +bdf_update_average_width(font) +bdf_font_t *font; +#endif +{ + int changed; + unsigned long i; + long oaw, awidth, used; + bdf_glyph_t *gp; + _bdf_list_t list; + bdf_property_t *pp, prop; + char *np, num[16], nbuf[128]; + + changed = 0; + + used = font->unencoded_used + font->glyphs_used; + if (used == 0) + awidth = font->bbx.width * 10; + else { + for (i = 0, awidth = 0, gp = font->unencoded; i < font->unencoded_used; + i++, gp++) + awidth += gp->dwidth; + for (i = 0, gp = font->glyphs; i < font->glyphs_used; i++, gp++) + awidth += gp->dwidth; + awidth = (long)((((double) awidth) / ((double) used)) * 10.0); + } + + /* + * Check to see if it is different than the average width in the font + * name. + */ + if (bdf_has_xlfd_name(font)) { + (void) memset((char *) &list, 0, sizeof(_bdf_list_t)); + i = (unsigned long) strlen(font->name); + (void) memcpy(nbuf, font->name, i + 1); + _bdf_split("-", nbuf, i, &list); + oaw = _bdf_atol(list.field[12], 0, 10); + if (oaw != awidth) { + /* + * Construct a new font name with the new average width. + */ + changed = 1; + sprintf(num, "%ld", awidth); + used = strlen(num) - strlen(list.field[12]); + if (used > 0) { + /* + * Resize the string used for the font name instead of + * creating a new one. + */ + used += i; + font->name = (char *) realloc(font->name, used); + } + + /* + * Copy the elements of the list back into the new font name. + */ + np = font->name; + *np++ = '-'; + for (i = 1; i < list.used; i++) { + if (i == 12) + strcpy(np, num); + else + strcpy(np, list.field[i]); + np += strlen(np); + if (i + 1 < list.used) + *np++ = '-'; + } + } + + /* + * Clear up any space allocated for the list. + */ + if (list.size > 0) + free((char *) list.field); + } + + /* + * Now check for the AVERAGE_WIDTH property. + */ + if ((pp = bdf_get_font_property(font, "AVERAGE_WIDTH")) != 0) { + if (pp->value.int32 != awidth) { + changed = 1; + pp->value.int32 = awidth; + } + } else { + /* + * Property doesn't exist yet, so add it. + */ + changed = 1; + prop.name = "AVERAGE_WIDTH"; + prop.format = BDF_INTEGER; + prop.value.int32 = awidth; + bdf_add_font_property(font, &prop); + } + + if (changed) + font->modified = 1; + + return changed; +} + +/* + * Change the font bounding box and return a non-zero number if this causes + * the font to get larger or smaller. + */ +int +#ifdef __STDC__ +bdf_set_font_bbx(bdf_font_t *font, bdf_metrics_t *metrics) +#else +bdf_set_font_bbx(font, metrics) +bdf_font_t *font; +bdf_metrics_t *metrics; +#endif +{ + int resize; + + resize = 0; + + if (font == 0 || metrics == 0) + return resize; + + resize = (font->bbx.width != metrics->width || + font->bbx.height != metrics->height) ? 1 : 0; + + font->bbx.width = metrics->width; + font->bbx.height = metrics->height; + font->bbx.x_offset = metrics->x_offset; + font->bbx.y_offset = metrics->y_offset; + font->bbx.ascent = metrics->ascent; + font->bbx.descent = metrics->descent; + + /* + * If the font is not proportional, then make sure the monowidth field is + * set to the font bounding box. + */ + if (font->spacing != BDF_PROPORTIONAL) + font->monowidth = font->bbx.width; + + return resize; +} + +static bdf_glyph_t * +#ifdef __STDC__ +_bdf_locate_glyph(bdf_font_t *font, long code, int unencoded) +#else +_bdf_locate_glyph(font, code, unencoded) +bdf_font_t *font; +long code; +int unencoded; +#endif +{ + long l, r, m, nc; + bdf_glyph_t *gl; + + if (code < 0 || font == 0) + return 0; + + if ((unencoded && font->unencoded_used == 0) || + font->glyphs_used == 0) + return 0; + + if (unencoded) { + gl = font->unencoded; + nc = font->unencoded_used; + } else { + gl = font->glyphs; + nc = font->glyphs_used; + } + for (l = m = 0, r = nc - 1; l < r;) { + m = (l + r) >> 1; + if (gl[m].encoding < code) + l = m + 1; + else if (gl[m].encoding > code) + r = m - 1; + else + break; + } + + /* + * Go back until we hit the beginning of the glyphs or until + * we find the glyph with a code less than the specified code. + */ + while (m > 0 && gl[m].encoding > code) + m--; + + /* + * Look forward if necessary. + */ + while (m < nc && gl[m].encoding < code) + m++; + + return (m < nc) ? &gl[m] : &gl[nc - 1]; +} + +int +#ifdef __STDC__ +bdf_translate_glyphs(bdf_font_t *font, short dx, short dy, long start, + long end, bdf_callback_t callback, void *data, + int unencoded) +#else +bdf_translate_glyphs(font, dx, dy, start, end, callback, data, unencoded) +bdf_font_t *font; +short dx, dy; +long start, end; +bdf_callback_t callback; +void *data; +int unencoded; +#endif +{ + int resize, diff; + bdf_glyph_t *gp, *sp, *ep; + bdf_callback_struct_t cb; + + if (font == 0 || (dx == 0 && dy == 0)) + return 0; + + if ((unencoded && font->unencoded_used == 0) || font->glyphs_used == 0) + return 0; + + /* + * Call the progress initialization callback. + */ + if (callback != 0) { + cb.reason = BDF_TRANSLATE_START; + cb.total = (end - start) + 1; + cb.current = 0; + (*callback)(&cb, data); + } + + /* + * Locate the first and last glyphs to be shifted. + */ + sp = _bdf_locate_glyph(font, start, unencoded); + ep = _bdf_locate_glyph(font, end, unencoded); + for (resize = 0, gp = sp; sp <= ep; sp++) { + /* + * Call the callback if one was provided. + */ + if (sp != gp && callback != 0) { + cb.reason = BDF_TRANSLATING; + cb.current = (sp->encoding - start) + 1; + (*callback)(&cb, data); + } + + /* + * Apply the X translation. + */ + if (dx != 0) { + sp->bbx.x_offset += dx; + diff = sp->bbx.x_offset - font->bbx.x_offset; + if (sp->bbx.x_offset < font->bbx.x_offset) { + font->bbx.x_offset = sp->bbx.x_offset; + font->bbx.width += MYABS(diff); + resize = 1; + } else if (sp->bbx.width + sp->bbx.x_offset > + font->bbx.width + font->bbx.x_offset) { + font->bbx.width += MYABS(diff); + resize = 1; + } + + /* + * Mark the glyph as modified appropriately. + */ + if (unencoded) + _bdf_set_glyph_modified(font->umod, sp->encoding); + else + _bdf_set_glyph_modified(font->nmod, sp->encoding); + } + + /* + * Apply the Y translation. + */ + if (dy != 0) { + sp->bbx.y_offset += dy; + sp->bbx.descent = -sp->bbx.y_offset; + sp->bbx.ascent = sp->bbx.height - sp->bbx.descent; + diff = sp->bbx.y_offset - font->bbx.y_offset; + if (sp->bbx.y_offset < font->bbx.y_offset) { + font->bbx.y_offset = sp->bbx.y_offset; + font->bbx.descent = -font->bbx.y_offset; + font->bbx.height += MYABS(diff); + resize = 1; + } else if (sp->bbx.ascent > font->bbx.ascent) { + font->bbx.ascent += MYABS(diff); + font->bbx.height += MYABS(diff); + resize = 1; + } + + /* + * Mark the glyph as modified appropriately. + */ + if (unencoded) + _bdf_set_glyph_modified(font->umod, sp->encoding); + else + _bdf_set_glyph_modified(font->nmod, sp->encoding); + } + } + + /* + * Call the callback one more time to make sure the client knows + * this is done. + */ + if (callback != 0 && cb.current < cb.total) { + cb.reason = BDF_TRANSLATING; + cb.current = cb.total; + (*callback)(&cb, data); + } + + if (resize) + font->modified = 1; + + return resize; +} + +static void +#ifdef __STDC__ +_bdf_resize_rotation(bdf_font_t *font, int mul90, short degrees, + bdf_glyph_t *glyph, bdf_bitmap_t *scratch, + unsigned short *width, unsigned short *height) +#else +_bdf_resize_rotation(font, mul90, degrees, glyph, scratch, width, height) +bdf_font_t *font; +int mul90; +short degrees; +bdf_glyph_t *glyph; +bdf_bitmap_t *scratch; +unsigned short *width, *height; +#endif +{ + unsigned short w, h, wd, ht, bytes; + short cx, cy, x1, y1, x2, y2; + double dx1, dy1, dx2, dy2; + + w = h = 0; + + cx = glyph->bbx.width >> 1; + cy = glyph->bbx.height >> 1; + + /* + * Rotate the lower left and upper right corners and check for a potential + * resize. + */ + x1 = 0; + y1 = glyph->bbx.height; + x2 = glyph->bbx.width; + y2 = 0; + + dx1 = (double)(x1 - cx); + dy1 = (double)(y1 - cy); + dx2 = (double)(x2 - cx); + dy2 = (double)(y2 - cx); + + if (mul90) { + x1 = cx + (short)((dx1 * _bdf_cos_tbl[degrees]) - + (dy1 * _bdf_sin_tbl[degrees])); + y1 = cy + (short)((dx1 * _bdf_sin_tbl[degrees]) + + (dy1 * _bdf_cos_tbl[degrees])); + x2 = cx + (short)((dx2 * _bdf_cos_tbl[degrees]) - + (dy2 * _bdf_sin_tbl[degrees])); + y2 = cy + (short)((dx2 * _bdf_sin_tbl[degrees]) + + (dy2 * _bdf_cos_tbl[degrees])); + } else { + x1 = cx + _bdf_ceiling((dx1 * _bdf_cos_tbl[degrees]) - + (dy1 * _bdf_sin_tbl[degrees])); + y1 = cy + _bdf_ceiling((dx1 * _bdf_sin_tbl[degrees]) + + (dy1 * _bdf_cos_tbl[degrees])); + x2 = cx + _bdf_ceiling((dx2 * _bdf_cos_tbl[degrees]) - + (dy2 * _bdf_sin_tbl[degrees])); + y2 = cy + _bdf_ceiling((dx2 * _bdf_sin_tbl[degrees]) + + (dy2 * _bdf_cos_tbl[degrees])); + } + + wd = MYABS(x2 - x1); + ht = MYABS(y2 - y1); + + w = MAX(wd, w); + h = MAX(ht, h); + + if (wd > font->bbx.width) + font->bbx.width += wd - font->bbx.width; + if (ht > font->bbx.height) { + font->bbx.ascent += ht - font->bbx.height; + font->bbx.height += ht - font->bbx.height; + } + + /* + * Rotate the upper left and lower right corners and check for a potential + * resize. + */ + x1 = 0; + y1 = 0; + x2 = glyph->bbx.width; + y2 = glyph->bbx.height; + + dx1 = (double)(x1 - cx); + dy1 = (double)(y1 - cy); + dx2 = (double)(x2 - cx); + dy2 = (double)(y2 - cx); + + if (mul90) { + x1 = cx + (short)((dx1 * _bdf_cos_tbl[degrees]) - + (dy1 * _bdf_sin_tbl[degrees])); + y1 = cy + (short)((dx1 * _bdf_sin_tbl[degrees]) + + (dy1 * _bdf_cos_tbl[degrees])); + x2 = cx + (short)((dx2 * _bdf_cos_tbl[degrees]) - + (dy2 * _bdf_sin_tbl[degrees])); + y2 = cy + (short)((dx2 * _bdf_sin_tbl[degrees]) + + (dy2 * _bdf_cos_tbl[degrees])); + } else { + x1 = cx + _bdf_ceiling((dx1 * _bdf_cos_tbl[degrees]) - + (dy1 * _bdf_sin_tbl[degrees])); + y1 = cy + _bdf_ceiling((dx1 * _bdf_sin_tbl[degrees]) + + (dy1 * _bdf_cos_tbl[degrees])); + x2 = cx + _bdf_ceiling((dx2 * _bdf_cos_tbl[degrees]) - + (dy2 * _bdf_sin_tbl[degrees])); + y2 = cy + _bdf_ceiling((dx2 * _bdf_sin_tbl[degrees]) + + (dy2 * _bdf_cos_tbl[degrees])); + } + + wd = MYABS(x2 - x1); + ht = MYABS(y2 - y1); + + w = MAX(wd, w); + h = MAX(ht, h); + + if (wd > font->bbx.width) + font->bbx.width += wd - font->bbx.width; + if (ht > font->bbx.height) { + font->bbx.ascent += ht - font->bbx.height; + font->bbx.height += ht - font->bbx.height; + } + + if (font->bbx.width > scratch->width || + font->bbx.height > scratch->height) { + scratch->width = MAX(font->bbx.width, scratch->width); + scratch->height = MAX(font->bbx.height, scratch->height); + bytes = (((font->bbx.width * font->bpp) + 7) >> 3) * font->bbx.height; + if (scratch->bytes == 0) + scratch->bitmap = (unsigned char *) malloc(bytes); + else + scratch->bitmap = (unsigned char *) + realloc((char *) scratch->bitmap, bytes); + scratch->bytes = bytes; + } + + /* + * Clear the bitmap. + */ + (void) memset((char *) scratch->bitmap, 0, scratch->bytes); + + /* + * Return the new glyph width and height. + */ + *width = w; + *height = h; +} + +int +#ifdef __STDC__ +bdf_rotate_glyphs(bdf_font_t *font, short degrees, long start, + long end, bdf_callback_t callback, void *data, + int unencoded) +#else +bdf_rotate_glyphs(font, degrees, start, end, callback, data, unencoded) +bdf_font_t *font; +short degrees; +long start, end; +bdf_callback_t callback; +void *data; +int unencoded; +#endif +{ + int mul90, bpr, sbpr; + unsigned short wd, ht, si, di, byte, col; + short x, y, cx, cy, nx, ny, ox, oy, shiftx, shifty; + bdf_glyph_t *gp, *sp, *ep; + unsigned char *masks; + double dx, dy; + bdf_bitmap_t scratch; + bdf_callback_struct_t cb; + + if (font == 0 || (unencoded && font->unencoded_used == 0) || + font->glyphs_used == 0) + return 0; + + while (degrees < 0) + degrees += 360; + while (degrees >= 360) + degrees -= 360; + + if (degrees == 0) + return 0; + + mul90 = ((degrees % 90) == 0) ? 1 : 0; + + masks = 0; + switch (font->bpp) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + /* + * Initialize the scratch bitmap. + */ + (void) memset((char *) &scratch, 0, sizeof(bdf_bitmap_t)); + + /* + * Call the progress initialization callback. + */ + if (callback != 0) { + cb.reason = BDF_ROTATE_START; + cb.total = (end - start) + 1; + cb.current = 0; + (*callback)(&cb, data); + } + + sp = _bdf_locate_glyph(font, start, unencoded); + ep = _bdf_locate_glyph(font, end, unencoded); + for (gp = sp; sp <= ep; sp++) { + /* + * Call the callback if one was provided. + */ + if (sp != gp && callback != 0) { + cb.reason = BDF_ROTATING; + cb.current = (sp->encoding - start) + 1; + (*callback)(&cb, data); + } + + /* + * Resize the bitmap, adjust the font bounding box, and get the new + * glyph width and height. + */ + _bdf_resize_rotation(font, mul90, degrees, sp, &scratch, &wd, &ht); + + cx = sp->bbx.width >> 1; + cy = sp->bbx.height >> 1; + + shiftx = shifty = 0; + sbpr = ((wd * font->bpp) + 7) >> 3; + bpr = ((sp->bbx.width * font->bpp) + 7) >> 3; + for (y = 0; y < sp->bbx.height; y++) { + for (col = x = 0; x < sp->bbx.width; x++, col += font->bpp) { + si = (col & 7) / font->bpp; + byte = sp->bitmap[(y * bpr) + (col >> 3)] & masks[si]; + if (byte) { + dx = (double)(x - cx); + dy = (double)(y - cy); + if (mul90) { + nx = cx + (short)((dx * _bdf_cos_tbl[degrees]) - + (dy * _bdf_sin_tbl[degrees])); + ny = cy + (short)((dx * _bdf_sin_tbl[degrees]) + + (dy * _bdf_cos_tbl[degrees])); + } else { + nx = cx + _bdf_ceiling((dx * _bdf_cos_tbl[degrees]) - + (dy * _bdf_sin_tbl[degrees])); + ny = cy + _bdf_ceiling((dx * _bdf_sin_tbl[degrees]) + + (dy * _bdf_cos_tbl[degrees])); + } + if (nx < 0) { + shiftx = MIN(shiftx, nx); + nx += wd; + } else if (nx >= wd) { + ox = (nx - wd) + 1; + shiftx = MAX(shiftx, ox); + nx -= wd; + } + if (ny < 0) { + shifty = MIN(shifty, ny); + ny += ht; + } else if (ny >= ht) { + oy = (ny - ht) + 1; + shifty = MAX(shifty, oy); + ny -= ht; + } + nx *= font->bpp; + di = (nx & 7) / font->bpp; + if (di < si) + byte <<= (si - di) * font->bpp; + else if (di > si) + byte >>= (di - si) * font->bpp; + scratch.bitmap[(ny * sbpr) + (nx >> 3)] |= byte; + } + } + } + /* + * Resize the glyph bitmap if necessary. + */ + if (wd != sp->bbx.width || ht != sp->bbx.height) { + sp->bbx.width = wd; + sp->bbx.height = ht; + sp->bbx.ascent = ht - sp->bbx.descent; + sp->bytes = (((wd * font->bpp) + 7) >> 3) * ht; + sp->bitmap = (unsigned char *) + realloc((char *) sp->bitmap, sp->bytes); + } + (void) memset((char *) sp->bitmap, 0, sp->bytes); + + /* + * Copy the glyph from the scratch area to the glyph bitmap, + * adjusting for any shift values encountered. + */ + bpr = ((sp->bbx.width * font->bpp) + 7) >> 3; + for (y = 0; y < sp->bbx.height; y++) { + for (col = x = 0; x < sp->bbx.width; x++, col += font->bpp) { + si = (col & 7) / font->bpp; + byte = scratch.bitmap[(y * bpr) + (col >> 3)] & masks[si]; + if (byte) { + nx = x - shiftx; + ny = y - shifty; + if (nx < 0) + nx += sp->bbx.width; + else if (nx >= sp->bbx.width) + nx -= sp->bbx.width; + if (ny < 0) + ny += sp->bbx.height; + else if (ny >= sp->bbx.height) + ny -= sp->bbx.height; + nx *= font->bpp; + di = (nx & 7) / font->bpp; + if (di < si) + byte <<= (si - di) * font->bpp; + else if (di > si) + byte >>= (di - si) * font->bpp; + sp->bitmap[(ny * bpr) + (nx >> 3)] |= byte; + } + } + } + /* + * Mark the glyph as modified. + */ + if (unencoded) + _bdf_set_glyph_modified(font->umod, sp->encoding); + else + _bdf_set_glyph_modified(font->nmod, sp->encoding); + } + + /* + * Call the callback one more time to make sure the client knows + * this is done. + */ + if (callback != 0 && cb.current < cb.total) { + cb.reason = BDF_TRANSLATING; + cb.current = cb.total; + (*callback)(&cb, data); + } + + if (scratch.bytes > 0) + free((char *) scratch.bitmap); + + /* + * Rotations always change things, so just return a value indicating this. + */ + font->modified = 1; + return 1; +} + +static void +#ifdef __STDC__ +_bdf_resize_shear(bdf_font_t *font, int neg, short degrees, + bdf_glyph_t *glyph, bdf_bitmap_t *scratch, + unsigned short *width, unsigned short *height) +#else +_bdf_resize_shear(font, neg, degrees, glyph, scratch, width, height) +bdf_font_t *font; +int neg; +short degrees; +bdf_glyph_t *glyph; +bdf_bitmap_t *scratch; +unsigned short *width, *height; +#endif +{ + unsigned short wd, w, bytes; + short x1, y1, x2, y2; + + w = 0; + *height = glyph->bbx.height; + + /* + * Shear the lower left and upper right corners and check for a potential + * resize. + */ + x1 = 0; + y1 = glyph->bbx.height; + x2 = glyph->bbx.width; + y2 = 0; + + if (neg) { + x1 += (short)((double) y1 * _bdf_tan_tbl[degrees]); + x2 += (short)((double) y2 * _bdf_tan_tbl[degrees]); + } else { + x1 += (short)((double)(glyph->bbx.height - y1) * + _bdf_tan_tbl[degrees]); + x2 += (short)((double)(glyph->bbx.height - y2) * + _bdf_tan_tbl[degrees]); + } + + wd = MYABS(x2 - x1); + w = MAX(w, wd); + + if (wd > font->bbx.width) + font->bbx.width += wd - font->bbx.width; + + /* + * Shear the upper left and lower right corners and check for a potential + * resize. + */ + x1 = 0; + y1 = 0; + x2 = glyph->bbx.width; + y2 = glyph->bbx.height; + + if (neg) { + x1 += (short)((double) y1 * _bdf_tan_tbl[degrees]); + x2 += (short)((double) y2 * _bdf_tan_tbl[degrees]); + } else { + x1 += (short)((double)(glyph->bbx.height - y1) * + _bdf_tan_tbl[degrees]); + x2 += (short)((double)(glyph->bbx.height - y2) * + _bdf_tan_tbl[degrees]); + } + + wd = MYABS(x2 - x1); + w = MAX(w, wd); + + if (wd > font->bbx.width) + font->bbx.width += wd - font->bbx.width; + + if (font->bbx.width > scratch->width || + font->bbx.height > scratch->height) { + scratch->width = MAX(font->bbx.width, scratch->width); + scratch->height = MAX(font->bbx.height, scratch->height); + bytes = (((font->bbx.width * font->bpp) + 7) >> 3) * font->bbx.height; + if (scratch->bytes == 0) + scratch->bitmap = (unsigned char *) malloc(bytes); + else + scratch->bitmap = (unsigned char *) + realloc((char *) scratch->bitmap, bytes); + scratch->bytes = bytes; + } + + /* + * Clear the bitmap. + */ + (void) memset((char *) scratch->bitmap, 0, scratch->bytes); + + /* + * Return the new glyph width. + */ + *width = w; +} + +int +#ifdef __STDC__ +bdf_shear_glyphs(bdf_font_t *font, short degrees, long start, + long end, bdf_callback_t callback, void *data, + int unencoded) +#else +bdf_shear_glyphs(font, degrees, start, end, callback, data, unencoded) +bdf_font_t *font; +short degrees; +long start, end; +bdf_callback_t callback; +void *data; +int unencoded; +#endif +{ + int neg, bpr, sbpr; + unsigned short wd, ht, si, di, byte, col; + short x, y, nx, shiftx, ox; + bdf_glyph_t *gp, *sp, *ep; + unsigned char *masks; + bdf_bitmap_t scratch; + bdf_callback_struct_t cb; + + if (font == 0 || (unencoded && font->unencoded_used == 0) || + font->glyphs_used == 0) + return 0; + + if (degrees == 0 || degrees < -45 || degrees > 45) + return 0; + + if ((neg = (degrees < 0))) + degrees = -degrees; + + masks = 0; + switch (font->bpp) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + /* + * Initialize the scratch bitmap. + */ + (void) memset((char *) &scratch, 0, sizeof(bdf_bitmap_t)); + + /* + * Call the progress initialization callback. + */ + if (callback != 0) { + cb.reason = BDF_SHEAR_START; + cb.total = (end - start) + 1; + cb.current = 0; + (*callback)(&cb, data); + } + + sp = _bdf_locate_glyph(font, start, unencoded); + ep = _bdf_locate_glyph(font, end, unencoded); + for (gp = sp; sp <= ep; sp++) { + /* + * Call the callback if one was provided. + */ + if (sp != gp && callback != 0) { + cb.reason = BDF_SHEARING; + cb.current = (sp->encoding - start) + 1; + (*callback)(&cb, data); + } + + /* + * Resize the bitmap, adjust the font bounding box, and get the new + * glyph width and height. + */ + _bdf_resize_shear(font, neg, degrees, sp, &scratch, &wd, &ht); + + shiftx = 0; + sbpr = ((wd * font->bpp) + 7) >> 3; + bpr = ((sp->bbx.width * font->bpp) + 7) >> 3; + for (y = 0; y < sp->bbx.height; y++) { + for (col = x = 0; x < sp->bbx.width; x++, col += font->bpp) { + si = (col & 7) / font->bpp; + byte = sp->bitmap[(y * bpr) + (col >> 3)] & masks[si]; + if (byte) { + if (neg) + nx = x + (short)((double) y * _bdf_tan_tbl[degrees]); + else + nx = x + (short)((double)(sp->bbx.height - y) * + _bdf_tan_tbl[degrees]); + + if (nx < 0) { + shiftx = MIN(shiftx, nx); + nx += wd; + } else if (nx >= wd) { + ox = (nx - wd) + 1; + shiftx = MAX(shiftx, ox); + nx -= wd; + } + nx *= font->bpp; + di = (nx & 7) / font->bpp; + if (di < si) + byte <<= (si - di) * font->bpp; + else if (di > si) + byte >>= (di - si) * font->bpp; + scratch.bitmap[(y * sbpr) + (nx >> 3)] |= byte; + } + } + } + /* + * Resize the glyph bitmap if necessary. + */ + if (wd != sp->bbx.width || ht != sp->bbx.height) { + sp->bbx.width = wd; + sp->bbx.height = ht; + sp->bbx.ascent = ht - sp->bbx.descent; + sp->bytes = (((wd * font->bpp) + 7) >> 3) * ht; + sp->bitmap = (unsigned char *) + realloc((char *) sp->bitmap, sp->bytes); + } + (void) memset((char *) sp->bitmap, 0, sp->bytes); + + /* + * Copy the glyph from the scratch area to the glyph bitmap, + * adjusting for any shift values encountered. + */ + bpr = ((sp->bbx.width * font->bpp) + 7) >> 3; + for (y = 0; y < sp->bbx.height; y++) { + for (col = x = 0; x < sp->bbx.width; x++, col += font->bpp) { + si = (col & 7) / font->bpp; + byte = scratch.bitmap[(y * bpr) + (col >> 3)] & masks[si]; + if (byte) { + nx = x - shiftx; + if (nx < 0) + nx += sp->bbx.width; + else if (nx >= sp->bbx.width) + nx -= sp->bbx.width; + nx *= font->bpp; + di = (nx & 7) / font->bpp; + if (di < si) + byte <<= (si - di) * font->bpp; + else if (di > si) + byte >>= (di - si) * font->bpp; + sp->bitmap[(y * bpr) + (nx >> 3)] |= byte; + } + } + } + /* + * Mark the glyph as modified. + */ + if (unencoded) + _bdf_set_glyph_modified(font->umod, sp->encoding); + else + _bdf_set_glyph_modified(font->nmod, sp->encoding); + } + + /* + * Call the callback one more time to make sure the client knows + * this is done. + */ + if (callback != 0 && cb.current < cb.total) { + cb.reason = BDF_TRANSLATING; + cb.current = cb.total; + (*callback)(&cb, data); + } + + if (scratch.bytes > 0) + free((char *) scratch.bitmap); + + /* + * Rotations always change things, so just return a value indicating this. + */ + font->modified = 1; + return 1; +} + +static void +#ifdef __STDC__ +_bdf_widen_by(bdf_font_t *f, bdf_glyph_t *g, bdf_bitmap_t *s, int n) +#else +_bdf_widen_by(f, g, s, n) +bdf_font_t *f; +bdf_glyph_t *g; +bdf_bitmap_t *s; +int n; +#endif +{ + int bytes, sbpr, dbpr, col; + short x, y, si, di; + unsigned char *bmap, *masks; + + masks = 0; + switch (f->bpp) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + s->height = g->bbx.height; + s->width = g->bbx.width + n; + + bytes = (((s->width * f->bpp) + 7) >> 3) * s->height; + + if (s->bytes == 0) + s->bitmap = (unsigned char *) malloc(bytes); + else + s->bitmap = (unsigned char *) + realloc((char *) s->bitmap, bytes); + s->bytes = bytes; + + (void) memset((char *) s->bitmap, 0, s->bytes); + + /* + * Copy the glyph bitmap to the scratch area, and then swap the bitmaps. + */ + sbpr = ((g->bbx.width * f->bpp) + 7) >> 3; + dbpr = ((s->width * f->bpp) + 7) >> 3; + for (y = 0; y < g->bbx.height; y++) { + for (col = x = 0; x < g->bbx.width; x++, col += f->bpp) { + si = (col & 7) / f->bpp; + bytes = g->bitmap[(y * sbpr) + (col >> 3)] & masks[si]; + if (bytes) { + di = ((x * f->bpp) & 7) / f->bpp; + if (di < si) + bytes <<= (si - di) * f->bpp; + else if (di > si) + bytes >>= (di - si) * f->bpp; + s->bitmap[(y * dbpr) + (col >> 3)] |= bytes; + } + } + } + g->bbx.width = s->width; + + /* + * Swap the bytes and bitmap fields from the scratch area and the glyph. + */ + bytes = g->bytes; + g->bytes = s->bytes; + s->bytes = bytes; + + bmap = g->bitmap; + g->bitmap = s->bitmap; + s->bitmap = bmap; +} + +int +#ifdef __STDC__ +bdf_embolden_glyphs(bdf_font_t *font, long start, long end, + bdf_callback_t callback, void *data, int unencoded, + int *resize) +#else +bdf_embolden_glyphs(font, start, end, callback, data, unencoded, resize) +bdf_font_t *font; +long start, end; +bdf_callback_t callback; +void *data; +int unencoded, *resize; +#endif +{ + int mod, gmod, bpr; + short x, y; + unsigned short si, di, b1, b2, col; + unsigned char *masks; + bdf_glyph_t *gp, *sp, *ep; + bdf_bitmap_t scratch; + bdf_callback_struct_t cb; + + if (font == 0 || (unencoded && font->unencoded_used == 0) || + font->glyphs_used == 0) + return 0; + + /* + * Initialize the scratch bitmap which may be needed. + */ + (void) memset((char *) &scratch, 0, sizeof(bdf_bitmap_t)); + + mod = 0; + gp = 0; + + masks = 0; + switch (font->bpp) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + /* + * Call the progress initialization callback. + */ + if (callback != 0) { + cb.reason = BDF_EMBOLDEN_START; + cb.total = (end - start) + 1; + cb.current = 0; + (*callback)(&cb, data); + } + + /* + * Initialize the resize flag for the caller. + */ + *resize = 0; + + sp = _bdf_locate_glyph(font, start, unencoded); + ep = _bdf_locate_glyph(font, end, unencoded); + for (; sp <= ep; sp++) { + /* + * Call the callback if one was provided. + */ + if (sp != gp && callback != 0) { + cb.reason = BDF_EMBOLDENING; + cb.current = (sp->encoding - start) + 1; + (*callback)(&cb, data); + } + + if (font->spacing == BDF_PROPORTIONAL || + (font->spacing == BDF_MONOWIDTH && + sp->bbx.width < font->bbx.width)) { + /* + * Only widen the glyph if it is within reason. + */ + _bdf_widen_by(font, sp, &scratch, 1); + + if (sp->bbx.width > font->bbx.width) { + /* + * Bump the font width up by the difference. + */ + font->bbx.width += sp->bbx.width - font->bbx.width; + *resize = 1; + } + } + + gmod = 0; + bpr = ((sp->bbx.width * font->bpp) + 7) >> 3; + for (y = 0; y < sp->bbx.height; y++) { + col = (sp->bbx.width - 1) * font->bpp; + for (x = sp->bbx.width - 1; x > 0; x--, col -= font->bpp) { + si = (col & 7) / font->bpp; + di = ((col - font->bpp) & 7) / font->bpp; + b1 = (x == sp->bbx.width) ? 0 : + sp->bitmap[(y * bpr) + (col >> 3)] & masks[si]; + b2 = sp->bitmap[(y * bpr) + ((col - font->bpp) >> 3)] & + masks[di]; + if (!b1 && b2) { + if (di < si) + b2 >>= (si - di) * font->bpp; + else if (di > si) + b2 <<= (di - si) * font->bpp; + sp->bitmap[(y * bpr) + (col >> 3)] |= b2; + gmod = mod = 1; + } + } + } + /* + * Mark the glyph as modified. + */ + if (gmod) { + if (unencoded) + _bdf_set_glyph_modified(font->umod, sp->encoding); + else + _bdf_set_glyph_modified(font->nmod, sp->encoding); + } + } + + /* + * Call the callback one more time to make sure the client knows + * this is done. + */ + if (callback != 0 && cb.current < cb.total) { + cb.reason = BDF_EMBOLDENING; + cb.current = cb.total; + (*callback)(&cb, data); + } + + /* + * Deallocate the scratch bitmap if necessary. + */ + if (scratch.bytes > 0) + free((char *) scratch.bitmap); + + font->modified = mod; + + return mod; +} + +static int _endian = 1; +static char *little_endian = (char *) & _endian; + +int +#ifdef __STDC__ +bdf_little_endian(void) +#else +bdf_little_endian() +#endif +{ + return *little_endian; +} diff --git a/tools/sci/bdf.h b/tools/sci/bdf.h new file mode 100644 index 0000000000..fe51caf020 --- /dev/null +++ b/tools/sci/bdf.h @@ -0,0 +1,675 @@ +/* + * Copyright 2001 Computing Research Labs, New Mexico State University + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT + * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef _h_bdf +#define _h_bdf + +/* + * $Id$ + */ + +#include <stdio.h> +#include <stdlib.h> +#ifndef __digital__ +#include <unistd.h> +#endif +#include <string.h> + +#ifdef HAVE_XLIB +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> +#endif /* HAVE_XLIB */ + +#ifdef HAVE_FREETYPE +#include <freetype.h> +#include <ftxsbit.h> +#endif /* HAVE_FREETYPE */ + +#ifdef __cplusplus +extern "C" { +#endif + + /* + * A macro for prototypes. + */ +#undef __ +#ifdef __STDC__ +#define __(x) x +#else +#define __(x) () +#endif + + /************************************************************************** + * + * BDF font options macros and types. + * + **************************************************************************/ + +#define BDF_UNIX_EOL 1 /* Save fonts with Unix LF. */ +#define BDF_DOS_EOL 2 /* Save fonts with DOS CRLF. */ +#define BDF_MAC_EOL 3 /* Save fonts with Mac CR. */ + +#define BDF_CORRECT_METRICS 0x01 /* Correct invalid metrics when loading. */ +#define BDF_KEEP_COMMENTS 0x02 /* Preserve the font comments. */ +#define BDF_KEEP_UNENCODED 0x04 /* Keep the unencoded glyphs. */ +#define BDF_PROPORTIONAL 0x08 /* Font has proportional spacing. */ +#define BDF_MONOWIDTH 0x10 /* Font has mono width. */ +#define BDF_CHARCELL 0x20 /* Font has charcell spacing. */ + +#define BDF_ALL_SPACING (BDF_PROPORTIONAL|BDF_MONOWIDTH|BDF_CHARCELL) + +#define BDF_DEFAULT_LOAD_OPTIONS \ + (BDF_CORRECT_METRICS|BDF_KEEP_COMMENTS|BDF_KEEP_UNENCODED|BDF_PROPORTIONAL) + + typedef struct { + int ttf_hint; + int correct_metrics; + int keep_unencoded; + int keep_comments; + int pad_cells; + int font_spacing; + long point_size; + unsigned long resolution_x; + unsigned long resolution_y; + int bits_per_pixel; + int eol; + } bdf_options_t; + + /* + * Callback function type for unknown configuration options. + */ + typedef int (*bdf_options_callback_t) __((bdf_options_t *opts, + char **params, + unsigned long nparams, + void *client_data)); + + /************************************************************************** + * + * BDF font property macros and types. + * + **************************************************************************/ + +#define BDF_ATOM 1 +#define BDF_INTEGER 2 +#define BDF_CARDINAL 3 + + /* + * This structure represents a particular property of a font. + * There are a set of defaults and each font has their own. + */ + typedef struct { + char *name; /* Name of the property. */ + int format; /* Format of the property. */ + int builtin; /* A builtin property. */ + union { + char *atom; + long int32; + unsigned long card32; + } value; /* Value of the property. */ + } bdf_property_t; + + /************************************************************************** + * + * SBIT metrics specific structures. + * + **************************************************************************/ + + /* + * Boolean flags for SBIT metrics files. + */ +#define BDF_SBIT_MONO_ADVANCE 0x0001 +#define BDF_SBIT_ADD_EBLC 0x0002 +#define BDF_SBIT_APPLE_COMPAT 0x0004 + + /* + * Direction macros (inclusive, can be combined). + */ +#define BDF_SBIT_HORIZONTAL 0x0008 +#define BDF_SBIT_VERTICAL 0x0010 + + /* + * Bitmap storage options (exclusive, cannot be combined). + */ +#define BDF_SBIT_STORE_SMALL 0x0020 +#define BDF_SBIT_STORE_FAST 0x0040 + + typedef struct { + short cnum; /* Caret slope numerator. */ + short cdenom; /* Caret slope denominator. */ + short coff; /* Caret offset. */ + short sx; /* Scaled version horizontal PPEM size. */ + short sy; /* Scaled version vertical PPEM size (optional).*/ + short flags; /* Booleans and other non-numeric values. */ + } bdf_sbit_t; + + /************************************************************************** + * + * BDF opaque undo information types. + * + **************************************************************************/ + + typedef struct _bdf_undo_struct *bdf_undo_t; + + /************************************************************************** + * + * BDF font metric and glyph types. + * + **************************************************************************/ + + /* + * A general bitmap type, mostly used when the glyph bitmap is being edited. + */ + typedef struct { + short x; + short y; + unsigned short width; + unsigned short height; + unsigned short bpp; + unsigned short pad; + unsigned char *bitmap; + unsigned long bytes; + } bdf_bitmap_t; + + typedef struct { + int font_spacing; + unsigned short swidth; + unsigned short dwidth; + unsigned short width; + unsigned short height; + short x_offset; + short y_offset; + short ascent; + short descent; + } bdf_metrics_t; + + typedef struct { + unsigned short width; + unsigned short height; + short x_offset; + short y_offset; + short ascent; + short descent; + } bdf_bbx_t; + + typedef struct { + char *name; /* Glyph name. */ + long encoding; /* Glyph encoding. */ + unsigned short swidth; /* Scalable width. */ + unsigned short dwidth; /* Device width. */ + bdf_bbx_t bbx; /* Glyph bounding box. */ + unsigned char *bitmap; /* Glyph bitmap. */ + unsigned short bytes; /* Number of bytes used for the bitmap. */ + } bdf_glyph_t; + + typedef struct { + unsigned short pad; /* Pad to 4-byte boundary. */ + unsigned short bpp; /* Bits per pixel. */ + long start; /* Beginning encoding value of glyphs. */ + long end; /* Ending encoding value of glyphs. */ + bdf_glyph_t *glyphs; /* Glyphs themselves. */ + unsigned long glyphs_size; /* Glyph structures allocated. */ + unsigned long glyphs_used; /* Glyph structures used. */ + bdf_bbx_t bbx; /* Overall bounding box of glyphs. */ + } bdf_glyphlist_t; + + typedef struct { + char *name; /* Name of the font. */ + bdf_bbx_t bbx; /* Font bounding box. */ + + long point_size; /* Point size of the font. */ + unsigned long resolution_x; /* Font horizontal resolution. */ + unsigned long resolution_y; /* Font vertical resolution. */ + + int hbf; /* Font came from an HBF font. */ + + int spacing; /* Font spacing value. */ + + unsigned short monowidth; /* Logical width for monowidth font. */ + + long default_glyph; /* Encoding of the default glyph. */ + + long font_ascent; /* Font ascent. */ + long font_descent; /* Font descent. */ + + long glyphs_size; /* Glyph structures allocated. */ + long glyphs_used; /* Glyph structures used. */ + bdf_glyph_t *glyphs; /* Glyphs themselves. */ + + long unencoded_size; /* Unencoded glyph structures allocated. */ + long unencoded_used; /* Unencoded glyph structures used. */ + bdf_glyph_t *unencoded; /* Unencoded glyphs themselves. */ + + unsigned long props_size; /* Font properties allocated. */ + unsigned long props_used; /* Font properties used. */ + bdf_property_t *props; /* Font properties themselves. */ + + char *comments; /* Font comments. */ + unsigned long comments_len; /* Length of comment string. */ + + char *acmsgs; /* Auto-correction messages. */ + unsigned long acmsgs_len; /* Length of auto-correction messages. */ + + bdf_glyphlist_t overflow; /* Storage used for glyph insertion. */ + + void *internal; /* Internal data for the font. */ + + unsigned long nmod[2048]; /* Bitmap indicating modified glyphs. */ + unsigned long umod[2048]; /* Bitmap indicating modified unencoded. */ + + unsigned short modified; /* Boolean indicating font modified. */ + unsigned short bpp; /* Bits per pixel. */ + + bdf_sbit_t *sbits; /* Associcated SBIT metrics. */ + unsigned long sbits_used; /* Number of SBIT metrics entries. */ + unsigned long sbits_size; /* Amount of entries allocated. */ + + bdf_undo_t *undo_stack; /* Record of undoable operations. */ + unsigned long undo_used; /* Amount of undo stack used. */ + unsigned long undo_size; /* Amount of undo stack allocated. */ + } bdf_font_t; + + /************************************************************************** + * + * BDF glyph grid structures for editing glyph bitmaps. + * + **************************************************************************/ + + typedef struct { + char *name; + long encoding; /* The glyph encoding. */ + unsigned short unencoded; /* Whether the glyph was unencoded. */ + unsigned short bpp; /* Bits per pixel. */ + int spacing; /* Font spacing. */ + long resolution_x; /* Horizontal resolution. */ + long resolution_y; /* Vertical resolution. */ + unsigned long point_size; /* Font point size. */ + unsigned short swidth; /* Scalable width. */ + unsigned short dwidth; /* Device width. */ + bdf_bbx_t font_bbx; /* Font bounding box. */ + bdf_bbx_t glyph_bbx; /* Glyph bounding box. */ + unsigned char *bitmap; /* The grid bitmap. */ + unsigned short bytes; /* Number of bytes in the grid bitmap. */ + short grid_width; /* Width of the grid. */ + short grid_height; /* Height of the grid. */ + short base_x; /* Baseline X coordinate. */ + short base_y; /* Baseline Y coordinate. */ + short glyph_x; /* Top-left X position of glyph. */ + short glyph_y; /* Top-left Y position of glyph. */ + unsigned short modified; /* Flag indicating if bitmap modified. */ + short cap_height; /* Font CAP_HEIGHT if it exists. */ + short x_height; /* Font X_HEIGHT if it exists. */ + bdf_bitmap_t sel; /* Selected portion of the glyph bitmap.*/ + } bdf_glyph_grid_t; + + /************************************************************************** + * + * Types for load/save callbacks. + * + **************************************************************************/ + + /* + * Callback reasons. + */ +#define BDF_LOAD_START 1 +#define BDF_LOADING 2 +#define BDF_SAVE_START 3 +#define BDF_SAVING 4 +#define BDF_TRANSLATE_START 5 +#define BDF_TRANSLATING 6 +#define BDF_ROTATE_START 7 +#define BDF_ROTATING 8 +#define BDF_SHEAR_START 9 +#define BDF_SHEARING 10 +#define BDF_GLYPH_NAME_START 11 +#define BDF_GLYPH_NAME 12 +#define BDF_EXPORT_START 13 +#define BDF_EXPORTING 14 +#define BDF_EMBOLDEN_START 15 +#define BDF_EMBOLDENING 16 +#define BDF_WARNING 20 +#define BDF_ERROR 21 + + /* + * Error codes. + */ +#define BDF_OK 0 +#define BDF_MISSING_START -1 +#define BDF_MISSING_FONTNAME -2 +#define BDF_MISSING_SIZE -3 +#define BDF_MISSING_FONTBBX -4 +#define BDF_MISSING_CHARS -5 +#define BDF_MISSING_STARTCHAR -6 +#define BDF_MISSING_ENCODING -7 +#define BDF_MISSING_BBX -8 + +#define BDF_NOT_CONSOLE_FONT -10 +#define BDF_NOT_MF_FONT -11 +#define BDF_NOT_PSF_FONT -12 +#define BDF_EMPTY_FONT -99 +#define BDF_INVALID_LINE -100 + + typedef struct { + unsigned long reason; + unsigned long current; + unsigned long total; + unsigned long errlineno; + } bdf_callback_struct_t; + + typedef void (*bdf_callback_t) __((bdf_callback_struct_t *call_data, + void *client_data)); + + /************************************************************************** + * + * BDF font API. + * + **************************************************************************/ + + /* + * Startup and shutdown functions. + */ + extern void bdf_setup __((void)); + extern void bdf_cleanup __((void)); + + /* + * Configuration file loading and saving. + */ + extern void bdf_load_options __((FILE *in, bdf_options_t *opts, + bdf_options_callback_t callback, + void *client_data)); + extern void bdf_save_options __((FILE *out, bdf_options_t *opts)); + + /* + * Font options functions. + */ + extern void bdf_default_options __((bdf_options_t *opts)); + + /* + * Font load, create, save and free functions. + */ + extern bdf_font_t *bdf_new_font __((char *name, long point_size, + long resolution_x, long resolution_y, + long spacing, int bpp)); + extern bdf_font_t *bdf_load_font __((FILE *in, bdf_options_t *opts, + bdf_callback_t callback, void *data)); + extern bdf_font_t *bdf_load_hbf_font __((char *filename, bdf_options_t *opts, + bdf_callback_t callback, void *data)); + +#ifdef HAVE_XLIB + extern bdf_font_t *bdf_load_server_font __((Display *d, XFontStruct *f, + char *name, bdf_options_t *opts, + bdf_callback_t callback, + void *data)); +#endif /* HAVE_XLIB */ + + extern int bdf_load_console_font __((FILE *in, bdf_options_t *opts, + bdf_callback_t callback, void *data, + bdf_font_t *fonts[3], int *nfonts)); + + extern int bdf_load_mf_font __((FILE *in, bdf_options_t *opts, + bdf_callback_t callback, void *data, + bdf_font_t **font)); + + extern void bdf_save_font __((FILE *out, bdf_font_t *font, + bdf_options_t *opts, bdf_callback_t callback, + void *data)); + + extern void bdf_save_sbit_metrics __((FILE *out, bdf_font_t *font, + bdf_options_t *opts, char *appname)); + + extern void bdf_export_hex __((FILE *out, bdf_font_t *font, + bdf_callback_t callback, void *data)); + + extern int bdf_export_psf __((FILE *out, bdf_font_t *font)); + + extern void bdf_free_font __((bdf_font_t *font)); + +#ifdef HAVE_FREETYPE + + /* + * TrueType related macros and functions. + */ + + /* + * ID numbers of the strings that can appear in a TrueType font. + */ +#define BDFTTF_COPYRIGHT_STRING 0 +#define BDFTTF_FAMILY_STRING 1 +#define BDFTTF_SUBFAMILY_STRING 2 +#define BDFTTF_UNIQUEID_STRING 3 +#define BDFTTF_FULLNAME_STRING 4 +#define BDFTTF_VENDOR_STRING 5 +#define BDFTTF_POSTSCRIPT_STRING 6 +#define BDFTTF_TRADEMARK_STRING 7 + + extern char *bdfttf_platform_name __((short pid)); + extern char *bdfttf_encoding_name __((short pid, short eid)); + extern int bdfttf_get_english_string __((TT_Face face, int nameID, + int dash_to_space, char *name)); + + extern int bdfttf_load_font __((TT_Face face, TT_Face_Properties *properties, + short pid, short eid, bdf_options_t *opts, + bdf_callback_t callback, void *data, + bdf_font_t **font)); + +#endif /* HAVE_FREETYPE */ + + /* + * FON/FNT related functions. + */ + + /* + * String ID numbers for FON/FNT fonts. + */ +#define BDFFNT_COPYRIGHT 1 +#define BDFFNT_TYPEFACE 2 + + /* + * Opaque font type. + */ + typedef struct _bdffnt_font_t *bdffnt_font_t; + + extern int bdffnt_open_font __((char *path, bdffnt_font_t *font)); + extern void bdffnt_close_font __((bdffnt_font_t font)); + extern int bdffnt_font_count __((bdffnt_font_t font)); + extern int bdffnt_get_copyright __((bdffnt_font_t font, unsigned long fontID, + unsigned char *string)); + extern int bdffnt_get_facename __((bdffnt_font_t font, unsigned long fontID, + int for_xlfd, unsigned char *string)); + extern int bdffnt_char_count __((bdffnt_font_t font, unsigned long fontID)); + extern int bdffnt_font_pointsize __((bdffnt_font_t font, + unsigned long fontID)); + extern int bdffnt_load_font __((bdffnt_font_t font, unsigned long fontID, + bdf_callback_t callback, void *data, + bdf_font_t **out)); + + /* + * Font property functions. + */ + extern void bdf_create_property __((char *name, int type)); + extern bdf_property_t *bdf_get_property __((char *name)); + extern unsigned long bdf_property_list __((bdf_property_t **props)); + + extern void bdf_add_font_property __((bdf_font_t *font, + bdf_property_t *property)); + extern void bdf_delete_font_property __((bdf_font_t *font, char *name)); + extern bdf_property_t *bdf_get_font_property __((bdf_font_t *font, + const char *name)); + extern unsigned long bdf_font_property_list __((bdf_font_t *font, + bdf_property_t **props)); + + /* + * Font comment functions. + */ + extern int bdf_replace_comments __((bdf_font_t *font, char *comments, + unsigned long comments_len)); + + /* + * Other miscellaneous functions. + */ + extern void bdf_set_default_metrics __((bdf_font_t *font)); + + /* + * Font glyph editing functions. + */ + extern int bdf_glyph_modified __((bdf_font_t *font, long which, + int unencoded)); + + extern void bdf_copy_glyphs __((bdf_font_t *font, long start, long end, + bdf_glyphlist_t *glyphs, int unencoded)); + + extern void bdf_delete_glyphs __((bdf_font_t *font, long start, long end, + int unencoded)); + + extern int bdf_insert_glyphs __((bdf_font_t *font, long start, + bdf_glyphlist_t *glyphs)); + + extern int bdf_replace_glyphs __((bdf_font_t *font, long start, + bdf_glyphlist_t *glyphs, int unencoded)); + + extern int bdf_merge_glyphs __((bdf_font_t *font, long start, + bdf_glyphlist_t *glyphs, int unencoded)); + + /************************************************************************** + * + * Other API functions. + * + **************************************************************************/ + + extern int bdf_set_font_bbx __((bdf_font_t *font, bdf_metrics_t *metrics)); + + extern void bdf_set_modified __((bdf_font_t *font, int modified)); + + extern int bdf_has_xlfd_name __((bdf_font_t *font)); + + extern char *bdf_make_xlfd_name __((bdf_font_t *font, char *foundry, + char *family)); + + extern void bdf_update_name_from_properties __((bdf_font_t *font)); + + extern void bdf_update_properties_from_name __((bdf_font_t *font)); + + extern int bdf_update_average_width __((bdf_font_t *font)); + + extern int bdf_set_unicode_glyph_names __((FILE *in, bdf_font_t *font, + bdf_callback_t callback)); + + extern int bdf_set_adobe_glyph_names __((FILE *in, bdf_font_t *font, + bdf_callback_t callback)); + + extern int bdf_set_glyph_code_names __((int prefix, bdf_font_t *font, + bdf_callback_t callback)); + + /************************************************************************** + * + * Glyph grid API. + * + **************************************************************************/ + + /* + * Glyph grid allocation and deallocation functions. + */ + extern bdf_glyph_grid_t *bdf_make_glyph_grid __((bdf_font_t *font, + long code, + int unencoded)); + extern void bdf_free_glyph_grid __((bdf_glyph_grid_t *grid)); + + /* + * Glyph grid information functions. + */ + extern void bdf_grid_image __((bdf_glyph_grid_t *grid, bdf_bitmap_t *image)); + extern void bdf_grid_origin __((bdf_glyph_grid_t *grid, short *x, short *y)); + extern bdf_glyph_t *bdf_grid_glyph __((bdf_glyph_grid_t *grid)); + + /* + * Glyph grid editing functions. + */ + extern int bdf_grid_enlarge __((bdf_glyph_grid_t *grid, unsigned short width, + unsigned short height)); + extern int bdf_grid_resize __((bdf_glyph_grid_t *grid, + bdf_metrics_t *metrics)); + extern int bdf_grid_crop __((bdf_glyph_grid_t *grid, int grid_modified)); + + extern int bdf_grid_set_pixel __((bdf_glyph_grid_t *grid, short x, short y, + int val)); + extern int bdf_grid_clear_pixel __((bdf_glyph_grid_t *grid, short x, short y)); + extern int bdf_grid_invert_pixel __((bdf_glyph_grid_t *grid, + short x, short y, int val)); + extern int bdf_grid_shift __((bdf_glyph_grid_t *grid, short xcount, + short ycount)); + extern int bdf_grid_flip __((bdf_glyph_grid_t *grid, short dir)); + extern int bdf_grid_rotate __((bdf_glyph_grid_t *grid, short degrees, + int *resize)); + extern int bdf_grid_shear __((bdf_glyph_grid_t *grid, short degrees, + int *resize)); + extern int bdf_grid_embolden __((bdf_glyph_grid_t *grid)); + + /* + * Glyph grid selection functions. + */ + extern int bdf_has_selection __((bdf_glyph_grid_t *grid, short *x, short *y, + short *width, short *height)); + extern void bdf_set_selection __((bdf_glyph_grid_t *grid, short x, short y, + short width, short height)); + extern void bdf_lose_selection __((bdf_glyph_grid_t *grid)); + extern void bdf_detach_selection __((bdf_glyph_grid_t *grid)); + extern void bdf_attach_selection __((bdf_glyph_grid_t *grid)); + extern void bdf_delete_selection __((bdf_glyph_grid_t *grid)); + extern int bdf_in_selection __((bdf_glyph_grid_t *grid, short x, short y, + short *set)); + extern void bdf_add_selection __((bdf_glyph_grid_t *grid, bdf_bitmap_t *sel)); + + /* + * Glyph grid misc functions. + */ + extern int bdf_grid_color_at __((bdf_glyph_grid_t *grid, short x, short y)); + + /* + * Graphical transformation functions. + */ + extern int bdf_translate_glyphs __((bdf_font_t *font, short dx, short dy, + long start, long end, + bdf_callback_t callback, void *data, + int unencoded)); + + extern int bdf_rotate_glyphs __((bdf_font_t *font, short degrees, + long start, long end, + bdf_callback_t callback, void *data, + int unencoded)); + + extern int bdf_shear_glyphs __((bdf_font_t *font, short degrees, + long start, long end, + bdf_callback_t callback, void *data, + int unencoded)); + + extern int bdf_embolden_glyphs __((bdf_font_t *font, long start, long end, + bdf_callback_t callback, void *data, + int unencoded, int *resize)); + + extern int bdf_little_endian __((void)); + +#undef __ + +#ifdef __cplusplus +} +#endif + +#endif /* _h_bdf */ diff --git a/tools/sci/bdfP.h b/tools/sci/bdfP.h new file mode 100644 index 0000000000..518cc76711 --- /dev/null +++ b/tools/sci/bdfP.h @@ -0,0 +1,142 @@ +/* + * Copyright 2001 Computing Research Labs, New Mexico State University + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT + * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef _h_bdfP +#define _h_bdfP + +/* + * $Id$ + */ + +#include "bdf.h" + +#ifdef __cplusplus +extern "C" { +#endif + + /* + * A macro for prototypes. + */ +#undef __ +#ifdef __STDC__ +#define __(x) x +#else +#define __(x) () +#endif + +#ifndef MYABS +#define MYABS(xx) ((xx) < 0 ? -(xx) : (xx)) +#endif + + /* + * Macros and structures used for undo operations in the font. + */ +#define _UNDO_REPLACE_GLYPHS 1 +#define _UNDO_INSERT_GLYPHS 2 +#define _UNDO_MERGE_GLYPHS 3 + + /* + * This structure is for undo operations of replacing and merging glyphs + * in the font. + */ + typedef struct { + bdf_bbx_t b; + bdf_glyphlist_t g; + } _bdf_undo1_t; + + /* + * This structure is for undo operations of inserting glyphs. + */ + typedef struct { + bdf_bbx_t b; + long start; + long end; + } _bdf_undo2_t; + + /* + * This is the final undo structure used to store undo information with the + * font. + */ + typedef struct _bdf_undo_struct { + int type; + union { + _bdf_undo1_t one; + _bdf_undo2_t two; + } field; + } bdf_undo_struct_t; + + /* + * Tables for rotation and shearing. + */ + extern double _bdf_cos_tbl[]; + extern double _bdf_sin_tbl[]; + extern double _bdf_tan_tbl[]; + + /* + * Arrays of masks for test with different bits per pixel. + */ + extern unsigned char onebpp[]; + extern unsigned char twobpp[]; + extern unsigned char fourbpp[]; + + /* + * Simple routine for determining the ceiling. + */ + extern short _bdf_ceiling __((double v)); + + extern unsigned char *_bdf_strdup __((unsigned char *s, unsigned long len)); + extern void _bdf_memmove __((char *dest, char *src, unsigned long bytes)); + + extern short _bdf_atos __((char *s, char **end, int base)); + extern long _bdf_atol __((char *s, char **end, int base)); + extern unsigned long _bdf_atoul __((char *s, char **end, int base)); + + /* + * Macros to test/set the modified status of a glyph. + */ +#define _bdf_glyph_modified(map, e) ((map)[(e) >> 5] & (1 << ((e) & 31))) +#define _bdf_set_glyph_modified(map, e) (map)[(e) >> 5] |= (1 << ((e) & 31)) +#define _bdf_clear_glyph_modified(map, e) (map)[(e) >> 5] &= ~(1 << ((e) & 31)) + + /* + * Function to add a message to the font. + */ + extern void _bdf_add_acmsg __((bdf_font_t *font, char *msg, + unsigned long len)); + + /* + * Function to add a comment to the font. + */ + extern void _bdf_add_comment __((bdf_font_t *font, char *comment, + unsigned long len)); + + /* + * Function to do glyph name table cleanup when exiting. + */ + extern void _bdf_glyph_name_cleanup __((void)); + +#undef __ + +#ifdef __cplusplus +} +#endif + +#endif /* _h_bdfP */ diff --git a/tools/sci/bdfgname.cpp b/tools/sci/bdfgname.cpp new file mode 100644 index 0000000000..694d82405c --- /dev/null +++ b/tools/sci/bdfgname.cpp @@ -0,0 +1,439 @@ +/* + * Copyright 2001 Computing Research Labs, New Mexico State University + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT + * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef lint +#ifdef __GNUC__ +static char rcsid[] __attribute__((unused)) = "$Id$"; +#else +static char rcsid[] = "$Id$"; +#endif +#endif + +#include "bdfP.h" + +typedef struct { + long code; + long start; + long end; + long pad; +} _bdf_adobe_name_t; + +static _bdf_adobe_name_t *adobe_names; +static unsigned long adobe_names_size; +static unsigned long adobe_names_used; + +/* + * Provide a maximum length for glyph names just to make things clearer. + */ +#define MAX_GLYPH_NAME_LEN 127 + +static int +#ifdef __STDC__ +getline(FILE *in, char *buf, int limit) +#else +getline(in, buf, limit) +FILE *in; +char *buf; +int limit; +#endif +{ + int c, i; + + c = EOF; + + for (i = 0; i < limit - 1; i++) { + if ((c = getc(in)) == EOF || (c == '\n' || c == '\r')) + break; + buf[i] = c; + } + buf[i] = 0; + + /* + * Discard the rest of the line which did not fit into the buffer. + */ + while (c != EOF && c != '\n' && c != '\r') + c = getc(in); + + if (c == '\r') { + /* + * Check for a trailing newline. + */ + c = getc(in); + if (c != '\n') + ungetc(c, in); + } + + return i; +} + +static long +#ifdef __STDC__ +_bdf_find_name(long code, char *name, FILE *in) +#else +_bdf_find_name(code, name, in) +long code; +char *name; +FILE *in; +#endif +{ + long c, i, pos; + char *sp, buf[256]; + + while (!feof(in)) { + pos = ftell(in); + (void) getline(in, buf, 256); + while (!feof(in) && (buf[0] == 0 || buf[0] == '#')) { + buf[0] = 0; + pos = ftell(in); + (void) getline(in, buf, 256); + } + + if (buf[0] == 0) + return -1; + + c = _bdf_atol(buf, 0, 16); + + if (c > code) { + /* + * Restore the last position read in case the code is not in the + * file and the current code is greater than the expected code. + */ + fseek(in, pos, 0L); + return -1; + } + + if (c == code) { + for (sp = buf; *sp != ';'; sp++) ; + sp++; + for (i = 0; *sp != ';' && i < MAX_GLYPH_NAME_LEN; sp++, i++) + name[i] = *sp; + name[i] = 0; + return i; + } + } + return -1; +} + +static int +#ifdef __STDC__ +by_encoding(const void *a, const void *b) +#else +by_encoding(a, b) +char *a, *b; +#endif +{ + _bdf_adobe_name_t *c1, *c2; + + c1 = (_bdf_adobe_name_t *) a; + c2 = (_bdf_adobe_name_t *) b; + if (c1->code < c2->code) + return -1; + else if (c1->code > c2->code) + return 1; + return 0; +} + +static void +#ifdef __STDC__ +_bdf_load_adobe_names(FILE *in) +#else +_bdf_load_adobe_names(in) +FILE *in; +#endif +{ + long c, pos; + char *sp, buf[256]; + + /* + * Go back to the beginning of the file to look for the code because the + * codes are not in order in the current Adobe Glyph Name list file. + */ + fseek(in, 0, 0); + + while (!feof(in)) { + pos = ftell(in); + (void) getline(in, buf, 256); + while (!feof(in) && (buf[0] == 0 || buf[0] == '#')) { + buf[0] = 0; + pos = ftell(in); + (void) getline(in, buf, 256); + } + + c = _bdf_atol(buf, 0, 16); + + /* + * Ignore the Adobe-specific names in the Private Use Area. + */ + if (c >= 0xe000 && c <= 0xf8ff) + continue; + + if (adobe_names_used == adobe_names_size) { + if (adobe_names_size == 0) + adobe_names = (_bdf_adobe_name_t *) + malloc(sizeof(_bdf_adobe_name_t) << 9); + else + adobe_names = (_bdf_adobe_name_t *) + realloc((char *) adobe_names, + sizeof(_bdf_adobe_name_t) * + (adobe_names_size + 512)); + (void) memset((char *)(adobe_names + adobe_names_size), 0, + sizeof(_bdf_adobe_name_t) << 9); + adobe_names_size += 512; + } + + adobe_names[adobe_names_used].code = c; + for (sp = buf; *sp != ';'; sp++) ; + sp++; + adobe_names[adobe_names_used].start = pos + (sp - buf); + for (; *sp != ';'; sp++) ; + adobe_names[adobe_names_used].end = pos + (sp - buf); + adobe_names_used++; + } + + /* + * Sort the results by code. + */ + qsort((char *) adobe_names, adobe_names_used, sizeof(_bdf_adobe_name_t), + by_encoding); +} + +static long +#ifdef __STDC__ +_bdf_find_adobe_name(long code, char *name, FILE *in) +#else +_bdf_find_adobe_name(code, name, in) +long code; +char *name; +FILE *in; +#endif +{ + long len; + int l, r, m; + + if (code < 0x20 || (code >= 0x7f && code <= 0x9f) || + code == 0xfffe || code == 0xffff) { + sprintf(name, "char%lu", code); + return (long) strlen(name); + } + + if (code >= 0xe000 && code <= 0xf8ff) { + sprintf(name, "uni%04lX", code & 0xffff); + return (long) strlen(name); + } + + if (adobe_names_size == 0) + _bdf_load_adobe_names(in); + + l = 0; + r = adobe_names_used - 1; + while (l <= r) { + m = (l + r) >> 1; + if (adobe_names[m].code < code) + l = m + 1; + else if (adobe_names[m].code > code) + r = m - 1; + else { + fseek(in, adobe_names[m].start, 0); + len = adobe_names[m].end - adobe_names[m].start; + if (len > MAX_GLYPH_NAME_LEN) + len = MAX_GLYPH_NAME_LEN; + len = (long) fread(name, sizeof(char), len, in); + name[len] = 0; + return len; + } + } + + sprintf(name, "uni%04lX", code & 0xffff); + return (long) strlen(name); +} + +static int +#ifdef __STDC__ +_bdf_set_glyph_names(FILE *in, bdf_font_t *font, bdf_callback_t callback, + int adobe) +#else +_bdf_set_glyph_names(in, font, callback, adobe) +FILE *in; +bdf_font_t *font; +bdf_callback_t callback; +int adobe; +#endif +{ + int changed; + long i, size, len; + bdf_glyph_t *gp; + bdf_callback_struct_t cb; + char name[MAX_GLYPH_NAME_LEN + 1]; + + if (callback != 0) { + cb.reason = BDF_GLYPH_NAME_START; + cb.current = 0; + cb.total = font->glyphs_used; + (*callback)(&cb, 0); + } + for (changed = 0, i = 0, gp = font->glyphs; i < font->glyphs_used; + i++, gp++) { + size = (adobe) ? + _bdf_find_adobe_name(gp->encoding, name, in) : + _bdf_find_name(gp->encoding, name, in); + if (size < 0) + continue; + + len = (gp->name) ? strlen(gp->name) : 0; + if (len == 0) { + gp->name = (char *) _bdf_strdup((unsigned char *) name, size + 1); + changed = 1; + } else if (size != len || strcmp(gp->name, name) != 0) { + /* + * Simply resize existing storage so lots of memory allocations + * are not needed. + */ + if (size > len) + gp->name = (char *) realloc(gp->name, size + 1); + (void) strcpy(gp->name, name); + changed = 1; + } + + if (callback != 0) { + cb.reason = BDF_GLYPH_NAME; + cb.current = i; + (*callback)(&cb, 0); + } + } + + if (callback != 0) { + cb.reason = BDF_GLYPH_NAME; + cb.current = cb.total; + (*callback)(&cb, 0); + } + + return changed; +} + +int +#ifdef __STDC__ +bdf_set_unicode_glyph_names(FILE *in, bdf_font_t *font, + bdf_callback_t callback) +#else +bdf_set_unicode_glyph_names(in, font, callback) +FILE *in; +bdf_font_t *font; +bdf_callback_t callback; +#endif +{ + return _bdf_set_glyph_names(in, font, callback, 0); +} + +int +#ifdef __STDC__ +bdf_set_adobe_glyph_names(FILE *in, bdf_font_t *font, bdf_callback_t callback) +#else +bdf_set_adobe_glyph_names(in, font, callback) +FILE *in; +bdf_font_t *font; +bdf_callback_t callback; +#endif +{ + return _bdf_set_glyph_names(in, font, callback, 1); +} + +int +#ifdef __STDC__ +bdf_set_glyph_code_names(int prefix, bdf_font_t *font, bdf_callback_t callback) +#else +bdf_set_glyph_code_names(prefix, font, callback) +int prefix; +bdf_font_t *font; +bdf_callback_t callback; +#endif +{ + int changed; + long i, size, len; + bdf_glyph_t *gp; + bdf_callback_struct_t cb; + char name[128]; + + if (callback != 0) { + cb.reason = BDF_GLYPH_NAME_START; + cb.current = 0; + cb.total = font->glyphs_used; + (*callback)(&cb, 0); + } + for (changed = 0, i = 0, gp = font->glyphs; i < font->glyphs_used; + i++, gp++) { + switch (prefix) { + case 'u': + sprintf(name, "uni%04lX", gp->encoding & 0xffff); + break; + case 'x': + sprintf(name, "0x%04lX", gp->encoding & 0xffff); + break; + case '+': + sprintf(name, "U+%04lX", gp->encoding & 0xffff); + break; + case '\\': + sprintf(name, "\\u%04lX", gp->encoding & 0xffff); + break; + } + size = 6; + + len = (gp->name) ? strlen(gp->name) : 0; + if (len == 0) { + gp->name = (char *) _bdf_strdup((unsigned char *) name, size + 1); + changed = 1; + } else if (size != len || strcmp(gp->name, name) != 0) { + /* + * Simply resize existing storage so lots of memory allocations + * are not needed. + */ + if (size > len) + gp->name = (char *) realloc(gp->name, size + 1); + (void) strcpy(gp->name, name); + changed = 1; + } + + if (callback != 0) { + cb.reason = BDF_GLYPH_NAME; + cb.current = i; + (*callback)(&cb, 0); + } + } + + if (callback != 0) { + cb.reason = BDF_GLYPH_NAME; + cb.current = cb.total; + (*callback)(&cb, 0); + } + + return changed; +} + +void +#ifdef __STDC__ +_bdf_glyph_name_cleanup(void) +#else +_bdf_glyph_name_cleanup() +#endif +{ + if (adobe_names_size > 0) + free((char *) adobe_names); + adobe_names_size = adobe_names_used = 0; +} diff --git a/tools/sci/bdfgrid.cpp b/tools/sci/bdfgrid.cpp new file mode 100644 index 0000000000..81dd35a4fa --- /dev/null +++ b/tools/sci/bdfgrid.cpp @@ -0,0 +1,3515 @@ +/* + * Copyright 2001 Computing Research Labs, New Mexico State University + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT + * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef lint +#ifdef __GNUC__ +static char rcsid[] __attribute__((unused)) = "$Id$"; +#else +static char rcsid[] = "$Id$"; +#endif +#endif + +#include "bdfP.h" + +#ifndef MYABS +#define MYABS(n) ((n) < 0 ? -(n) : (n)) +#endif + +#undef MAX +#define MAX(h, i) ((h) > (i) ? (h) : (i)) + +#undef MIN +#define MIN(l, o) ((l) < (o) ? (l) : (o)) + +double _bdf_cos_tbl[360] = { + 0.000000, 0.999848, 0.999391, 0.998630, 0.997564, 0.996195, + 0.994522, 0.992546, 0.990268, 0.987688, 0.984808, 0.981627, + 0.978148, 0.974370, 0.970296, 0.965926, 0.961262, 0.956305, + 0.951057, 0.945519, 0.939693, 0.933580, 0.927184, 0.920505, + 0.913545, 0.906308, 0.898794, 0.891007, 0.882948, 0.874620, + 0.866025, 0.857167, 0.848048, 0.838671, 0.829038, 0.819152, + 0.809017, 0.798636, 0.788011, 0.777146, 0.766044, 0.754710, + 0.743145, 0.731354, 0.719340, 0.707107, 0.694658, 0.681998, + 0.669131, 0.656059, 0.642788, 0.629320, 0.615661, 0.601815, + 0.587785, 0.573576, 0.559193, 0.544639, 0.529919, 0.515038, + 0.500000, 0.484810, 0.469472, 0.453990, 0.438371, 0.422618, + 0.406737, 0.390731, 0.374607, 0.358368, 0.342020, 0.325568, + 0.309017, 0.292372, 0.275637, 0.258819, 0.241922, 0.224951, + 0.207912, 0.190809, 0.173648, 0.156434, 0.139173, 0.121869, + 0.104528, 0.087156, 0.069756, 0.052336, 0.034899, 0.017452, + 0.000000, -0.017452, -0.034899, -0.052336, -0.069756, -0.087156, + -0.104528, -0.121869, -0.139173, -0.156434, -0.173648, -0.190809, + -0.207912, -0.224951, -0.241922, -0.258819, -0.275637, -0.292372, + -0.309017, -0.325568, -0.342020, -0.358368, -0.374607, -0.390731, + -0.406737, -0.422618, -0.438371, -0.453990, -0.469472, -0.484810, + -0.500000, -0.515038, -0.529919, -0.544639, -0.559193, -0.573576, + -0.587785, -0.601815, -0.615661, -0.629320, -0.642788, -0.656059, + -0.669131, -0.681998, -0.694658, -0.707107, -0.719340, -0.731354, + -0.743145, -0.754710, -0.766044, -0.777146, -0.788011, -0.798636, + -0.809017, -0.819152, -0.829038, -0.838671, -0.848048, -0.857167, + -0.866025, -0.874620, -0.882948, -0.891007, -0.898794, -0.906308, + -0.913545, -0.920505, -0.927184, -0.933580, -0.939693, -0.945519, + -0.951057, -0.956305, -0.961262, -0.965926, -0.970296, -0.974370, + -0.978148, -0.981627, -0.984808, -0.987688, -0.990268, -0.992546, + -0.994522, -0.996195, -0.997564, -0.998630, -0.999391, -0.999848, + -1.000000, -0.999848, -0.999391, -0.998630, -0.997564, -0.996195, + -0.994522, -0.992546, -0.990268, -0.987688, -0.984808, -0.981627, + -0.978148, -0.974370, -0.970296, -0.965926, -0.961262, -0.956305, + -0.951057, -0.945519, -0.939693, -0.933580, -0.927184, -0.920505, + -0.913545, -0.906308, -0.898794, -0.891007, -0.882948, -0.874620, + -0.866025, -0.857167, -0.848048, -0.838671, -0.829038, -0.819152, + -0.809017, -0.798636, -0.788011, -0.777146, -0.766044, -0.754710, + -0.743145, -0.731354, -0.719340, -0.707107, -0.694658, -0.681998, + -0.669131, -0.656059, -0.642788, -0.629320, -0.615661, -0.601815, + -0.587785, -0.573576, -0.559193, -0.544639, -0.529919, -0.515038, + -0.500000, -0.484810, -0.469472, -0.453990, -0.438371, -0.422618, + -0.406737, -0.390731, -0.374607, -0.358368, -0.342020, -0.325568, + -0.309017, -0.292372, -0.275637, -0.258819, -0.241922, -0.224951, + -0.207912, -0.190809, -0.173648, -0.156434, -0.139173, -0.121869, + -0.104528, -0.087156, -0.069756, -0.052336, -0.034899, -0.017452, + -0.000000, 0.017452, 0.034899, 0.052336, 0.069756, 0.087156, + 0.104528, 0.121869, 0.139173, 0.156434, 0.173648, 0.190809, + 0.207912, 0.224951, 0.241922, 0.258819, 0.275637, 0.292372, + 0.309017, 0.325568, 0.342020, 0.358368, 0.374607, 0.390731, + 0.406737, 0.422618, 0.438371, 0.453990, 0.469472, 0.484810, + 0.500000, 0.515038, 0.529919, 0.544639, 0.559193, 0.573576, + 0.587785, 0.601815, 0.615661, 0.629320, 0.642788, 0.656059, + 0.669131, 0.681998, 0.694658, 0.707107, 0.719340, 0.731354, + 0.743145, 0.754710, 0.766044, 0.777146, 0.788011, 0.798636, + 0.809017, 0.819152, 0.829038, 0.838671, 0.848048, 0.857167, + 0.866025, 0.874620, 0.882948, 0.891007, 0.898794, 0.906308, + 0.913545, 0.920505, 0.927184, 0.933580, 0.939693, 0.945519, + 0.951057, 0.956305, 0.961262, 0.965926, 0.970296, 0.974370, + 0.978148, 0.981627, 0.984808, 0.987688, 0.990268, 0.992546, + 0.994522, 0.996195, 0.997564, 0.998630, 0.999391, 0.999848, +}; + +double _bdf_sin_tbl[360] = { + 0.000000, 0.017452, 0.034899, 0.052336, 0.069756, 0.087156, + 0.104528, 0.121869, 0.139173, 0.156434, 0.173648, 0.190809, + 0.207912, 0.224951, 0.241922, 0.258819, 0.275637, 0.292372, + 0.309017, 0.325568, 0.342020, 0.358368, 0.374607, 0.390731, + 0.406737, 0.422618, 0.438371, 0.453990, 0.469472, 0.484810, + 0.500000, 0.515038, 0.529919, 0.544639, 0.559193, 0.573576, + 0.587785, 0.601815, 0.615661, 0.629320, 0.642788, 0.656059, + 0.669131, 0.681998, 0.694658, 0.707107, 0.719340, 0.731354, + 0.743145, 0.754710, 0.766044, 0.777146, 0.788011, 0.798636, + 0.809017, 0.819152, 0.829038, 0.838671, 0.848048, 0.857167, + 0.866025, 0.874620, 0.882948, 0.891007, 0.898794, 0.906308, + 0.913545, 0.920505, 0.927184, 0.933580, 0.939693, 0.945519, + 0.951057, 0.956305, 0.961262, 0.965926, 0.970296, 0.974370, + 0.978148, 0.981627, 0.984808, 0.987688, 0.990268, 0.992546, + 0.994522, 0.996195, 0.997564, 0.998630, 0.999391, 0.999848, + 1.000000, 0.999848, 0.999391, 0.998630, 0.997564, 0.996195, + 0.994522, 0.992546, 0.990268, 0.987688, 0.984808, 0.981627, + 0.978148, 0.974370, 0.970296, 0.965926, 0.961262, 0.956305, + 0.951057, 0.945519, 0.939693, 0.933580, 0.927184, 0.920505, + 0.913545, 0.906308, 0.898794, 0.891007, 0.882948, 0.874620, + 0.866025, 0.857167, 0.848048, 0.838671, 0.829038, 0.819152, + 0.809017, 0.798636, 0.788011, 0.777146, 0.766044, 0.754710, + 0.743145, 0.731354, 0.719340, 0.707107, 0.694658, 0.681998, + 0.669131, 0.656059, 0.642788, 0.629320, 0.615661, 0.601815, + 0.587785, 0.573576, 0.559193, 0.544639, 0.529919, 0.515038, + 0.500000, 0.484810, 0.469472, 0.453990, 0.438371, 0.422618, + 0.406737, 0.390731, 0.374607, 0.358368, 0.342020, 0.325568, + 0.309017, 0.292372, 0.275637, 0.258819, 0.241922, 0.224951, + 0.207912, 0.190809, 0.173648, 0.156434, 0.139173, 0.121869, + 0.104528, 0.087156, 0.069756, 0.052336, 0.034899, 0.017452, + 0.000000, -0.017452, -0.034899, -0.052336, -0.069756, -0.087156, + -0.104528, -0.121869, -0.139173, -0.156434, -0.173648, -0.190809, + -0.207912, -0.224951, -0.241922, -0.258819, -0.275637, -0.292372, + -0.309017, -0.325568, -0.342020, -0.358368, -0.374607, -0.390731, + -0.406737, -0.422618, -0.438371, -0.453990, -0.469472, -0.484810, + -0.500000, -0.515038, -0.529919, -0.544639, -0.559193, -0.573576, + -0.587785, -0.601815, -0.615661, -0.629320, -0.642788, -0.656059, + -0.669131, -0.681998, -0.694658, -0.707107, -0.719340, -0.731354, + -0.743145, -0.754710, -0.766044, -0.777146, -0.788011, -0.798636, + -0.809017, -0.819152, -0.829038, -0.838671, -0.848048, -0.857167, + -0.866025, -0.874620, -0.882948, -0.891007, -0.898794, -0.906308, + -0.913545, -0.920505, -0.927184, -0.933580, -0.939693, -0.945519, + -0.951057, -0.956305, -0.961262, -0.965926, -0.970296, -0.974370, + -0.978148, -0.981627, -0.984808, -0.987688, -0.990268, -0.992546, + -0.994522, -0.996195, -0.997564, -0.998630, -0.999391, -0.999848, + -1.000000, -0.999848, -0.999391, -0.998630, -0.997564, -0.996195, + -0.994522, -0.992546, -0.990268, -0.987688, -0.984808, -0.981627, + -0.978148, -0.974370, -0.970296, -0.965926, -0.961262, -0.956305, + -0.951057, -0.945519, -0.939693, -0.933580, -0.927184, -0.920505, + -0.913545, -0.906308, -0.898794, -0.891007, -0.882948, -0.874620, + -0.866025, -0.857167, -0.848048, -0.838671, -0.829038, -0.819152, + -0.809017, -0.798636, -0.788011, -0.777146, -0.766044, -0.754710, + -0.743145, -0.731354, -0.719340, -0.707107, -0.694658, -0.681998, + -0.669131, -0.656059, -0.642788, -0.629320, -0.615661, -0.601815, + -0.587785, -0.573576, -0.559193, -0.544639, -0.529919, -0.515038, + -0.500000, -0.484810, -0.469472, -0.453990, -0.438371, -0.422618, + -0.406737, -0.390731, -0.374607, -0.358368, -0.342020, -0.325568, + -0.309017, -0.292372, -0.275637, -0.258819, -0.241922, -0.224951, + -0.207912, -0.190809, -0.173648, -0.156434, -0.139173, -0.121869, + -0.104528, -0.087156, -0.069756, -0.052336, -0.034899, -0.017452, +}; + +double _bdf_tan_tbl[90] = { + 0.000000, 0.017455, 0.034921, 0.052408, 0.069927, 0.087489, + 0.105104, 0.122785, 0.140541, 0.158384, 0.176327, 0.194380, + 0.212557, 0.230868, 0.249328, 0.267949, 0.286745, 0.305731, + 0.324920, 0.344328, 0.363970, 0.383864, 0.404026, 0.424475, + 0.445229, 0.466308, 0.487733, 0.509525, 0.531709, 0.554309, + 0.577350, 0.600861, 0.624869, 0.649408, 0.674509, 0.700208, + 0.726543, 0.753554, 0.781286, 0.809784, 0.839100, 0.869287, + 0.900404, 0.932515, 0.965689, 1.000000, 1.035530, 1.072369, + 1.110613, 1.150368, 1.191754, 1.234897, 1.279942, 1.327045, + 1.376382, 1.428148, 1.482561, 1.539865, 1.600335, 1.664279, + 1.732051, 1.804048, 1.880726, 1.962611, 2.050304, 2.144507, + 2.246037, 2.355852, 2.475087, 2.605089, 2.747477, 2.904211, + 3.077684, 3.270853, 3.487414, 3.732051, 4.010781, 4.331476, + 4.704630, 5.144554, 5.671282, 6.313752, 7.115370, 8.144346, + 9.514364, 11.430052, 14.300666, 19.081137, 28.636253, 57.289962, +}; + +/* + * Determine the actual ink bounds. + */ +static int +#ifdef __STDC__ +_bdf_grid_ink_bounds(bdf_glyph_grid_t *grid, short *x, short *y, + short *width, short *height) +#else +_bdf_grid_ink_bounds(grid, x, y, width, height) +bdf_glyph_grid_t *grid; +short *x, *y, *width, *height; +#endif +{ + short bx, by, bwd, bht, minx, maxx, miny, maxy, dx, dy; + unsigned short bpr, ink, sel, col; + unsigned char *bmap, *masks; + + masks = 0; + switch (grid->bpp) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + if (grid->sel.width != 0 && grid->sel.height != 0) { + sel = 1; + bx = by = 0; + bwd = grid->sel.width; + bht = grid->sel.height; + bmap = grid->sel.bitmap; + } else { + sel = 0; + bx = grid->glyph_x; + by = grid->glyph_y; + bwd = grid->glyph_bbx.width; + bht = grid->glyph_bbx.height; + bmap = grid->bitmap; + } + maxx = maxy = 0; + minx = bx + bwd; + miny = by + bht; + + bpr = ((bwd * grid->bpp) + 7) >> 3; + ink = 0; + + bwd += bx; + bht += by; + for (dy = by; dy < bht; dy++) { + for (col = bx * grid->bpp, dx = bx; dx < bwd; dx++, col += grid->bpp) { + if (bmap[(dy * bpr) + (col >> 3)] & masks[(col & 7) / grid->bpp]) { + ink = 1; + minx = MIN(minx, dx); + miny = MIN(miny, dy); + maxx = MAX(maxx, dx); + maxy = MAX(maxy, dy); + } + } + } + + *x = minx + ((sel) ? grid->sel.x : 0); + *y = miny + ((sel) ? grid->sel.y : 0); + if (ink == 0) + *width = *height = 0; + else { + *width = (maxx - minx) + 1; + *height = (maxy - miny) + 1; + } + return ink; +} + +/************************************************************************** + * + * Glyph grid create and destroy functions. + * + **************************************************************************/ + +/* + * Make a glyph grid with the glyph bitmap set in the bitmap. + */ +bdf_glyph_grid_t * +#ifdef __STDC__ +bdf_make_glyph_grid(bdf_font_t *font, long code, int unencoded) +#else +bdf_make_glyph_grid(font, code, unencoded) +bdf_font_t *font; +long code; +int unencoded; +#endif +{ + unsigned short si, di, col, colx, byte; + short ht, as, ds, gsize, bpr, x, y, nx, ny; + long l, r, m; + bdf_glyph_grid_t *gr; + bdf_glyph_t *gl, *glp; + bdf_property_t *p; + unsigned char *masks; + char name[24]; + + if (font == 0) + return 0; + + /* + * Allocate the grid and initialize it. + */ + gr = (bdf_glyph_grid_t *) malloc(sizeof(bdf_glyph_grid_t)); + (void) memset((char *) gr, 0, sizeof(bdf_glyph_grid_t)); + + /* + * Set the encoding and the unencoded flag. + */ + gr->bpp = font->bpp; + gr->encoding = code; + gr->unencoded = unencoded; + + /* + * Set the glyph grid spacing. + */ + gr->spacing = font->spacing; + + /* + * Set the point size and resolutions. + */ + gr->point_size = font->point_size; + gr->resolution_x = font->resolution_x; + gr->resolution_y = font->resolution_y; + + /* + * Set the CAP_HEIGHT and X_HEIGHT if they exist in the font. + */ + if ((p = bdf_get_font_property(font, "CAP_HEIGHT")) != 0) + gr->cap_height = (short) p->value.int32; + if ((p = bdf_get_font_property(font, "X_HEIGHT")) != 0) + gr->x_height = (short) p->value.int32; + + masks = 0; + switch (gr->bpp) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + /* + * Copy the font bounding box into the grid. + */ + (void) memcpy((char *) &gr->font_bbx, (char *) &font->bbx, + sizeof(bdf_bbx_t)); + + if (unencoded) { + gl = font->unencoded; + r = font->unencoded_used; + } else { + gl = font->glyphs; + r = font->glyphs_used; + } + + /* + * Locate the specified glyph using a simple binary search. + */ + glp = 0; + if (r > 0) { + for (l = 0; r >= l;) { + m = (l + r) >> 1; + glp = gl + m; + if (glp->encoding == code) + break; + if (glp->encoding > code) + r = m - 1; + else if (glp->encoding < code) + l = m + 1; + glp = 0; + } + } + + ht = gr->font_bbx.height; + as = gr->font_bbx.ascent; + ds = gr->font_bbx.descent; + + /* + * 1. Determine width and height needed from the largest of the + * width or height. + */ + gr->grid_width = gr->grid_height = + MAX(gr->font_bbx.width, gr->font_bbx.height); + + /* + * 2. Make sure the grid is at least a square of the largest of the width + * or height of the glyph itself to allow room for transformations. + */ + if (glp != 0) { + /* + * Set the glyph name and other metrics. + */ + if (glp->name) { + gr->name = (char *) malloc(strlen(glp->name) + 1); + (void) memcpy(gr->name, glp->name, strlen(glp->name) + 1); + } else { + sprintf(name, "char%ld", code); + gr->name = (char *) malloc(strlen(name) + 1); + (void) memcpy(gr->name, name, strlen(name) + 1); + } + gr->dwidth = glp->dwidth; + + /* + * Copy the glyph bounding box into the grid. + */ + (void) memcpy((char *) &gr->glyph_bbx, (char *) &glp->bbx, + sizeof(bdf_bbx_t)); + + if (glp->bbx.height < glp->bbx.ascent + glp->bbx.descent) + gsize = glp->bbx.ascent + glp->bbx.descent; + else + gsize = glp->bbx.height; + + /* + * Figure the maximum of the glyph width and height. + */ + gsize = MAX(gr->glyph_bbx.width, gsize); + + /* + * If either the grid width or grid height is less than the + * grid size just determined, then adjust them to the new grid size. + */ + gr->grid_width = MAX(gr->grid_width, gsize); + gr->grid_height = MAX(gr->grid_height, gsize); + } else { + /* + * The glyph doesn't exist, so make up a name for it. + */ + if (unencoded) + sprintf(name, "unencoded%ld", code); + else + sprintf(name, "char%ld", code); + gr->name = (char *) malloc(strlen(name) + 1); + (void) memcpy(gr->name, name, strlen(name) + 1); + } + + /* + * If the font has character-cell or mono spacing, make sure the grid + * device width is set to the width stored in the font. + */ + if (gr->spacing != BDF_PROPORTIONAL) + gr->dwidth = font->monowidth; + + /* + * Determine the vertical origin based on the font bounding box. + */ + if (ht >= as + ds) + gr->base_y = (((gr->grid_height >> 1) - (ht >> 1)) + ht) - ds; + else + gr->base_y = ((gr->grid_height >> 1) - ((as + ds) >> 1)) + as; + + /* + * The final adjust is to check to see if the glyph positioned relative to + * the baseline would cause the grid to change size. This sometimes + * happens in fonts that have incorrect metrics. + */ + if (gr->base_y + gr->glyph_bbx.descent > gr->grid_height) { + gsize = gr->base_y + gr->glyph_bbx.descent; + gr->grid_width = MAX(gsize, gr->grid_width); + gr->grid_height = MAX(gsize, gr->grid_height); + } + + /* + * Determine the horizontal origin based on the font bounding box and + * centered within the grid. + */ + gr->base_x = (gr->grid_width >> 1) - (gr->font_bbx.width >> 1); + if (gr->font_bbx.x_offset < 0) + gr->base_x += MYABS(gr->font_bbx.x_offset); + + /* + * Allocate double the storage needed for the grid bitmap. The extra + * storage will be used for transformations. + */ + gr->bytes = ((((gr->grid_width * gr->bpp) + 7) >> 3) * + gr->grid_height) << 1; + gr->bitmap = (unsigned char *) malloc(gr->bytes); + (void) memset((char *) gr->bitmap, 0, gr->bytes); + + /* + * Initialize the top-left coordinates of the glyph to the baseline + * coordinates. + */ + gr->glyph_x = gr->base_x; + gr->glyph_y = gr->base_y; + + /* + * If the glyph was not found, simply return the empty grid. + */ + if (glp == 0) + return gr; + + /* + * Determine the top-left coordinates of the glyph with respect to the + * baseline coordinates. + */ + gr->glyph_x = nx = gr->base_x + gr->glyph_bbx.x_offset; + gr->glyph_y = ny = gr->base_y - gr->glyph_bbx.ascent; + + /* + * Now copy the glyph bitmap to the appropriate location in the + * grid. + */ + bpr = ((gr->glyph_bbx.width * gr->bpp) + 7) >> 3; + gsize = ((gr->grid_width * gr->bpp) + 7) >> 3; + for (y = 0; y < gr->glyph_bbx.height; y++, ny++) { + for (colx = nx * gr->bpp, col = x = 0; x < gr->glyph_bbx.width; + x++, col += gr->bpp, colx += gr->bpp) { + si = (col & 7) / gr->bpp; + byte = glp->bitmap[(y * bpr) + (col >> 3)] & masks[si]; + if (byte) { + di = (colx & 7) / gr->bpp; + if (di < si) + byte <<= (si - di) * gr->bpp; + else if (di > si) + byte >>= (di - si) * gr->bpp; + gr->bitmap[(ny * gsize) + (colx >> 3)] |= byte; + } + } + } + + /* + * Always crop the glyph to the ink bounds before editing. + */ + bdf_grid_crop(gr, 0); + + /* + * Return the grid. + */ + return gr; +} + +void +#ifdef __STDC__ +bdf_free_glyph_grid(bdf_glyph_grid_t *grid) +#else +bdf_free_glyph_grid(grid) +bdf_glyph_grid_t *grid; +#endif +{ + if (grid == 0) + return; + + if (grid->name != 0) + free(grid->name); + if (grid->bytes > 0) + free((char *) grid->bitmap); + if (grid->sel.bytes > 0) + free((char *) grid->sel.bitmap); + free((char *) grid); +} + +/************************************************************************** + * + * Glyph grid resize functions. + * + **************************************************************************/ + +/* + * Enlarge the grid without affecting the font or glyph metrics. + */ +int +#ifdef __STDC__ +bdf_grid_enlarge(bdf_glyph_grid_t *grid, unsigned short width, + unsigned short height) +#else +bdf_grid_enlarge(grid, width, height) +bdf_glyph_grid_t *grid; +unsigned short width, height; +#endif +{ + unsigned short si, di, col, colx, byte; + short ht, wd, as, ds, x, y, nx, ny; + unsigned short gwd, ght, bytes, obpr, nbpr, gsize; + unsigned char *bitmap, *masks; + + if (grid == 0 || (width < grid->grid_width && height < grid->grid_height)) + return 0; + + masks = 0; + switch (grid->bpp) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + ht = height; + as = grid->font_bbx.ascent; + ds = grid->font_bbx.descent; + + gwd = MAX(width, grid->grid_width); + ght = MAX(height, grid->grid_height); + gsize = MAX(gwd, ght); + + nbpr = ((gsize * grid->bpp) + 7) >> 3; + bytes = (nbpr * ght) << 1; + bitmap = (unsigned char *) malloc(bytes); + (void) memset((char *) bitmap, 0, bytes); + + /* + * Determine the new baseline. + */ + if (ht >= as + ds) + grid->base_y = (((ght >> 1) - (ht >> 1)) + ht) - ds; + else + grid->base_y = ((ght >> 1) - ((as + ds) >> 1)) + as; + + grid->base_x = (gwd >> 1) - (grid->font_bbx.width >> 1); + if (grid->font_bbx.x_offset < 0) + grid->base_x += MYABS(grid->font_bbx.x_offset); + + nx = grid->base_x + grid->glyph_bbx.x_offset; + ny = grid->base_y - grid->glyph_bbx.ascent; + + /* + * Now copy the bitmap into the new storage base on the new metrics + * values. + */ + obpr = ((grid->grid_width * grid->bpp) + 7) >> 3; + wd = grid->glyph_x + grid->glyph_bbx.width; + ht = grid->glyph_y + grid->glyph_bbx.height; + for (y = grid->glyph_y; y < ht; y++, ny++) { + col = grid->glyph_x * grid->bpp; + colx = nx * grid->bpp; + for (x = grid->glyph_x; x < wd; + x++, col += grid->bpp, colx += grid->bpp) { + si = (col & 7) / grid->bpp; + byte = grid->bitmap[(y * obpr) + (col >> 3)] & masks[si]; + if (byte) { + di = (colx & 7) / grid->bpp; + if (di < si) + byte <<= (si - di) * grid->bpp; + else if (di > si) + byte >>= (di - si) * grid->bpp; + bitmap[(ny * nbpr) + (colx >> 3)] |= byte; + } + } + } + + /* + * Adjust the glyph coordinates. + */ + grid->glyph_x = grid->base_x + grid->glyph_bbx.x_offset; + grid->glyph_y = grid->base_y - grid->glyph_bbx.ascent; + + /* + * Get rid of the old grid bitmap and replace it with the new one. + */ + free((char *) grid->bitmap); + grid->bytes = bytes; + grid->bitmap = bitmap; + + /* + * Update the new grid width and height. + */ + grid->grid_width = grid->grid_height = gsize; + + /* + * Always mark the grid as being modified on a resize. + */ + grid->modified = 1; + + return 1; +} + +/* + * Change the font bounding box values and resize the grid bitmap if + * necessary. + */ +int +#ifdef __STDC__ +bdf_grid_resize(bdf_glyph_grid_t *grid, bdf_metrics_t *metrics) +#else +bdf_grid_resize(grid, metrics) +bdf_glyph_grid_t *grid; +bdf_metrics_t *metrics; +#endif +{ + int changed; + unsigned short si, di, col, colx, byte; + short ht, wd, as, ds, x, y, nx, ny; + unsigned short gwd, ght, bytes, obpr, nbpr, gsize; + unsigned char *bitmap, *masks; + + changed = 0; + + if (grid == 0 || metrics == 0) + return changed; + + masks = 0; + switch (grid->bpp) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + /* + * Create new grid bitmaps in preparation for the various metrics changing. + */ + if (metrics->width > grid->grid_width || + metrics->height > grid->grid_height) { + changed = 1; + + ht = metrics->height; + as = metrics->ascent; + ds = metrics->descent; + + gwd = MAX(metrics->width, grid->grid_width); + ght = MAX(metrics->height, grid->grid_height); + + /* + * Get the larger of the two dimensions. + */ + gsize = MAX(gwd, ght); + + nbpr = ((gsize * grid->bpp) + 7) >> 3; + bytes = (nbpr * gsize) << 1; + bitmap = (unsigned char *) malloc(bytes); + (void) memset((char *) bitmap, 0, bytes); + + /* + * Determine the new baseline. + */ + if (ht >= as + ds) + grid->base_y = (((ght >> 1) - (ht >> 1)) + ht) - ds; + else + grid->base_y = ((ght >> 1) - ((as + ds) >> 1)) + as; + + grid->base_x = (gwd >> 1) - (metrics->width >> 1); + if (metrics->x_offset < 0) + grid->base_x += MYABS(metrics->x_offset); + + nx = grid->base_x + grid->glyph_bbx.x_offset; + ny = grid->base_y - grid->glyph_bbx.ascent; + + /* + * Now copy the bitmap into the new storage base on the new metrics + * values. + */ + obpr = ((grid->grid_width * grid->bpp) + 7) >> 3; + wd = grid->glyph_x + grid->glyph_bbx.width; + ht = grid->glyph_y + grid->glyph_bbx.height; + for (y = grid->glyph_y; y < ht; y++, ny++) { + col = grid->glyph_x * grid->bpp; + colx = nx * grid->bpp; + for (x = grid->glyph_x; x < wd; + x++, col += grid->bpp, colx += grid->bpp) { + si = (col & 7) / grid->bpp; + byte = grid->bitmap[(y * obpr) + (col >> 3)] & masks[si]; + if (byte) { + di = (colx & 7) / grid->bpp; + if (di < si) + byte <<= (si - di) * grid->bpp; + else if (di > si) + byte >>= (di - si) * grid->bpp; + bitmap[(ny * nbpr) + (colx >> 3)] |= byte; + } + } + } + + /* + * Adjust the glyph coordinates. + */ + grid->glyph_x = grid->base_x + grid->glyph_bbx.x_offset; + grid->glyph_y = grid->base_y - grid->glyph_bbx.ascent; + + /* + * Get rid of the old grid bitmap and replace it with the new one. + */ + free((char *) grid->bitmap); + grid->bytes = bytes; + grid->bitmap = bitmap; + + /* + * Update the new grid width and height. + */ + grid->grid_width = grid->grid_height = gsize; + + /* + * Copy the metrics info into the font bounding box. + */ + grid->font_bbx.width = metrics->width; + grid->font_bbx.x_offset = metrics->x_offset; + grid->font_bbx.height = metrics->height; + grid->font_bbx.ascent = metrics->ascent; + grid->font_bbx.descent = metrics->descent; + grid->font_bbx.y_offset = metrics->y_offset; + } else { + /* + * The grid does not need to resized, but the baseline must + * be recalculated and the bitmap copied again. + */ + bytes = grid->bytes >> 1; + bitmap = grid->bitmap + bytes; + (void) memset((char *) bitmap, 0, bytes); + + ht = metrics->height; + as = metrics->ascent; + ds = metrics->descent; + + gwd = grid->grid_width; + ght = grid->grid_height; + + /* + * Determine the new baseline. + */ + if (ht >= as + ds) + grid->base_y = (((ght >> 1) - (ht >> 1)) + ht) - ds; + else + grid->base_y = ((ght >> 1) - ((as + ds) >> 1)) + as; + + grid->base_x = (gwd >> 1) - (metrics->width >> 1); + if (metrics->x_offset < 0) + grid->base_x += MYABS(metrics->x_offset); + + nx = grid->base_x + grid->glyph_bbx.x_offset; + ny = grid->base_y - grid->glyph_bbx.ascent; + + wd = grid->glyph_x + grid->glyph_bbx.width; + ht = grid->glyph_y + grid->glyph_bbx.height; + + obpr = nbpr = ((grid->grid_width * grid->bpp) + 7) >> 3; + for (y = grid->glyph_y; y < ht; y++, ny++) { + col = grid->glyph_x * grid->bpp; + colx = nx * grid->bpp; + for (x = grid->glyph_x; x < wd; + x++, col += grid->bpp, colx += grid->bpp) { + si = (col & 7) / grid->bpp; + byte = grid->bitmap[(y * obpr) + (col >> 3)] & masks[si]; + if (byte) { + di = (colx & 7) / grid->bpp; + if (di < si) + byte <<= (si - di) * grid->bpp; + else if (di > si) + byte >>= (di - si) * grid->bpp; + bitmap[(ny * nbpr) + (colx >> 3)] |= byte; + } + } + } + + /* + * Copy the adjusted bitmap back into the main area. + */ + (void) memcpy((char *) grid->bitmap, (char *) bitmap, bytes); + + /* + * Adjust the glyph coordinates. + */ + grid->glyph_x = grid->base_x + grid->glyph_bbx.x_offset; + grid->glyph_y = grid->base_y - grid->glyph_bbx.ascent; + + /* + * Copy the metrics info into the font bounding box. + */ + grid->font_bbx.width = metrics->width; + grid->font_bbx.x_offset = metrics->x_offset; + grid->font_bbx.height = metrics->height; + grid->font_bbx.ascent = metrics->ascent; + grid->font_bbx.descent = metrics->descent; + grid->font_bbx.y_offset = metrics->y_offset; + } + + /* + * If the font is not proportional, make sure the device width is adjusted + * to meet the new font bounding box. + */ + if (changed && grid->spacing != BDF_PROPORTIONAL) + grid->dwidth = grid->font_bbx.width; + + /* + * Always mark the grid as being modified on a resize. + */ + grid->modified = 1; + + return changed; +} + +int +#ifdef __STDC__ +bdf_grid_crop(bdf_glyph_grid_t *grid, int grid_modified) +#else +bdf_grid_crop(grid, grid_modified) +bdf_glyph_grid_t *grid; +int grid_modified; +#endif +{ + int cropped; + short x, y, delta, maxx, minx, maxy, miny, col; + unsigned short bpr; + unsigned char *masks; + + cropped = 0; + if (grid == 0) + return cropped; + + masks = 0; + switch (grid->bpp) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + bpr = ((grid->grid_width * grid->bpp) + 7) >> 3; + + maxx = maxy = -1; + minx = miny = grid->grid_width; + for (y = 0; y < grid->grid_height; y++) { + for (col = x = 0; x < grid->grid_width; x++, col += grid->bpp) { + if (grid->bitmap[(y * bpr) + (col >> 3)] & + masks[(col & 7) / grid->bpp]) { + minx = MIN(minx, x); + maxx = MAX(maxx, x); + miny = MIN(miny, y); + maxy = MAX(maxy, y); + } + } + } + + /* + * Handle an empty bitmap as a special case. + */ + if (maxx == -1) { + /* + * If the glyph bounding box indicated something was there originally, + * then indicate that it was cropped. + */ + if (grid->glyph_bbx.width != 0 || grid->glyph_bbx.height != 0) + cropped = 1; + (void) memset((char *) &grid->glyph_bbx, 0, sizeof(bdf_bbx_t)); + grid->glyph_x = grid->base_x; + grid->glyph_y = grid->base_y; + if (cropped) + grid->modified = 1; + return cropped; + } + + /* + * Increment the max points so width and height calculations won't go + * wrong. + */ + maxx++; + maxy++; + + if (minx != grid->glyph_x) { + cropped = 1; + delta = minx - grid->glyph_x; + grid->glyph_x += delta; + grid->glyph_bbx.x_offset += delta; + } + if (maxx - minx != grid->glyph_bbx.width) { + cropped = 1; + delta = (maxx - minx) - grid->glyph_bbx.width; + grid->glyph_bbx.width += delta; + if (grid->spacing == BDF_PROPORTIONAL) + grid->dwidth += delta; + } + + if (miny != grid->glyph_y) { + cropped = 1; + delta = miny - grid->glyph_y; + grid->glyph_y += delta; + grid->glyph_bbx.y_offset = + grid->base_y - (grid->glyph_y + (maxy - miny)); + } + if (maxy - miny != grid->glyph_bbx.height) { + cropped = 1; + delta = (maxy - miny) - grid->glyph_bbx.height; + grid->glyph_bbx.height += delta; + grid->glyph_bbx.y_offset = + grid->base_y - (grid->glyph_y + (maxy - miny)); + grid->glyph_bbx.ascent = + grid->glyph_bbx.height + grid->glyph_bbx.y_offset; + grid->glyph_bbx.descent = -grid->glyph_bbx.y_offset; + } + + /* + * Indicate that the grid was modified if the glyph had to be cropped. + */ + if (cropped && grid_modified) + grid->modified = 1; + + return cropped; +} + +/************************************************************************** + * + * Glyph grid pixel functions. + * + **************************************************************************/ + +int +#ifdef __STDC__ +bdf_grid_set_pixel(bdf_glyph_grid_t *grid, short x, short y, int val) +#else +bdf_grid_set_pixel(grid, x, y, val) +bdf_glyph_grid_t *grid; +short x, y; +int val; +#endif +{ + unsigned short si, di, dx; + int set, bpr, delta; + unsigned char *masks; + + set = 0; + + if (grid == 0 || x < 0 || x >= grid->grid_width || + y < 0 || y >= grid->grid_height) + return set; + + si = 0; + masks = 0; + switch (grid->bpp) { + case 1: + masks = onebpp; + si = 7; + break; + case 2: + masks = twobpp; + si = 3; + break; + case 4: + masks = fourbpp; + si = 1; + break; + } + + /* + * Remove any unused bits from the value. + */ + val &= masks[si]; + + dx = x * grid->bpp; + di = (dx & 7) / grid->bpp; + + /* + * Shift up the value to the appropriate place if necessary. + */ + if (di < si) + val <<= (si - di) * grid->bpp; + + /* + * Determine the bytes-per-row. + */ + bpr = ((grid->grid_width * grid->bpp) + 7) >> 3; + + /* + * If the bit is already set, simply return with an indication that + * nothing changed. + */ + if ((grid->bitmap[(y * bpr) + (dx >> 3)] & masks[di]) == val) + return set; + + /* + * Set the bit. + */ + set = 1; + + /* + * Clear the bits that will take the new value. + */ + grid->bitmap[(y * bpr) + (dx >> 3)] &= ~masks[di]; + grid->bitmap[(y * bpr) + (dx >> 3)] |= val; + + /* + * Adjust the glyph bounding box. + */ + if (x < grid->glyph_x) { + delta = grid->glyph_x - x; + grid->glyph_bbx.width += delta; + grid->glyph_bbx.x_offset -= delta; + if (grid->spacing == BDF_PROPORTIONAL) + grid->dwidth = grid->glyph_bbx.width + grid->glyph_bbx.x_offset; + grid->glyph_x -= delta; + } else if (x >= grid->glyph_x + grid->glyph_bbx.width) { + delta = x - (grid->glyph_x + grid->glyph_bbx.width) + 1; + grid->glyph_bbx.width += delta; + if (grid->spacing == BDF_PROPORTIONAL) + grid->dwidth = grid->glyph_bbx.width + grid->glyph_bbx.x_offset; + } + if (y < grid->glyph_y) { + delta = grid->glyph_y - y; + grid->glyph_bbx.ascent += delta; + grid->glyph_bbx.height += delta; + grid->glyph_y -= delta; + } else if (y >= grid->glyph_y + grid->glyph_bbx.height) { + delta = y - (grid->glyph_y + grid->glyph_bbx.height) + 1; + grid->glyph_bbx.descent += delta; + grid->glyph_bbx.height += delta; + grid->glyph_bbx.y_offset = -grid->glyph_bbx.descent; + } + + /* + * Indicate that the glyph was modified. + */ + grid->modified = 1; + + return set; +} + +int +#ifdef __STDC__ +bdf_grid_clear_pixel(bdf_glyph_grid_t *grid, short x, short y) +#else +bdf_grid_clear_pixel(grid, x, y) +bdf_glyph_grid_t *grid; +short x, y; +#endif +{ + int cleared, bpr; + short delta, maxx, minx, maxy, miny, wd, ht; + unsigned short di, dx; + unsigned char *masks; + + cleared = 0; + + if (grid == 0 || x < 0 || x >= grid->grid_width || + y < 0 || y >= grid->grid_height) + return cleared; + + masks = 0; + switch (grid->bpp) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + /* + * Determine the bytes-per-row. + */ + bpr = ((grid->grid_width * grid->bpp) + 7) >> 3; + + dx = x * grid->bpp; + di = (dx & 7) / grid->bpp; + + /* + * If the bit is already clear, simply return with an indication that + * nothing changed. + */ + if (!(grid->bitmap[(y * bpr) + (dx >> 3)] & masks[di])) + return cleared; + + /* + * Clear the bit. + */ + cleared = 1; + grid->bitmap[(y * bpr) + (dx >> 3)] &= ~masks[di]; + + /* + * Determine the new min and max values. + */ + maxx = maxy = 0; + minx = miny = 32767; + + wd = grid->glyph_x + grid->glyph_bbx.width; + ht = grid->glyph_y + grid->glyph_bbx.height; + + for (y = grid->glyph_y; y < ht; y++) { + dx = grid->glyph_x * grid->bpp; + for (x = grid->glyph_x; x < wd; x++, dx += grid->bpp) { + di = (dx & 7) / grid->bpp; + if (grid->bitmap[(y * bpr) + (dx >> 3)] & masks[di]) { + minx = MIN(minx, x); + maxx = MAX(maxx, x); + miny = MIN(miny, y); + maxy = MAX(maxy, y); + } + } + } + + /* + * If this call clears the last bit in the image, set the glyph origin + * to the base and return. + */ + if (maxx == 0) { + grid->glyph_x = grid->base_x; + grid->glyph_y = grid->base_y; + if (grid->spacing == BDF_PROPORTIONAL) + grid->dwidth = 0; + (void) memset((char *) &grid->glyph_bbx, 0, sizeof(grid->glyph_bbx)); + grid->modified = 1; + return cleared; + } + + /* + * Figure out the left and right bearing changes. + */ + if (minx > grid->glyph_x) { + delta = minx - grid->glyph_x; + grid->glyph_bbx.width -= delta; + grid->glyph_bbx.x_offset += delta; + if (grid->spacing == BDF_PROPORTIONAL) + grid->dwidth = grid->glyph_bbx.width + grid->glyph_bbx.x_offset; + grid->glyph_x += delta; + } else if (maxx < wd - 1) { + delta = (wd - 1) - maxx; + grid->glyph_bbx.width -= delta; + if (grid->spacing == BDF_PROPORTIONAL) + grid->dwidth = grid->glyph_bbx.width + grid->glyph_bbx.x_offset; + } + + if (miny > grid->glyph_y) { + delta = miny - grid->glyph_y; + grid->glyph_bbx.ascent -= delta; + grid->glyph_bbx.height -= delta; + grid->glyph_y += delta; + } else if (maxy < ht - 1) { + delta = (ht - 1) - maxy; + grid->glyph_bbx.descent -= delta; + grid->glyph_bbx.height -= delta; + grid->glyph_bbx.y_offset = -grid->glyph_bbx.descent; + } + + /* + * Indicate that the glyph was modified. + */ + grid->modified = 1; + + return cleared; +} + +int +#ifdef __STDC__ +bdf_grid_invert_pixel(bdf_glyph_grid_t *grid, short x, short y, int val) +#else +bdf_grid_invert_pixel(grid, x, y, val) +bdf_glyph_grid_t *grid; +short x, y; +int val; +#endif +{ + short bpr, di; + unsigned char *masks; + + if (grid == 0 || x < 0 || x >= grid->grid_width || + y < 0 || y >= grid->grid_height) + return 0; + + masks = 0; + switch (grid->bpp) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + /* + * Determine the bytes-per-row and mask index. + */ + bpr = ((grid->grid_width * grid->bpp) + 7) >> 3; + di = ((x * grid->bpp) & 7) / grid->bpp; + + /* + * If the bit is set, then clear it, otherwise, set it. + */ + if (grid->bitmap[(y * bpr) + ((x * grid->bpp) >> 3)] & masks[di]) + return bdf_grid_clear_pixel(grid, x, y); + else + return bdf_grid_set_pixel(grid, x, y, val); +} + +/************************************************************************** + * + * Glyph grid bitmap transformation functions. + * + **************************************************************************/ + +short +#ifdef __STDC__ +_bdf_ceiling(double v) +#else +_bdf_ceiling(v) +double v; +#endif +{ + short val, neg; + + val = neg = 0; + if (v < 0) { + neg = 1; + while (v < -1.0) { + val++; + v += 1.0; + } + } else if (v > 0) { + while (v > 1.0) { + val++; + v -= 1.0; + } + if (v > 0.0) + val++; + } + return (!neg) ? val : -val; +} + +static int +#ifdef __STDC__ +_bdf_rotate_selection(bdf_glyph_grid_t *grid, int mul90, short degrees) +#else +_bdf_rotate_selection(grid, mul90, degrees) +bdf_glyph_grid_t *grid; +int mul90; +short degrees; +#endif +{ + int rotated, byte; + short wd, ht, nx, ny, cx, cy, x, y, col; + short ox, oy, shiftx, shifty, si, di; + double dx, dy; + unsigned short bytes, bpr; + unsigned char *scratch, *masks; + + rotated = 0; + + /* + * Check to see if the number of rotations would have no affect by + * checking if the count is a multiple of 4 (mod 4 == 0). + */ + if (grid == 0 || degrees == 0) + return rotated; + + masks = 0; + switch (grid->bpp) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + bytes = grid->sel.bytes >> 1; + scratch = grid->sel.bitmap + bytes; + (void) memset((char *) scratch, 0, bytes); + + cx = grid->sel.width >> 1; + cy = grid->sel.height >> 1; + + wd = ht = MAX(grid->sel.width, grid->sel.height); + cx = cy = wd >> 1; + + bpr = ((wd * grid->bpp) + 7) >> 3; + + for (shiftx = shifty = y = 0; y < ht; y++) { + for (col = x = 0; x < wd; x++, col += grid->bpp) { + dx = (double)(x - cx); + dy = (double)(y - cy); + if (mul90) { + nx = cx + (short)((dx * _bdf_cos_tbl[degrees]) - + (dy * _bdf_sin_tbl[degrees])); + ny = cy + (short)((dx * _bdf_sin_tbl[degrees]) + + (dy * _bdf_cos_tbl[degrees])); + } else { + nx = cx + _bdf_ceiling((dx * _bdf_cos_tbl[degrees]) - + (dy * _bdf_sin_tbl[degrees])); + ny = cy + _bdf_ceiling((dx * _bdf_sin_tbl[degrees]) + + (dy * _bdf_cos_tbl[degrees])); + } + + /* + * Wrap the coordinates around the edges if necessary. + */ + if (nx < 0) { + shiftx = MIN(shiftx, nx); + nx += wd; + } else if (nx >= wd) { + ox = (nx - wd) + 1; + shiftx = MAX(shiftx, ox); + nx -= wd; + } + if (ny < 0) { + shifty = MIN(shifty, ny); + ny += ht; + } else if (ny >= ht) { + oy = (ny - ht) + 1; + shifty = MAX(shifty, oy); + ny -= ht; + } + + si = (col & 7) / grid->bpp; + byte = grid->sel.bitmap[(y * bpr) + (col >> 3)] & masks[si]; + if (byte) { + rotated = 1; + nx *= grid->bpp; + di = (nx & 7) / grid->bpp; + if (di < si) + byte <<= (si - di) * grid->bpp; + else if (di > si) + byte >>= (di - si) * grid->bpp; + scratch[(ny * bpr) + (nx >> 3)] |= byte; + } + } + } + + if (rotated) { + /* + * If a shift is required, then shift the scratch area back into + * the main bitmap. + */ + if (shiftx || shifty) { + (void) memset((char *) grid->sel.bitmap, 0, bytes); + for (y = 0; y < ht; y++) { + for (col = x = 0; x < wd; x++, col += grid->bpp) { + si = (col & 7) / grid->bpp; + byte = scratch[(y * bpr) + (col >> 3)] & masks[si]; + if (byte) { + nx = x - shiftx; + ny = y - shifty; + + if (nx < 0) + nx += wd; + else if (nx >= wd) + nx -= wd; + if (ny < 0) + ny += ht; + else if (ny >= ht) + ny -= ht; + + nx *= grid->bpp; + di = (nx & 7) / grid->bpp; + if (di < si) + byte <<= (si - di) * grid->bpp; + else if (di > si) + byte >>= (di - si) * grid->bpp; + grid->sel.bitmap[(ny * bpr) + (nx >> 3)] |= byte; + } + } + } + } else + /* + * Copy the scratch buffer back to the main buffer. + */ + (void) memcpy((char *) grid->sel.bitmap, (char *) scratch, bytes); + + /* + * Determine the new selection width and height. + */ + ox = oy = 0; + nx = ny = 16384; + for (y = 0; y < ht; y++) { + for (col = x = 0; x < wd; x++, col += grid->bpp) { + si = (col & 7) / grid->bpp; + if (grid->sel.bitmap[(y * bpr) + (col >> 3)] & masks[si]) { + ox = MAX(ox, x); + nx = MIN(nx, x); + oy = MAX(oy, y); + ny = MIN(ny, y); + } + } + } + + /* + * Recalculate the center corrdinates so the selection will be + * positioned nicely once it is shifted to the upper left corner. + */ + cx = grid->sel.width >> 1; + cy = grid->sel.height >> 1; + + /* + * Set the new width and height. + */ + grid->sel.width = (ox - nx) + 1; + grid->sel.height = (oy - ny) + 1; + + /* + * Shift again to force the selection to the upper left corner. + */ + if (nx || ny) { + (void) memset((char *) scratch, 0, bytes); + for (y = 0; y < ht; y++) { + for (col = x = 0; x < wd; x++, col += grid->bpp) { + si = (col & 7) / grid->bpp; + byte = grid->sel.bitmap[(y * bpr) + (col >> 3)] & + masks[si]; + if (byte) { + oy = y - ny; + ox = (x - nx) * grid->bpp; + di = (ox & 7) / grid->bpp; + if (di < si) + byte <<= (si - di) * grid->bpp; + else if (di > si) + byte >>= (di - si) * grid->bpp; + scratch[(oy * bpr) + (ox >> 3)] |= byte; + } + } + } + (void) memcpy((char *) grid->sel.bitmap, (char *) scratch, bytes); + } + + /* + * Determine the new top left coordinates from the center coordinates. + */ + grid->sel.x = (grid->sel.x + cx) - (grid->sel.width >> 1); + grid->sel.y = (grid->sel.y + cy) - (grid->sel.height >> 1); + + /* + * If the rotation caused the selection rectangle to overlap the edges + * of the grid, shift it so it is completely visible again. + */ + if (grid->sel.x + grid->sel.width > grid->grid_width) + grid->sel.x -= (grid->sel.x + grid->sel.width) - grid->grid_width; + if (grid->sel.y + grid->sel.height > grid->grid_height) + grid->sel.y -= (grid->sel.y + grid->sel.height) - grid->grid_height; + + /* + * Mark the grid as being modified. + */ + grid->modified = 1; + } + + return rotated; +} + +static void +#ifdef __STDC__ +_bdf_rotate_resize(bdf_glyph_grid_t *grid, int mul90, short degrees, + int *resize) +#else +_bdf_rotate_resize(grid, mul90, degrees, resize) +bdf_glyph_grid_t *grid; +int mul90; +short degrees; +int *resize; +#endif +{ + unsigned short wd, ht; + short cx, cy, x1, y1, x2, y2; + double dx1, dy1, dx2, dy2; + bdf_metrics_t metrics; + + *resize = 0; + (void) memset((char *) &metrics, 0, sizeof(bdf_metrics_t)); + + metrics.x_offset = grid->font_bbx.x_offset; + metrics.width = grid->font_bbx.width; + metrics.ascent = grid->font_bbx.ascent; + metrics.descent = grid->font_bbx.descent; + metrics.height = grid->font_bbx.height; + metrics.y_offset = grid->font_bbx.y_offset; + + cx = grid->glyph_x + (grid->glyph_bbx.width >> 1); + cy = grid->glyph_y + (grid->glyph_bbx.height >> 1); + + /* + * Rotate the lower left and upper right corners and check for a potential + * resize. + */ + x1 = grid->glyph_x; + y1 = grid->glyph_y + grid->glyph_bbx.height; + x2 = grid->glyph_x + grid->glyph_bbx.width; + y2 = grid->glyph_y; + + dx1 = (double)(x1 - cx); + dy1 = (double)(y1 - cy); + dx2 = (double)(x2 - cx); + dy2 = (double)(y2 - cx); + + if (mul90) { + x1 = cx + (short)((dx1 * _bdf_cos_tbl[degrees]) - + (dy1 * _bdf_sin_tbl[degrees])); + y1 = cy + (short)((dx1 * _bdf_sin_tbl[degrees]) + + (dy1 * _bdf_cos_tbl[degrees])); + x2 = cx + (short)((dx2 * _bdf_cos_tbl[degrees]) - + (dy2 * _bdf_sin_tbl[degrees])); + y2 = cy + (short)((dx2 * _bdf_sin_tbl[degrees]) + + (dy2 * _bdf_cos_tbl[degrees])); + } else { + x1 = cx + _bdf_ceiling((dx1 * _bdf_cos_tbl[degrees]) - + (dy1 * _bdf_sin_tbl[degrees])); + y1 = cy + _bdf_ceiling((dx1 * _bdf_sin_tbl[degrees]) + + (dy1 * _bdf_cos_tbl[degrees])); + x2 = cx + _bdf_ceiling((dx2 * _bdf_cos_tbl[degrees]) - + (dy2 * _bdf_sin_tbl[degrees])); + y2 = cy + _bdf_ceiling((dx2 * _bdf_sin_tbl[degrees]) + + (dy2 * _bdf_cos_tbl[degrees])); + } + + wd = MYABS(x2 - x1); + ht = MYABS(y2 - y1); + if (wd > metrics.width) { + metrics.width += wd - grid->font_bbx.width; + *resize = 1; + } + if (ht > metrics.height) { + metrics.ascent += ht - grid->font_bbx.height; + metrics.height += ht - grid->font_bbx.height; + *resize = 1; + } + + /* + * Rotate the upper left and lower right corners and check for a potential + * resize. + */ + x1 = grid->glyph_x; + y1 = grid->glyph_y; + x2 = grid->glyph_x + grid->glyph_bbx.width; + y2 = grid->glyph_y + grid->glyph_bbx.height; + + dx1 = (double)(x1 - cx); + dy1 = (double)(y1 - cy); + dx2 = (double)(x2 - cx); + dy2 = (double)(y2 - cx); + + if (mul90) { + x1 = cx + (short)((dx1 * _bdf_cos_tbl[degrees]) - + (dy1 * _bdf_sin_tbl[degrees])); + y1 = cy + (short)((dx1 * _bdf_sin_tbl[degrees]) + + (dy1 * _bdf_cos_tbl[degrees])); + x2 = cx + (short)((dx2 * _bdf_cos_tbl[degrees]) - + (dy2 * _bdf_sin_tbl[degrees])); + y2 = cy + (short)((dx2 * _bdf_sin_tbl[degrees]) + + (dy2 * _bdf_cos_tbl[degrees])); + } else { + x1 = cx + _bdf_ceiling((dx1 * _bdf_cos_tbl[degrees]) - + (dy1 * _bdf_sin_tbl[degrees])); + y1 = cy + _bdf_ceiling((dx1 * _bdf_sin_tbl[degrees]) + + (dy1 * _bdf_cos_tbl[degrees])); + x2 = cx + _bdf_ceiling((dx2 * _bdf_cos_tbl[degrees]) - + (dy2 * _bdf_sin_tbl[degrees])); + y2 = cy + _bdf_ceiling((dx2 * _bdf_sin_tbl[degrees]) + + (dy2 * _bdf_cos_tbl[degrees])); + } + + wd = MYABS(x2 - x1); + ht = MYABS(y2 - y1); + if (wd > metrics.width) { + metrics.width += wd - grid->font_bbx.width; + *resize = 1; + } + if (ht > metrics.height) { + metrics.ascent += ht - grid->font_bbx.height; + metrics.height += ht - grid->font_bbx.height; + *resize = 1; + } + + if (*resize) + (void) bdf_grid_resize(grid, &metrics); +} + +static void +#ifdef __STDC__ +_bdf_shear_resize(bdf_glyph_grid_t *grid, short degrees, int neg, int *resize) +#else +_bdf_shear_resize(grid, degrees, neg, resize) +bdf_glyph_grid_t *grid; +short degrees; +int neg, *resize; +#endif +{ + unsigned short wd; + short x1, y1, x2, y2; + bdf_metrics_t metrics; + + *resize = 0; + (void) memset((char *) &metrics, 0, sizeof(bdf_metrics_t)); + + metrics.x_offset = grid->font_bbx.x_offset; + metrics.width = grid->font_bbx.width; + metrics.ascent = grid->font_bbx.ascent; + metrics.descent = grid->font_bbx.descent; + metrics.height = grid->font_bbx.height; + metrics.y_offset = grid->font_bbx.y_offset; + + /* + * Shear the lower left and upper right corners and check for a potential + * resize. + */ + x1 = 0; + y1 = grid->glyph_bbx.height; + x2 = grid->glyph_bbx.width; + y2 = 0; + + if (neg) { + x1 += (short)((double) y1 * _bdf_tan_tbl[degrees]); + x2 += (short)((double) y2 * _bdf_tan_tbl[degrees]); + } else { + x1 += (short)((double)(grid->glyph_bbx.height - y1) * + _bdf_tan_tbl[degrees]); + x2 += (short)((double)(grid->glyph_bbx.height - y2) * + _bdf_tan_tbl[degrees]); + } + + wd = MYABS(x2 - x1); + if (wd > metrics.width) { + metrics.width += wd - grid->font_bbx.width; + *resize = 1; + } + + /* + * Shear the upper left and lower right corners and check for a potential + * resize. + */ + x1 = 0; + y1 = 0; + x2 = grid->glyph_bbx.width; + y2 = grid->glyph_bbx.height; + + if (neg) { + x1 += (short)((double) y1 * _bdf_tan_tbl[degrees]); + x2 += (short)((double) y2 * _bdf_tan_tbl[degrees]); + } else { + x1 += (short)((double)(grid->glyph_bbx.height - y1) * + _bdf_tan_tbl[degrees]); + x2 += (short)((double)(grid->glyph_bbx.height - y2) * + _bdf_tan_tbl[degrees]); + } + + wd = MYABS(x2 - x1); + if (wd > metrics.width) { + metrics.width += wd - grid->font_bbx.width; + *resize = 1; + } + + if (*resize) + (void) bdf_grid_resize(grid, &metrics); +} + +/* + * Rotate the bitmap in the grid by some number of degrees. + */ +int +#ifdef __STDC__ +bdf_grid_rotate(bdf_glyph_grid_t *grid, short degrees, int *resize) +#else +bdf_grid_rotate(grid, degrees, resize) +bdf_glyph_grid_t *grid; +short degrees; +int *resize; +#endif +{ + int rotated, mul90; + short nx, ny, cx, cy, x, y, wd, ht; + short ox, oy, gx, gy, shiftx, shifty; + unsigned short si, di, col, byte; + double dx, dy; + unsigned short bytes, bpr; + unsigned char *scratch, *masks; + + rotated = 0; + + /* + * Make sure the number of degrees is between 0 and 359 and adjusted to a + * positive number of degrees if necessary. + */ + while (degrees < 0) + degrees += 360; + while (degrees >= 360) + degrees -= 360; + + if (grid == 0 || degrees == 0 || + (grid->glyph_bbx.width == 0 && grid->glyph_bbx.height == 0)) + return rotated; + + masks = 0; + switch (grid->bpp) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + mul90 = ((degrees % 90) == 0) ? 1 : 0; + + /* + * Force the grid to resize if the rotation requires it. + */ + _bdf_rotate_resize(grid, mul90, degrees, resize); + + if (grid->sel.width != 0 && grid->sel.height != 0) + return _bdf_rotate_selection(grid, mul90, degrees); + + /* + * Halve the byte count in the grid for later use. + */ + bytes = grid->bytes >> 1; + + /* + * Point at the scratch buffer area and initialize it. + */ + scratch = grid->bitmap + bytes; + (void) memset((char *) scratch, 0, bytes); + + /* + * Determine the bytes per row. + */ + bpr = ((grid->grid_width * grid->bpp) + 7) >> 3; + + /* + * Determine the center coordinates of the glyph bitmap rectangle. + */ + cx = grid->glyph_x + (grid->glyph_bbx.width >> 1); + cy = grid->glyph_y + (grid->glyph_bbx.height >> 1); + + /* + * Only run over the rectangle containing the glyph itself. + */ + gx = grid->glyph_x; + gy = grid->glyph_y; + + wd = gx + grid->glyph_bbx.width; + ht = gy + grid->glyph_bbx.height; + + /* + * Initialize the adjustment counts used if the bitmap + * wraps around the edge. + */ + shiftx = shifty = 0; + + for (y = gy; y < ht; y++) { + col = gx * grid->bpp; + for (x = gx; x < wd; x++, col += grid->bpp) { + + /* + * Rotate the point. + */ + dx = (double)(x - cx); + dy = (double)(y - cy); + if (mul90) { + nx = cx + (short)((dx * _bdf_cos_tbl[degrees]) - + (dy * _bdf_sin_tbl[degrees])); + ny = cy + (short)((dx * _bdf_sin_tbl[degrees]) + + (dy * _bdf_cos_tbl[degrees])); + } else { + nx = cx + _bdf_ceiling((dx * _bdf_cos_tbl[degrees]) - + (dy * _bdf_sin_tbl[degrees])); + ny = cy + _bdf_ceiling((dx * _bdf_sin_tbl[degrees]) + + (dy * _bdf_cos_tbl[degrees])); + } + + /* + * Wrap the coordinates around the edges if necessary. + */ + if (nx < 0) { + shiftx = MIN(shiftx, nx); + nx += grid->grid_width; + } else if (nx >= grid->grid_width) { + ox = (nx - grid->grid_width) + 1; + shiftx = MAX(shiftx, ox); + nx -= grid->grid_width; + } + if (ny < 0) { + shifty = MIN(shifty, ny); + ny += grid->grid_height; + } else if (ny >= grid->grid_height) { + oy = (ny - grid->grid_height) + 1; + shifty = MAX(shifty, oy); + ny -= grid->grid_height; + } + + si = (col & 7) / grid->bpp; + byte = grid->bitmap[(y * bpr) + (col >> 3)] & masks[si]; + if (byte) { + rotated = 1; + nx *= grid->bpp; + di = (nx & 7) / grid->bpp; + if (di < si) + byte <<= (si - di) * grid->bpp; + else if (di > si) + byte >>= (di - si) * grid->bpp; + scratch[(ny * bpr) + (nx >> 3)] |= byte; + } + } + } + + if (rotated) { + /* + * If a shift is required, then shift the scratch area back into + * the main bitmap. + */ + if (shiftx || shifty) { + (void) memset((char *) grid->bitmap, 0, bytes); + for (y = 0; y < grid->grid_height; y++) { + for (col = x = 0; x < grid->grid_width; + x++, col += grid->bpp) { + si = (col & 7) / grid->bpp; + byte = scratch[(y * bpr) + (col >> 3)] & masks[si]; + if (byte) { + nx = x - shiftx; + ny = y - shifty; + + if (nx < 0) + nx += grid->grid_width; + else if (nx >= grid->grid_width) + nx -= grid->grid_width; + if (ny < 0) + ny += grid->grid_height; + else if (ny >= grid->grid_height) + ny -= grid->grid_height; + + nx *= grid->bpp; + di = (nx & 7) / grid->bpp; + if (di < si) + byte <<= (si - di) * grid->bpp; + else if (di > si) + byte >>= (di - si) * grid->bpp; + grid->bitmap[(ny * bpr) + (nx >> 3)] |= byte; + } + } + } + } else + /* + * Copy the scratch buffer back to the main buffer. + */ + (void) memcpy((char *) grid->bitmap, (char *) scratch, bytes); + + /* + * Determine the new glyph bounding box and the top left coordinates. + */ + ox = oy = 0; + nx = ny = 16384; + for (y = 0; y < grid->grid_height; y++) { + for (col = x = 0; x < grid->grid_width; x++, col += grid->bpp) { + si = (col & 7) / grid->bpp; + if (grid->bitmap[(y * bpr) + (col >> 3)] & masks[si]) { + nx = MIN(nx, x); + ox = MAX(ox, x); + ny = MIN(ny, y); + oy = MAX(oy, y); + } + } + } + + /* + * Set the new top left corrdinates. + */ + grid->glyph_x = nx; + grid->glyph_y = ny; + + /* + * Set the new glyph bounding box. + */ + grid->glyph_bbx.width = (ox - nx) + 1; + grid->glyph_bbx.x_offset = nx - grid->base_x; + grid->glyph_bbx.height = (oy - ny) + 1; + grid->glyph_bbx.ascent = grid->base_y - ny; + grid->glyph_bbx.descent = grid->glyph_bbx.height - + grid->glyph_bbx.ascent; + grid->glyph_bbx.y_offset = -grid->glyph_bbx.descent; + + /* + * Mark the grid as being modified. + */ + grid->modified = 1; + } + + return rotated; +} + +int +#ifdef __STDC__ +bdf_grid_shear(bdf_glyph_grid_t *grid, short degrees, int *resize) +#else +bdf_grid_shear(grid, degrees, resize) +bdf_glyph_grid_t *grid; +short degrees; +int *resize; +#endif +{ + int sheared, neg; + short cx, cy, wd, ht, gx, gy, x, y; + short nx, ox, ny, oy, shiftx, shifty; + unsigned short bytes, bpr, si, di, col, byte; + unsigned char *scratch, *masks; + + sheared = 0; + + if (degrees == 0 || degrees < -45 || degrees > 45 || grid == 0 || + (grid->glyph_bbx.width == 0 && grid->glyph_bbx.height == 0)) + return sheared; + + if ((neg = (degrees < 0))) + degrees = -degrees; + + /* + * Check to see if the grid needs to be resized to hold the sheared glyph. + */ + _bdf_shear_resize(grid, degrees, neg, resize); + + masks = 0; + switch (grid->bpp) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + /* + * Halve the byte count in the grid for later use. + */ + bytes = grid->bytes >> 1; + + /* + * Point at the scratch buffer area and initialize it. + */ + scratch = grid->bitmap + bytes; + (void) memset((char *) scratch, 0, bytes); + + /* + * Determine the bytes per row. + */ + bpr = ((grid->grid_width * grid->bpp) + 7) >> 3; + + /* + * Determine the center coordinates of the glyph bitmap rectangle. + */ + gx = grid->glyph_x; + gy = grid->glyph_y; + + cx = gx + (grid->glyph_bbx.width >> 1); + cy = gy + (grid->glyph_bbx.height >> 1); + + wd = gx + grid->glyph_bbx.width; + ht = gy + grid->glyph_bbx.height; + + shiftx = shifty = 0; + for (y = gy; y < ht; y++) { + col = gx * grid->bpp; + for (x = gx; x < wd; x++, col += grid->bpp) { + ny = y; + if (neg) + nx = x + (short)((double) y * _bdf_tan_tbl[degrees]); + else + nx = x + (short)((double)(gy + (ht - y)) * + _bdf_tan_tbl[degrees]); + + if (nx < 0) { + shiftx = MIN(shiftx, nx); + nx += grid->grid_width; + } else if (nx >= grid->grid_width) { + ox = (nx - grid->grid_width) + 1; + shiftx = MAX(shiftx, ox); + nx -= grid->grid_width; + } + if (ny < 0) { + shifty = MIN(shifty, ny); + ny += grid->grid_height; + } else if (ny >= grid->grid_height) { + oy = (ny - grid->grid_height) + 1; + shifty = MAX(shifty, oy); + ny -= grid->grid_height; + } + + si = (col & 7) / grid->bpp; + byte = grid->bitmap[(y * bpr) + (col >> 3)] & masks[si]; + if (byte) { + sheared = 1; + nx *= grid->bpp; + di = (nx & 7) / grid->bpp; + if (di < si) + byte <<= (si - di) * grid->bpp; + else if (di > si) + byte >>= (di - si) * grid->bpp; + scratch[(y * bpr) + (nx >> 3)] |= byte; + } + } + } + + if (sheared) { + /* + * If a shift is required, then shift the scratch area back into + * the main bitmap. + */ + if (shiftx || shifty) { + (void) memset((char *) grid->bitmap, 0, bytes); + for (y = 0; y < grid->grid_height; y++) { + for (col = x = 0; x < grid->grid_width; + x++, col += grid->bpp) { + si = (col & 7) / grid->bpp; + byte = scratch[(y * bpr) + (col >> 3)] & masks[si]; + if (byte) { + nx = x - shiftx; + ny = y - shifty; + + if (nx < 0) + nx += grid->grid_width; + else if (nx >= grid->grid_width) + nx -= grid->grid_width; + if (ny < 0) + ny += grid->grid_height; + else if (ny >= grid->grid_height) + ny -= grid->grid_height; + + nx *= grid->bpp; + di = (nx & 7) / grid->bpp; + if (di < si) + byte <<= (si - di) * grid->bpp; + else if (di > si) + byte >>= (di - si) * grid->bpp; + grid->bitmap[(ny * bpr) + (nx >> 3)] |= byte; + } + } + } + } else + /* + * Copy the scratch buffer back to the main buffer. + */ + (void) memcpy((char *) grid->bitmap, (char *) scratch, bytes); + + ox = oy = 0; + nx = ny = 16384; + for (y = 0; y < grid->grid_height; y++) { + for (col = x = 0; x < grid->grid_width; x++, col += grid->bpp) { + si = (col & 7) / grid->bpp; + if (grid->bitmap[(y * bpr) + (col >> 3)] & masks[si]) { + ox = MAX(ox, x); + nx = MIN(nx, x); + oy = MAX(oy, y); + ny = MIN(ny, y); + } + } + } + + /* + * Set the new top left corrdinates. + */ + grid->glyph_x = nx; + grid->glyph_y = ny; + + /* + * Set the new glyph bounding box. + */ + grid->glyph_bbx.width = (ox - nx) + 1; + grid->glyph_bbx.x_offset = nx - grid->base_x; + grid->glyph_bbx.height = (oy - ny) + 1; + grid->glyph_bbx.ascent = grid->base_y - ny; + grid->glyph_bbx.descent = grid->glyph_bbx.height - + grid->glyph_bbx.ascent; + grid->glyph_bbx.y_offset = -grid->glyph_bbx.descent; + + /* + * Mark the grid as being modified. + */ + grid->modified = 1; + } + + return sheared; +} + +int +#ifdef __STDC__ +bdf_grid_embolden(bdf_glyph_grid_t *grid) +#else +bdf_grid_embolden(grid) +bdf_glyph_grid_t *grid; +#endif +{ + int done; + short wd, ht, gx, gy, x, y; + unsigned short b1, b2, bpr, si, di, col; + unsigned char *masks; + + done = 0; + + if (grid == 0 || + (grid->glyph_bbx.width == 0 && grid->glyph_bbx.height == 0)) + return done; + + masks = 0; + switch (grid->bpp) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + /* + * Determine the bytes per row. + */ + bpr = ((grid->grid_width * grid->bpp) + 7) >> 3; + + gx = grid->glyph_x; + gy = grid->glyph_y; + + wd = gx + grid->glyph_bbx.width; + ht = gy + grid->glyph_bbx.height; + + if (grid->spacing == BDF_PROPORTIONAL || + (grid->spacing == BDF_MONOWIDTH && + grid->glyph_bbx.width < grid->font_bbx.width)) + /* + * Only allow horizontal expansion in the cases that make sense. + */ + wd++; + + for (y = gy; y < ht; y++) { + col = (wd - 1) * grid->bpp; + for (x = wd - 1; x > gx; x--, col -= grid->bpp) { + si = (col & 7) / grid->bpp; + di = ((col - grid->bpp) & 7) / grid->bpp; + b1 = grid->bitmap[(y * bpr) + (col >> 3)] & masks[si]; + b2 = grid->bitmap[(y * bpr) + ((col - grid->bpp) >> 3)] & + masks[di]; + if (!b1 && b2) { + if (di < si) + b2 >>= (si - di) * grid->bpp; + else if (di > si) + b2 <<= (di - si) * grid->bpp; + grid->bitmap[(y * bpr) + (col >> 3)] |= b2; + /* + * Mark the grid as being modified. + */ + done = grid->modified = 1; + } + } + } + + /* + * Adjust the glyph width so it will be reflected when the glyph is stored + * back in the font. + */ + grid->glyph_bbx.width = wd - gx; + + return done; +} + +/************************************************************************** + * + * Glyph grid selection functions. + * + **************************************************************************/ + +int +#ifdef __STDC__ +bdf_has_selection(bdf_glyph_grid_t *grid, short *x, short *y, + short *width, short *height) +#else +bdf_has_selection(grid, x, y, width, height) +bdf_glyph_grid_t *grid; +short *x, *y, *width, *height; +#endif +{ + if (grid == 0 || (grid->sel.width == 0 && grid->sel.height == 0)) + return 0; + + if (x != 0) + *x = grid->sel.x; + if (y != 0) + *y = grid->sel.y; + if (width != 0) + *width = grid->sel.width; + if (height != 0) + *height = grid->sel.height; + + return 1; +} + +/* + * Select a rectangle on the grid. + */ +void +#ifdef __STDC__ +bdf_set_selection(bdf_glyph_grid_t *grid, short x, short y, + short width, short height) +#else +bdf_set_selection(grid, x, y, width, height) +bdf_glyph_grid_t *grid; +short x, y, width, height; +#endif +{ + short nx, ny, wd, ht, ssize, dx, dy, col; + unsigned short bytes, bpr, sbpr, si, di, byte; + unsigned char *masks; + + if (grid == 0) + return; + + /* + * Make sure the specified rectangle is within reasonable bounds. + */ + if (x < 0 || x >= grid->grid_width) + x = 0; + if (y < 0 || y >= grid->grid_height) + y = 0; + + if (x + width > grid->grid_width) + width = (x + width) - grid->grid_width; + if (y + height > grid->grid_height) + height = (y + height) - grid->grid_height; + + grid->sel.x = x; + grid->sel.y = y; + grid->sel.width = width; + grid->sel.height = height; + + /* + * Allocate enough space to represent a square the size of the largest + * of the width and height of the selection. This allows rotation and + * flipping of the selected bitmap. + */ + ssize = MAX(width, height); + + bytes = ((((ssize * grid->bpp) + 7) >> 3) * ssize) << 1; + + /* + * If the selection is being removed (width and height are 0), then simply + * return. + */ + if (bytes == 0) + return; + + masks = 0; + switch (grid->bpp) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + if (bytes > grid->sel.bytes) { + if (grid->sel.bytes == 0) + grid->sel.bitmap = (unsigned char *) malloc(bytes); + else + grid->sel.bitmap = (unsigned char *) + realloc((char *) grid->sel.bitmap, bytes); + grid->sel.bytes = bytes; + } else + bytes = grid->sel.bytes; + + /* + * Initialize the selection bitmap and copy the selected bits to it. + */ + (void) memset((char *) grid->sel.bitmap, 0, bytes); + + wd = x + width; + ht = y + height; + + bpr = ((grid->grid_width * grid->bpp) + 7) >> 3; + sbpr = ((grid->sel.width * grid->bpp) + 7) >> 3; + + for (ny = 0, dy = y; dy < ht; dy++, ny++) { + col = x * grid->bpp; + for (nx = 0, dx = x; dx < wd; + dx++, nx += grid->bpp, col += grid->bpp) { + si = (col & 7) / grid->bpp; + byte = grid->bitmap[(dy * bpr) + (col >> 3)] & masks[si]; + if (byte) { + di = (nx & 7) / grid->bpp; + if (di < si) + byte <<= (si - di) * grid->bpp; + else if (di > si) + byte >>= (di - si) * grid->bpp; + grid->sel.bitmap[(ny * sbpr) + (nx >> 3)] |= byte; + } + } + } +} + +/* + * Detach a selection in preparation for moving it. What is does is clear the + * bits set in the selection from the main grid. Again, this is only used for + * move operations. + */ +void +#ifdef __STDC__ +bdf_detach_selection(bdf_glyph_grid_t *grid) +#else +bdf_detach_selection(grid) +bdf_glyph_grid_t *grid; +#endif +{ + short sx, sy, x, y, wd, ht, dx; + unsigned short bpr, sbpr, si, di, byte; + unsigned char *masks; + + if (grid == 0 || (grid->sel.width == 0 && grid->sel.height == 0)) + return; + + masks = 0; + switch (grid->bpp) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + bpr = ((grid->grid_width * grid->bpp) + 7) >> 3; + sbpr = ((grid->sel.width * grid->bpp) + 7) >> 3; + + wd = grid->sel.x + grid->sel.width; + ht = grid->sel.y + grid->sel.height; + + for (sy = 0, y = grid->sel.y; y < ht; y++, sy++) { + for (sx = 0, x = grid->sel.x; x < wd; x++, sx += grid->bpp) { + si = (sx & 7) / grid->bpp; + byte = grid->sel.bitmap[(sy * sbpr) + (sx >> 3)] & masks[si]; + if (byte) { + dx = x * grid->bpp; + di = (dx & 7) / grid->bpp; + grid->bitmap[(y * bpr) + (dx >> 3)] &= ~masks[di]; + } + } + } + + /* + * Crop the new image to determine the new bounds with the selection. + */ + (void) bdf_grid_crop(grid, 1); +} + +void +#ifdef __STDC__ +bdf_attach_selection(bdf_glyph_grid_t *grid) +#else +bdf_attach_selection(grid) +bdf_glyph_grid_t *grid; +#endif +{ + short sx, sy, x, y, wd, ht; + unsigned short bpr, sbpr, dx, di, si, byte; + unsigned char *masks; + + if (grid == 0 || (grid->sel.width == 0 && grid->sel.height == 0)) + return; + + masks = 0; + switch (grid->bpp) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + bpr = ((grid->grid_width * grid->bpp) + 7) >> 3; + sbpr = ((grid->sel.width * grid->bpp) + 7) >> 3; + + wd = grid->sel.x + grid->sel.width; + ht = grid->sel.y + grid->sel.height; + + for (sy = 0, y = grid->sel.y; y < ht; y++, sy++) { + for (sx = 0, x = grid->sel.x; x < wd; x++, sx += grid->bpp) { + si = (sx & 7) / grid->bpp; + byte = grid->sel.bitmap[(sy * sbpr) + (sx >> 3)] & masks[si]; + if (byte) { + dx = x * grid->bpp; + di = (dx & 7) / grid->bpp; + if (di < si) + byte <<= (si - di) * grid->bpp; + else if (di > si) + byte >>= (di - si) * grid->bpp; + grid->bitmap[(y * bpr) + (dx >> 3)] |= byte; + } + } + } + + /* + * Crop the new image to determine the new bounds with the selection. + */ + (void) bdf_grid_crop(grid, 1); +} + +/* + * Indicate the selection no longer exists by setting the width and height to + * 0. + */ +void +#ifdef __STDC__ +bdf_lose_selection(bdf_glyph_grid_t *grid) +#else +bdf_lose_selection(grid) +bdf_glyph_grid_t *grid; +#endif +{ + if (grid == 0) + return; + grid->sel.width = grid->sel.height = 0; +} + +/* + * Delete the selection by first detaching it which will erase the rectangle + * on the grid and then losing the selection. + */ +void +#ifdef __STDC__ +bdf_delete_selection(bdf_glyph_grid_t *grid) +#else +bdf_delete_selection(grid) +bdf_glyph_grid_t *grid; +#endif +{ + bdf_detach_selection(grid); + bdf_lose_selection(grid); +} + +/* + * Check to see if a coordinate pair is in the selected region. + */ +int +#ifdef __STDC__ +bdf_in_selection(bdf_glyph_grid_t *grid, short x, short y, short *set) +#else +bdf_in_selection(grid, x, y, set) +bdf_glyph_grid_t *grid; +short x, y, *set; +#endif +{ + short wd, ht; + unsigned short bpr, si, di, byte; + unsigned char *masks; + + if (grid == 0 || (grid->sel.width == 0 && grid->sel.height == 0)) + return 0; + + di = 0; + masks = 0; + switch (grid->bpp) { + case 1: + masks = onebpp; + di = 7; + break; + case 2: + masks = twobpp; + di = 3; + break; + case 4: + masks = fourbpp; + di = 1; + break; + } + + bpr = ((grid->sel.width * grid->bpp) + 7) >> 3; + + wd = grid->sel.x + grid->sel.width; + ht = grid->sel.y + grid->sel.height; + + if ((x >= grid->sel.x && x < wd) && (y >= grid->sel.y && y < ht)) { + if (set) { + /* + * Adjust the byte back to an index value. + */ + x *= grid->bpp; + si = (x & 7) / grid->bpp; + byte = grid->sel.bitmap[(y * bpr) + (x >> 3)] & masks[si]; + if (di > si) + byte >>= (di - si) * grid->bpp; + *set = byte; + } + return 1; + } + + return 0; +} + +int +#ifdef __STDC__ +bdf_grid_shift(bdf_glyph_grid_t *grid, short xcount, short ycount) +#else +bdf_grid_shift(grid, xcount, ycount) +bdf_glyph_grid_t *grid; +short xcount, ycount; +#endif +{ + int sel, delta; + short xdir, ydir, x, y, wd, ht, dx, dy, nx, ny; + unsigned short bytes, bpr, si, di, byte, col; + unsigned char *scratch, *masks; + + if (grid == 0) + return 0; + + xdir = ydir = 1; + if (xcount < 0) { + xdir = -1; + xcount = -xcount; + } + + if (ycount < 0) { + ydir = -1; + ycount = -ycount; + } + + /* + * Adjust the shift counts if they are larger than they should be. + */ + if (xcount > grid->grid_width) + xcount -= grid->grid_width; + if (ycount > grid->grid_height) + ycount -= grid->grid_height; + + /* + * Adjust the counts to limit the shift to the boundaries of the grid. + */ + if (grid->sel.width != 0 && grid->sel.height != 0) { + /* + * The selection is being shifted. + */ + x = grid->sel.x; + y = grid->sel.y; + wd = grid->sel.width; + ht = grid->sel.height; + sel = 1; + } else { + x = grid->glyph_x; + y = grid->glyph_y; + wd = grid->glyph_bbx.width; + ht = grid->glyph_bbx.height; + sel = 0; + } + + /* + * If the width and height are 0, then simply return, because there + * is nothing to shift. + */ + if (wd == 0 && ht == 0) + return 0; + + if (xdir == 1 && x + wd + xcount > grid->grid_width) + xcount = grid->grid_width - (x + wd); + else if (xdir == -1 && xcount > x) + xcount = x; + + if (ydir == 1 && y + ht + ycount > grid->grid_height) + ycount = grid->grid_height - (y + ht); + else if (ydir == -1 && ycount > y) + ycount = y; + + if (xcount == 0 && ycount == 0) + return 0; + + /* + * If the selection is the one being shifted, adjust the X and Y + * coordinates and adjust the glyph metrics. + */ + if (sel) { + /* + * Determine the actual ink bounds of the selection so the + * glyph metrics can be adjusted if necessary. + */ + if (_bdf_grid_ink_bounds(grid, &x, &y, &wd, &ht)) { + /* + * Have to adjust the glyph metrics. + */ + x += xdir * xcount; + y += ydir * ycount; + if (x < grid->glyph_x) { + delta = grid->glyph_x - x; + grid->glyph_bbx.width += delta; + grid->glyph_bbx.x_offset -= delta; + if (grid->spacing == BDF_PROPORTIONAL) + grid->dwidth += delta; + grid->glyph_x -= delta; + } else if (x >= grid->glyph_x + grid->glyph_bbx.width) { + delta = x - (grid->glyph_x + grid->glyph_bbx.width); + grid->glyph_bbx.width += delta; + if (grid->spacing == BDF_PROPORTIONAL) + grid->dwidth += delta; + } + + if (y < grid->glyph_y) { + delta = grid->glyph_y - y; + grid->glyph_bbx.height += delta; + grid->glyph_bbx.ascent += delta; + grid->glyph_y -= delta; + } else if (y + ht >= grid->glyph_y + grid->glyph_bbx.height) { + delta = (y + ht) - (grid->glyph_y + grid->glyph_bbx.height); + grid->glyph_bbx.height += delta; + grid->glyph_bbx.y_offset -= delta; + grid->glyph_bbx.descent += delta; + } + + grid->modified = 1; + } + + /* + * Adjust the top-left coordinate of the selection rectangle. + */ + grid->sel.x += xdir * xcount; + grid->sel.y += ydir * ycount; + + return 1; + } + + masks = 0; + switch (grid->bpp) { + case 1: + masks = onebpp; + di = 7; + break; + case 2: + masks = twobpp; + di = 3; + break; + case 4: + masks = fourbpp; + di = 1; + break; + } + + /* + * The glyph itself is being shifted. + */ + bpr = ((grid->grid_width * grid->bpp) + 7) >> 3; + bytes = grid->bytes >> 1; + scratch = grid->bitmap + bytes; + (void) memset((char *) scratch, 0, bytes); + + /* + * Shift just the glyph rectangle to keep things fast. + */ + wd += x; + ht += y; + for (dy = y; dy < ht; dy++) { + col = x * grid->bpp; + for (dx = x; dx < wd; dx++, col += grid->bpp) { + si = (col & 7) / grid->bpp; + byte = grid->bitmap[(dy * bpr) + (col >> 3)] & masks[si]; + if (byte) { + nx = dx + (xdir * xcount); + ny = dy + (ydir * ycount); + nx *= grid->bpp; + di = (nx & 7) / grid->bpp; + if (di < si) + byte <<= (si - di) * grid->bpp; + else if (di > si) + byte >>= (di - si) * grid->bpp; + scratch[(ny * bpr) + (nx >> 3)] |= byte; + } + } + } + + /* + * Copy the scratch buffer back to the main buffer. + */ + (void) memcpy((char *) grid->bitmap, (char *) scratch, bytes); + + /* + * Adjust the top-left coordinate of the glyph rectangle. + */ + grid->glyph_x += xdir * xcount; + grid->glyph_y += ydir * ycount; + + /* + * Adjust the glyph offsets relative to the baseline coordinates. + */ + grid->glyph_bbx.x_offset = grid->glyph_x - grid->base_x; + grid->glyph_bbx.y_offset = grid->base_y - + (grid->glyph_y + grid->glyph_bbx.height); + + /* + * Adjust the glyph ascent and descent. + */ + grid->glyph_bbx.ascent = grid->base_y - grid->glyph_y; + grid->glyph_bbx.descent = (grid->glyph_y + grid->glyph_bbx.height) - + grid->base_y; + + /* + * Mark the grid as being modified. + */ + grid->modified = 1; + + return 1; +} + + +int +#ifdef __STDC__ +bdf_grid_flip(bdf_glyph_grid_t *grid, short dir) +#else +bdf_grid_flip(grid, dir) +bdf_glyph_grid_t *grid; +short dir; +#endif +{ + int flipped, sel, delta; + short dx, dy, x, y, nx, ny, wd, ht; + unsigned short bytes, bpr, si, di, col, colx, byte; + unsigned char *bmap, *scratch, *masks; + + flipped = 0; + + if (grid == 0) + return flipped; + + if (grid->sel.width != 0 && grid->sel.height != 0) { + sel = 1; + x = y = 0; + wd = grid->sel.width; + ht = grid->sel.height; + bpr = ((wd * grid->bpp) + 7) >> 3; + bytes = grid->sel.bytes >> 1; + bmap = grid->sel.bitmap; + } else { + sel = 0; + x = grid->glyph_x; + y = grid->glyph_y; + wd = grid->glyph_bbx.width; + ht = grid->glyph_bbx.height; + bpr = ((grid->grid_width * grid->bpp) + 7) >> 3; + bytes = grid->bytes >> 1; + bmap = grid->bitmap; + } + + /* + * If the width or height is 0, don't do anything. + */ + if (wd == 0 || ht == 0) + return flipped; + + nx = 0; + masks = 0; + switch (grid->bpp) { + case 1: + masks = onebpp; + di = 7; + break; + case 2: + masks = twobpp; + di = 3; + break; + case 4: + masks = fourbpp; + di = 1; + break; + } + + /* + * Set and initialize the scratch area. + */ + scratch = bmap + bytes; + (void) memset((char *) scratch, 0, bytes); + + wd += x; + ht += y; + + if (dir < 0) { + /* + * Flip horizontally. + */ + for (dy = y; dy < ht; dy++) { + col = x * grid->bpp; + for (nx = wd - 1, dx = x; dx < wd; dx++, nx--, col += grid->bpp) { + si = (col & 7) / grid->bpp; + byte = bmap[(dy * bpr) + (col >> 3)] & masks[si]; + if (byte) { + flipped = 1; + colx = nx * grid->bpp; + di = (colx & 7) / grid->bpp; + if (di < si) + byte <<= (si - di) * grid->bpp; + else if (di > si) + byte >>= (di - si) * grid->bpp; + scratch[(dy * bpr) + (colx >> 3)] |= byte; + } + } + } + if (flipped) { + if (sel) + grid->sel.x += nx + 1; + else { + grid->glyph_x = nx + 1; + grid->glyph_bbx.x_offset = grid->glyph_x - grid->base_x; + } + } + } else { + /* + * Flip vertically. + */ + for (ny = ht - 1, dy = y; dy < ht; dy++, ny--) { + col = x * grid->bpp; + for (dx = x; dx < wd; dx++, col += grid->bpp) { + si = (col & 7) / grid->bpp; + byte = bmap[(dy * bpr) + (col >> 3)] & masks[si]; + if (byte) { + flipped = 1; + scratch[(ny * bpr) + (col >> 3)] |= byte; + } + } + } + if (flipped) { + if (sel) + grid->sel.y += ny + 1; + else { + grid->glyph_y = ny + 1; + grid->glyph_bbx.y_offset = grid->base_y - + (grid->glyph_y + grid->glyph_bbx.height); + grid->glyph_bbx.ascent = grid->base_y - grid->glyph_y; + grid->glyph_bbx.descent = + (grid->glyph_y + grid->glyph_bbx.height) - grid->base_y; + } + } + } + + if (flipped) { + /* + * Copy the scratch area back to the working area. + */ + if (sel) + (void) memcpy((char *) grid->sel.bitmap, (char *) scratch, bytes); + else + (void) memcpy((char *) grid->bitmap, (char *) scratch, bytes); + + if (sel) { + /* + * Check to see if flipping the selection caused the glyph metrics + * to change. + */ + if (_bdf_grid_ink_bounds(grid, &x, &y, &wd, &ht)) { + if (x < grid->glyph_x) { + delta = grid->glyph_x - x; + grid->glyph_bbx.width += delta; + grid->glyph_bbx.x_offset -= delta; + grid->glyph_x -= delta; + if (grid->spacing == BDF_PROPORTIONAL) + grid->dwidth += delta; + } else if (x >= grid->glyph_x + grid->glyph_bbx.width) { + delta = x - (grid->glyph_x + grid->glyph_bbx.width); + grid->glyph_bbx.width += delta; + if (grid->spacing == BDF_PROPORTIONAL) + grid->dwidth += delta; + } + + if (y < grid->glyph_y) { + delta = grid->glyph_y - y; + grid->glyph_bbx.height += delta; + grid->glyph_bbx.ascent += delta; + grid->glyph_y -= delta; + } else if (y >= grid->glyph_y + grid->glyph_bbx.height) { + delta = y - (grid->glyph_y + grid->glyph_bbx.height); + grid->glyph_bbx.height += delta; + grid->glyph_bbx.y_offset -= delta; + grid->glyph_bbx.descent += delta; + } + } + } + + /* + * Mark the grid as being modified. + */ + grid->modified = 1; + } + + return flipped; +} + +void +#ifdef __STDC__ +bdf_grid_origin(bdf_glyph_grid_t *grid, short *x, short *y) +#else +bdf_grid_origin(grid, x, y) +bdf_glyph_grid_t *grid; +short *x, *y; +#endif +{ + if (grid == 0) + return; + + *x = grid->base_x; + *y = grid->base_y; +} + +bdf_glyph_t * +#ifdef __STDC__ +bdf_grid_glyph(bdf_glyph_grid_t *grid) +#else +bdf_grid_glyph(grid) +bdf_glyph_grid_t *grid; +#endif +{ + int len; + short x, y, nx, ny, wd, ht, gx, gy; + unsigned short bpr, nbpr, si, di, col, byte; + bdf_glyph_t *glyph; + unsigned char *masks; + double ps, dw, rx; + + if (grid == 0) + return 0; + + masks = 0; + switch (grid->bpp) { + case 1: + masks = onebpp; + di = 7; + break; + case 2: + masks = twobpp; + di = 3; + break; + case 4: + masks = fourbpp; + di = 1; + break; + } + + /* + * Create the new glyph. + */ + glyph = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t)); + (void) memset((char *) glyph, 0, sizeof(bdf_glyph_t)); + + gx = grid->glyph_x; + gy = grid->glyph_y; + + /* + * Copy the bounding box. + */ + (void) memcpy((char *) &glyph->bbx, (char *) &grid->glyph_bbx, + sizeof(bdf_bbx_t)); + + /* + * If the font has character-cell spacing, then make sure the bitmap is + * cropped to fit within the bounds of the font bbx. + */ + if (grid->spacing == BDF_CHARCELL) { + if (gx < grid->base_x) { + glyph->bbx.x_offset = 0; + glyph->bbx.width -= grid->base_x - gx; + gx += grid->base_x - gx; + } + if (glyph->bbx.width > grid->font_bbx.width) + glyph->bbx.width -= glyph->bbx.width - grid->font_bbx.width; + } + + /* + * Set up its bitmap. + */ + nbpr = ((glyph->bbx.width * grid->bpp) + 7) >> 3; + glyph->bytes = nbpr * glyph->bbx.height; + glyph->bitmap = (unsigned char *) malloc(glyph->bytes); + (void) memset((char *) glyph->bitmap, 0, glyph->bytes); + + /* + * Set the other values. + */ + if (grid->name != 0) { + len = strlen(grid->name) + 1; + glyph->name = (char *) malloc(len); + (void) memcpy(glyph->name, grid->name, len); + } + glyph->encoding = grid->encoding; + glyph->dwidth = grid->dwidth; + + /* + * Reset the glyph SWIDTH value. + */ + ps = (double) grid->point_size; + rx = (double) grid->resolution_x; + dw = (double) grid->dwidth; + glyph->swidth = (unsigned short)((dw * 72000.0) / (ps * rx)); + + bpr = ((grid->grid_width * grid->bpp) + 7) >> 3; + wd = gx + glyph->bbx.width; + ht = gy + glyph->bbx.height; + + /* + * Copy the bitmap from the grid into the glyph. + */ + for (ny = 0, y = gy; y < ht; y++, ny++) { + col = gx * grid->bpp; + for (nx = 0, x = gx; x < wd; x++, nx += grid->bpp, col += grid->bpp) { + si = (col & 7) / grid->bpp; + byte = grid->bitmap[(y * bpr) + (col >> 3)] & masks[si]; + if (byte) { + di = (nx & 7) / grid->bpp; + if (di < si) + byte <<= (si - di) * grid->bpp; + else if (di > si) + byte >>= (di - si) * grid->bpp; + glyph->bitmap[(ny * nbpr) + (nx >> 3)] |= byte; + } + } + } + + /* + * Return the new glyph. + */ + return glyph; +} + +/* + * Create a bitmap with the glyph image as well as the selection. + */ +void +#ifdef __STDC__ +bdf_grid_image(bdf_glyph_grid_t *grid, bdf_bitmap_t *image) +#else +bdf_grid_image(grid, image) +bdf_glyph_grid_t *grid; +bdf_bitmap_t *image; +#endif +{ + short x, y, ix, iy; + unsigned short bpr, ibpr, si, di, col, colx, byte; + unsigned char *masks; + + if (grid == 0 || image == 0) + return; + + masks = 0; + switch (grid->bpp) { + case 1: + masks = onebpp; + di = 7; + break; + case 2: + masks = twobpp; + di = 3; + break; + case 4: + masks = fourbpp; + di = 1; + break; + } + + image->bpp = grid->bpp; + image->x = image->y = 0; + image->width = grid->grid_width; + image->height = grid->grid_height; + image->bytes = grid->bytes >> 1; + image->bitmap = (unsigned char *) malloc(image->bytes); + (void) memcpy((char *) image->bitmap, (char *) grid->bitmap, image->bytes); + + /* + * Add the selection to the bitmap if it exists. + */ + if (grid->sel.width != 0 && grid->sel.height != 0) { + ibpr = ((image->width * grid->bpp) + 7) >> 3; + bpr = ((grid->sel.width * grid->bpp) + 7) >> 3; + for (iy = grid->sel.y, y = 0; y < grid->sel.height; y++, iy++) { + for (ix = grid->sel.x, col = x = 0; x < grid->sel.width; + x++, ix++, col += grid->bpp) { + si = (col & 7) / grid->bpp; + byte = grid->sel.bitmap[(y * bpr) + (col >> 3)] & masks[si]; + if (byte) { + colx = ix * grid->bpp; + di = (colx & 7) / grid->bpp; + if (di < si) + byte <<= (si - di) * grid->bpp; + else if (di > si) + byte >>= (di - si) * grid->bpp; + image->bitmap[(iy * ibpr) + (colx >> 3)] |= byte; + } + } + } + } +} + +/* + * Routines for quick and dirty dithering. + */ +static void +#ifdef __STDC__ +_bdf_one_to_n(bdf_bitmap_t *bmap, int n) +#else +_bdf_one_to_n(bmap, n) +bdf_bitmap_t *bmap; +int n; +#endif +{ + unsigned short bpr, sbpr, bytes, col, sx, sy; + unsigned char *nbmap, *masks; + + if (bmap == 0 || bmap->width == 0 || bmap->height == 0) + return; + + masks = 0; + switch (n) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + sbpr = (bmap->width + 7) >> 3; + bpr = ((bmap->width * n) + 7) >> 3; + bytes = bpr * bmap->height; + nbmap = (unsigned char *) malloc(bytes); + (void) memset((char *) nbmap, 0, bytes); + + for (sy = 0; sy < bmap->height; sy++) { + for (col = sx = 0; sx < bmap->width; sx++, col += n) { + if (bmap->bitmap[(sy * sbpr) + (sx >> 3)] & (0x80 >> (sx & 7))) + nbmap[(sy * bpr) + (col >> 3)] |= masks[(col & 7) / n]; + } + } + free((char *) bmap->bitmap); + bmap->bpp = n; + bmap->bytes = bytes; + bmap->bitmap = nbmap; +} + +static void +#ifdef __STDC__ +_bdf_n_to_one(bdf_bitmap_t *bmap) +#else +_bdf_n_to_one(bmap) +bdf_bitmap_t *bmap; +#endif +{ + unsigned short bpr, sbpr, bytes, col, sx, sy; + unsigned char *nbmap, *masks; + + if (bmap == 0 || bmap->width == 0 || bmap->height == 0) + return; + + masks = 0; + switch (bmap->bpp) { + case 1: + masks = onebpp; + break; + case 2: + masks = twobpp; + break; + case 4: + masks = fourbpp; + break; + } + + sbpr = ((bmap->width * bmap->bpp) + 7) >> 3; + bpr = (bmap->width + 7) >> 3; + bytes = bpr * bmap->height; + nbmap = (unsigned char *) malloc(bytes); + (void) memset((char *) nbmap, 0, bytes); + + for (sy = 0; sy < bmap->height; sy++) { + for (col = sx = 0; sx < bmap->width; sx++, col += bmap->bpp) { + if (bmap->bitmap[(sy * sbpr) + (col >> 3)] & + masks[(col & 7) / bmap->bpp]) + nbmap[(sy * bpr) + (sx >> 3)] |= (0x80 >> (sx & 7)); + } + } + free((char *) bmap->bitmap); + bmap->bpp = 1; + bmap->bytes = bytes; + bmap->bitmap = nbmap; +} + +static void +#ifdef __STDC__ +_bdf_two_to_four(bdf_bitmap_t *bmap) +#else +_bdf_two_to_four(bmap) +bdf_bitmap_t *bmap; +#endif +{ + unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy; + unsigned char *nbmap, *masks; + + if (bmap == 0 || bmap->width == 0 || bmap->height == 0) + return; + + masks = twobpp; + + sbpr = ((bmap->width << 1) + 7) >> 3; + bpr = ((bmap->width << 2) + 7) >> 3; + bytes = bpr * bmap->height; + nbmap = (unsigned char *) malloc(bytes); + (void) memset((char *) nbmap, 0, bytes); + + for (sy = 0; sy < bmap->height; sy++) { + for (col = sx = 0; sx < bmap->width; sx++, col += 2) { + si = (col & 7) >> 1; + byte = bmap->bitmap[(sy * sbpr) + (col >> 3)] & masks[si]; + if (byte) { + /* + * Shift the byte down to make an index. + */ + if (si < 3) + byte >>= (3 - si) << 1; + + /* + * Scale the index to four bits per pixel and shift it into + * place before adding it. + */ + byte = (byte << 2) + 3; + if ((sx & 1) == 0) + byte <<= 4; + nbmap[(sy * bpr) + ((sx << 2) >> 3)] |= byte; + } + } + } + free((char *) bmap->bitmap); + bmap->bpp = 4; + bmap->bytes = bytes; + bmap->bitmap = nbmap; +} + +static void +#ifdef __STDC__ +_bdf_four_to_two(bdf_bitmap_t *bmap) +#else +_bdf_four_to_two(bmap) +bdf_bitmap_t *bmap; +#endif +{ + unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy; + unsigned char *nbmap, *masks; + + if (bmap == 0 || bmap->width == 0 || bmap->height == 0) + return; + + masks = fourbpp; + + sbpr = ((bmap->width << 2) + 7) >> 3; + bpr = ((bmap->width << 1) + 7) >> 3; + bytes = bpr * bmap->height; + nbmap = (unsigned char *) malloc(bytes); + (void) memset((char *) nbmap, 0, bytes); + + for (sy = 0; sy < bmap->height; sy++) { + for (col = sx = 0; sx < bmap->width; sx++, col += 4) { + si = (col & 7) >> 2; + byte = bmap->bitmap[(sy * sbpr) + (col >> 3)] & masks[si]; + if (byte) { + /* + * Shift the byte down to make an index. + */ + if (si == 0) + byte >>= 4; + + /* + * Scale the index to two bits per pixel and shift it into + * place if necessary. + */ + byte >>= 2; + + si = ((sx << 1) & 7) >> 1; + if (si < 3) + byte <<= (3 - si) << 1; + + nbmap[(sy * bpr) + ((sx << 1) >> 3)] |= byte; + } + } + } + free((char *) bmap->bitmap); + bmap->bpp = 2; + bmap->bytes = bytes; + bmap->bitmap = nbmap; +} + +/* + * Add a bitmap to a grid as a selection. + */ +void +#ifdef __STDC__ +bdf_add_selection(bdf_glyph_grid_t *grid, bdf_bitmap_t *sel) +#else +bdf_add_selection(grid, sel) +bdf_glyph_grid_t *grid; +bdf_bitmap_t *sel; +#endif +{ + unsigned short bytes, bpr; + + if (grid == 0 || sel == 0 || sel->width == 0 || sel->height == 0 || + sel->bytes == 0) + return; + + if (sel->bpp != grid->bpp) { + /* + * Dither the incoming bitmap to match the same bits per pixel as the + * grid it is being added to. + */ + if (sel->bpp == 1) + _bdf_one_to_n(sel, grid->bpp); + else if (grid->bpp == 1) + _bdf_n_to_one(sel); + else if (sel->bpp == 2) + _bdf_two_to_four(sel); + else + _bdf_four_to_two(sel); + } + + /* + * If the bitmap is too big then trim the right and/or the bottom to fit + * in the grid. + */ + if (sel->width > grid->grid_width) + sel->width = grid->grid_width; + if (sel->height > grid->grid_height) + sel->height = grid->grid_height; + + /* + * If the positioning puts the selection bitmap off one of the edges, + * adjust it so it is completely on the grid. + */ + if (sel->x + sel->width > grid->grid_width) + sel->x -= (sel->x + sel->width) - grid->grid_width; + if (sel->y + sel->height > grid->grid_height) + sel->y -= (sel->y + sel->height) - grid->grid_height; + + bpr = ((sel->width * grid->bpp) + 7) >> 3; + bytes = (bpr * sel->height) << 1; + + /* + * Resize the storage for the selection bitmap if necessary. + */ + if (bytes > grid->sel.bytes) { + if (grid->sel.bytes == 0) + grid->sel.bitmap = (unsigned char *) malloc(bytes); + else + grid->sel.bitmap = (unsigned char *) + realloc((char *) grid->sel.bitmap, bytes); + grid->sel.bytes = bytes; + } + + /* + * Copy the width and height values. + */ + grid->sel.x = sel->x; + grid->sel.y = sel->y; + grid->sel.width = sel->width; + grid->sel.height = sel->height; + + /* + * Copy the incoming bitmap to the new selection bitmap. + */ + (void) memcpy((char *) grid->sel.bitmap, (char *) sel->bitmap, + bytes >> 1); + + /* + * Crop the image to adjust the glyph bounding box. + */ + (void) bdf_grid_crop(grid, 1); +} + +int +#ifdef __STDC__ +bdf_grid_color_at(bdf_glyph_grid_t *grid, short x, short y) +#else +bdf_grid_color_at(grid, x, y) +bdf_glyph_grid_t *grid; +short x, y; +#endif +{ + unsigned short bpr, si, di, byte; + unsigned char *masks; + + if (grid->bpp == 1) + return -1; + + masks = twobpp; + di = 0; + switch (grid->bpp) { + case 2: + di = 3; + break; + case 4: + di = 1; + break; + } + + x *= grid->bpp; + + bpr = ((grid->grid_width * grid->bpp) + 7) >> 3; + si = (x & 7) / grid->bpp; + + byte = grid->bitmap[(y * bpr) + (x >> 3)] & masks[si]; + if (di > si) + byte >>= (di - si) * grid->bpp; + return (int) byte; +} diff --git a/tools/sci/bdftofont.cpp b/tools/sci/bdftofont.cpp new file mode 100644 index 0000000000..c09543bfc0 --- /dev/null +++ b/tools/sci/bdftofont.cpp @@ -0,0 +1,177 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include <bdf.h> +#include <config.h> +#include <stdlib.h> +#include <stdio.h> + + +bdf_options_t bdf_opts = { + 0, /* ttf_hint */ + 0, /* correct_metrics */ + 0, /* keep_unencoded */ + 0, /* keep_comments */ + 0, /* pad_cells */ + 0, /* font_spacing */ + 0, /* point_size */ + 0, /* resolution_x */ + 0, /* resolution_y */ + 0, /* bits_per_pixel */ + BDF_UNIX_EOL /* eol */ +}; + + +#define GLYPH(n) glyphs[(((n) > 31)? ((n) - 31) : 0)] + +void +convert_font(FILE *in_file, FILE *out_file) { + bdf_font_t *font = + bdf_load_font(in_file, + &bdf_opts, + NULL, NULL); + + int chars_nr = font->glyphs_used; + int width = font->monowidth; + int bytes_per_row = (width + 7) >> 3; + int line_height; + int char_height = 0; + int char_byte_size; + int i; + bdf_glyph_t *glyphs = font->glyphs; + + fclose(in_file); + + if (!font) { + fprintf(stderr, "Not a BDF file? Aborting!\n"); + exit(1); + } + + printf("Res = %d/%d; pointsize = %d, spacing = %d, width=%d, asc=%ld, desc=%ld, glyphs=%ld\n", + font->resolution_x, + font->resolution_y, + font->point_size, + font->spacing, + font->monowidth, + font->font_ascent, + font->font_descent, + chars_nr); + + if (chars_nr > 256) + chars_nr = 256; + + for (i = 0; i < chars_nr; i++) { + int rh = GLYPH(i).bbx.height; + + if (rh > char_height) + char_height = rh; + } + + + + line_height = char_height + 1; + char_byte_size = bytes_per_row * char_height; + + fprintf(out_file, "# %d %d\n", chars_nr, char_height + 1); + + for (i = 0; i < chars_nr; i++) { + int rh = GLYPH(i).bbx.height; + int rw = GLYPH(i).bbx.width; + int xoff = 0; /* GLYPH(i).bbx.x_offset; */ + int yoff = 0; /* GLYPH(i).bbx.y_offset; */ + int j, k; + int top_pad = yoff; + int bot_pad = (char_height - rh) - top_pad; + int bytes_to_read = (GLYPH(i).bytes) / rh; + unsigned char *data = GLYPH(i).bitmap; + + if (bytes_to_read <= 0) { + fprintf(stderr, "No bytes per row: bytes=%d, w=%d, h=%d\n", + GLYPH(i).bytes, rw, rh); + exit(1); + } + + if (bot_pad < 0) { + fprintf(stderr, "Bottom padding <0: height=%d/%d, top_pad=%d\n", + rh, char_height, yoff); + exit(1); + } + + /* First, pad everything */ + for (j = 0; j < top_pad; j++) { + for (k = 0; k < rw; k++) + fprintf(out_file, "."); + fprintf(out_file, "\n"); + } + + /* Write char data */ + for (j = 0; j < rh; j++) { + unsigned int b = 0; + unsigned int oldb; + for (k = 0; k < bytes_to_read; k++) { + int shift_offset = 8 * (bytes_to_read - 1 - k); + b |= (*data++ << shift_offset); + } + + oldb = b; + + for (k = 0; k < rw; k++) + fprintf(out_file, (oldb & (1 << ((bytes_per_row * 8) - 1 - k))) ? "#" : "."); + + fprintf(out_file, "\n"); + } + + /* Pad bottom */ + for (j = 0; j < bot_pad; j++) { + for (k = 0; k < rw; k++) + fprintf(out_file, "."); + fprintf(out_file, "\n"); + } + fprintf(out_file, "----\t 0x%02x ('%c') */\n", i, ((i > 31) && (i < 0x7f)) ? i : '.'); + } + fprintf(out_file, "\n\n"); + + fclose(out_file); +} + + +int +main(int argc, char **argv) { + FILE *f = NULL; + bdf_setup(); + + if (argc < 3) { + fprintf(stderr, "Usage: %s <font.bdf> <outfile.font>\n ", argv[0]); + exit(1); + } + + f = fopen(argv[1], "r"); + if (f) + convert_font(f, fopen(argv[2], "w")); + else + perror(argv[1]); + + bdf_cleanup(); +} diff --git a/tools/sci/classes.cpp b/tools/sci/classes.cpp new file mode 100644 index 0000000000..2fbe873e24 --- /dev/null +++ b/tools/sci/classes.cpp @@ -0,0 +1,51 @@ +#include <stdio.h> +#include <stdlib.h> + +#include <engine.h> +#include <vocabulary.h> + +int main(int argc, char** argv) { + int res; + int sizes[1000]; + int altsizes[1000]; + int count, *classes; + loadResources(SCI_VERSION_AUTODETECT, 1); + + for (res = 0; res < 1000; res++) { + resource_t* r; + int i = 0; + + sizes[res] = -1; + + if ((r = findResource(sci_script, res)) == 0) continue; + sizes[res] = 0; + altsizes[res] = 0; + i += 2; + i = getInt16(r->data + i); + + while (i < r->length - 2) { + switch (getInt16(r->data + i)) { + case 1: + case 6: + sizes[res]++; + break; + default: + altsizes[res]++; + } + i += getInt16(r->data + i + 2); + } + fflush(stdout); + } + + for (res = 0; res < 1000; res++) if (sizes[res] != -1) printf("%03d %d\n", res, sizes[res]); + printf("\n"); + + classes = vocabulary_get_classes(&count); + for (res = 0; res < count; res++) { + printf("%03d %d (%d)\n", classes[res], + sizes[classes[res]]--, altsizes[classes[res]]); + } + + freeResources(); + return 0; +} diff --git a/tools/sci/fonttoc.cpp b/tools/sci/fonttoc.cpp new file mode 100644 index 0000000000..9f7a9a2011 --- /dev/null +++ b/tools/sci/fonttoc.cpp @@ -0,0 +1,256 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include <config.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + + +#define GLYPH(n) glyphs[n] + + +int max_width = 0; + +char inbuf[256]; + +typedef struct { + int bytes; + int width; + unsigned char *bitmap; +} glyph_t; + + +unsigned int +invert_bits(unsigned int s, int bits) { + unsigned int rv = 0; + int i; + for (i = 0; i < bits; i++) + if (s & (1 << i)) + rv |= (1 << (bits - 1 - i)); + + return rv; +} + +void +read_single_glyph(FILE *in_file, glyph_t *dest, int index, int char_height) { + int width = -1; + int bytes = 0; + int i; + unsigned char *data + = dest->bitmap = (unsigned char *) malloc(char_height * 4); /* Let's waste memory */ + + do { + unsigned int d = 0; + + fgets(inbuf, 255, in_file); + + if (char_height-- == -1) { + fprintf(stderr, "Char 0x%02x is too long!\n", index); + exit(1); + } + + if (inbuf[0] == '.' || inbuf[0] == '#') { + int cw; + + if (width == -1) + width = strlen(inbuf) - 1; + else if (strlen(inbuf) - 1 != width) { + fprintf(stderr, "Char 0x%02x uses inconsistent width\n", index); + exit(1); + } + + for (i = 0; i < width; i++) + if (inbuf[i] == '#') + d |= (1 << i); + + d = invert_bits(d, ((width + 7) / 8) * 8); + + cw = width; + do { + *data = d & 0xff; + d >>= 8; + data++; + cw -= 8; + ++bytes; + } while (cw > 0); + } + + } while (inbuf[0] == '.' || inbuf[0] == '#'); + + if (char_height >= 0) { + fprintf(stderr, "Char 0x%02x is too short (by %d)!\n", index, char_height); + exit(1); + } + + dest->width = width; + if (width > max_width) + max_width = width; + + dest->bytes = bytes; +} + +glyph_t * +read_glyphs(FILE *in_file, int nr, int char_height) { + int i; + glyph_t *glyphs = (glyph_t *) calloc(sizeof(glyph_t), nr); + + for (i = 0; i < nr; i++) + read_single_glyph(in_file, glyphs + i, i, char_height); + + return glyphs; +} + +void +convert_font(FILE *in_file, char *structname, FILE *out_file) { + int chars_nr; + glyph_t *glyphs; + int bytes_per_row; + int line_height; + int char_height = 0; + int char_byte_size; + int i; + + fscanf(in_file, "# %d %d\n", &chars_nr, &char_height); + printf("Parsing %d characters at height %d\n", chars_nr, char_height); + glyphs = read_glyphs(in_file, chars_nr, char_height); + + bytes_per_row = (max_width + 7) >> 3; + line_height = char_height + 1; + fclose(in_file); + + char_byte_size = bytes_per_row * char_height; + + fprintf(out_file, "/* Auto-generated by bdftofont.c */\n\n"); + + fprintf(out_file, "#include <gfx_system.h>\n\n"); + + fprintf(out_file, "static int %s_widths[] = {\n", structname); + for (i = 0; i < chars_nr; i++) { + int rw = GLYPH(i).width; + fprintf(out_file, "\t%d%s\t/* 0x%02x */\n", rw, + (i < (chars_nr - 1)) ? "," : "", i); + } + fprintf(out_file, "};\n\n"); + + fprintf(out_file, "static unsigned char %s_data[] = {\n", structname); + for (i = 0; i < chars_nr; i++) { + int rh = char_height; + int rw = GLYPH(i).width; + int xoff = 0; + int yoff = 0; + int j, k; + + int top_pad = yoff; + int bot_pad = (char_height - rh) - top_pad; + int bytes_to_read = (GLYPH(i).bytes) / rh; + unsigned char *data = GLYPH(i).bitmap; + + if (bytes_to_read <= 0) { + fprintf(stderr, "No bytes per row: bytes=%d, w=%d, h=%d\n", + GLYPH(i).bytes, rw, rh); + exit(1); + } + + if (bot_pad < 0) { + fprintf(stderr, "Bottom padding <0: height=%d/%d, top_pad=%d\n", + rh, char_height, yoff); + exit(1); + } + + fprintf(out_file, "\t/* 0x%02x ('%c') */\n", i, ((i > 31) && (i < 0x7f)) ? i : '.'); + /* First, pad everything */ + for (j = 0; j < top_pad; j++) { + fprintf(out_file, "\t"); + for (k = 0; k < bytes_per_row; k++) + fprintf(out_file, "0x00, "); + fprintf(out_file, "\n"); + } + + /* Write char data */ + for (j = 0; j < rh; j++) { + unsigned int b = 0; + unsigned int oldb; + fprintf(out_file, "\t"); + for (k = 0; k < bytes_to_read; k++) { + int shift_offset = 8 * (bytes_to_read - 1 - k); + b |= (*data++ << shift_offset); + } + + oldb = b; + + for (k = 0; k < bytes_per_row; k++) { + fprintf(out_file, "0x%02x%s", (b & 0xff), (bot_pad || (i + 1 < chars_nr) || (j + 1 < rh) || (k + 1 < bytes_per_row)) ? ", " : ""); + b >>= 8; + } + fprintf(out_file, "\t/* "); + for (k = 0; k < rw; k++) + fprintf(out_file, (oldb & (1 << ((bytes_per_row * 8) - 1 - k))) ? "##" : ".."); + fprintf(out_file, " */"); + + fprintf(out_file, "\n"); + } + + /* Pad bottom */ + for (j = 0; j < bot_pad; j++) { + fprintf(out_file, "\t"); + for (k = 0; k < bytes_per_row; k++) + fprintf(out_file, "0x00%s", ((i + 1 < chars_nr) || (j + 1 < bot_pad) || (k + 1 < bytes_per_row)) ? ", " : ""); + fprintf(out_file, "\n"); + } + } + fprintf(out_file, "};\n\n"); + + fprintf(out_file, "gfx_bitmap_font_t %s = {\n", structname); + fprintf(out_file, "\t-1, /* resource ID */\n"); + fprintf(out_file, "\t%d, /* # of characters */\n", chars_nr); + fprintf(out_file, "\t%s_widths, /* Widths */\n", structname); + fprintf(out_file, "\t%d, /* Bytes per row */\n", bytes_per_row); + fprintf(out_file, "\t%d, /* Line height */\n", line_height); + fprintf(out_file, "\t%d, /* Char height */\n", char_height); + fprintf(out_file, "\t%d, /* Char size (occupied, in bytes) */\n", char_byte_size); + fprintf(out_file, "\t%s_data /* Bulk data */\n", structname); + fprintf(out_file, "};\n"); + + fclose(out_file); +} + + +int +main(int argc, char **argv) { + FILE *f = NULL; + + if (argc < 4) { + fprintf(stderr, "Usage: %s <font.font> <structname> <outfile.c>\n ", argv[0]); + exit(1); + } + + f = fopen(argv[1], "r"); + if (f) + convert_font(f, argv[2], fopen(argv[3], "w")); + else + perror(argv[1]); + +} diff --git a/tools/sci/graphics_png.h b/tools/sci/graphics_png.h new file mode 100644 index 0000000000..84358478f1 --- /dev/null +++ b/tools/sci/graphics_png.h @@ -0,0 +1,112 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +/* Provides facilities for writing pictures and seperate views to .png files */ + + +#ifndef _SCI_GRAPHICS_PNG_H_ +#define _SCI_GRAPHICS_PNG_H_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif /* HAVE_CONFIG_H */ + +#ifdef HAVE_LIBPNG + +#include <resource.h> +#include <graphics.h> +#include <png.h> + +int +write_pic_png(char *filename, guint8 *pic); +/* Stores a picture map in a png file +** --DEPRECATED-- +** Parameters: (filename) The name of the file to create +** (pic) A pointer to the picture map to store +** Returns : (int) 0 on success, != 0 otherwise +** Please note that pic must not point to a picture_t, it must point to a +** map. +** E.g. to store the foreground picture, you could use +** write_pic_png("filename.png", picture->maps[0]). +*/ + + +int +png_save_buffer(picture_t pic, char *name, + int xoffset, int yoffset, int width, int height, + byte *data, int force_8bpp_special); +/* Stores any buffer in a png file +** Parameters: (picture_t) pic: The picture_t containing the parameters of the buffer +** (char *) name: File name to write to +** (int x int) xoffset, yoffset: relative screen position of the buffer +** (int x int) width, height: Buffer size +** (byte *) data: The actual data to write +** (int) force_8bpp_special: See below +** Returns : (int) 0 on success, 1 otherwise +** Each graphics buffer is stored in the way that the corresponding picture_t +** dictates (all buffers are either identical to, or parts of a past representation +** of the picture_t map 0, after all). +** force_8bpp_special overrides this and forces 8bpp palette mode for writing the +** buffer. +** This should only be used for maps 1 through 3, which are always in this format. +*/ + + +byte * +png_load_buffer(picture_t pic, char *name, + int *xoffset, int *yoffset, int *width, int *height, + int *size, int force_8bpp_special); +/* Loads a buffer from a png file +** Parameters: (picture_t) pic: The picture_t containing the target parameters +** (char *) name: The file name of the file to read from +** (int* x int*) xoffset, yoffset: Offset storage pointers +** (int* x int*) width, height: Size storage pointers +** (int*) size: Memory size storage pointer +** (int) force_8bpp_special: Import file as 8bpp with palette +** Returns : (byte *): The buffer on success, NULL otherwise +** xoffset, yoffset, width, height, and size should each point to ints the picture +** parameters are stored in. xoffset and yoffset may be set to NULL, though, in +** order to be omitted. +*/ + + +int +png_save_pic(picture_t pic); +/* Stores a picture_t in the current directory +** Parameters: (picture_t) pic: The picture_t to store +** Returns : (int) 0 on success, 1 otherwise +*/ + +int +png_load_pic(picture_t pic); +/* Loads a picture_t from the cwd +** Parameters: (picture_t) pic: The structure to write to +** Returns : (int) 0 on success, 1 otherwise +** On error, the original pic status is retained. +*/ + + +#endif /* HAVE_LIBPNG */ +#endif /* !_SCI_GRAPHICS_PNG_H_ */ diff --git a/tools/sci/listwords.cpp b/tools/sci/listwords.cpp new file mode 100644 index 0000000000..3951a1e779 --- /dev/null +++ b/tools/sci/listwords.cpp @@ -0,0 +1,85 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "sciunpack.h" +#include <engine.h> +#include <kernel.h> + +int +_vocab_cmp_group(const void *word1, const void *word2) { +#define fw (* ((word_t **) word1)) +#define sw (* ((word_t **) word2)) + if (fw->group < sw->group) + return -1; + else if (fw->group == sw->group) + return 0; + else + return 1; +} + +int vocab_sort = DEFAULT_SORTING; + +int +vocab_print(void) { + int b, words_nr, counter; + word_t **words, **tracker; + + tracker = words = vocab_get_words(resmgr, &words_nr); + + counter = words_nr; + + if (vocab_sort == SORT_METHOD_GROUP) + qsort(words, words_nr, sizeof(word_t *), _vocab_cmp_group); /* Sort entries */ + + while (counter--) { + printf("%s (class %03x, group %03x) ", &tracker[0]->word, + tracker[0]->w_class, tracker[0]->group); + + if ((tracker[0]->w_class >= 0xf00) || + (tracker[0]->w_class == 0)) + printf("anyword\n"); + else + while (tracker[0]->w_class) { + b = sci_ffs(tracker[0]->w_class) - 1; + tracker[0]->w_class &= ~(1 << b); + printf("%s", class_names[b]); + if (tracker[0]->w_class) + printf("|"); + else + printf("\n"); + } + tracker++; + } + + vocab_free_words(words, words_nr); + + return 0; +} + + + + + + diff --git a/tools/sci/musicplayer.cpp b/tools/sci/musicplayer.cpp new file mode 100644 index 0000000000..139ce451ef --- /dev/null +++ b/tools/sci/musicplayer.cpp @@ -0,0 +1,103 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif /* HAVE_CONFIG_H */ + +#include <sfx_iterator_internal.h> +#include <sfx_engine.h> +#include <sfx_core.h> +#include <resource.h> + +#define DUMMY_SOUND_HANDLE 0xdeadbeef + +static song_iterator_t * +build_iterator(resource_mgr_t *resmgr, int song_nr, int type, songit_id_t id) { + resource_t *song = scir_find_resource(resmgr, sci_sound, song_nr, 0); + + if (!song) + return NULL; + + return songit_new(song->data, song->size, type, id); +} + +int main(int argc, char** argv) { + resource_mgr_t *resmgr; + sfx_state_t sound; + int res_version = SCI_VERSION_AUTODETECT; + int sound_nr; + song_handle_t dummy1; + int dummy2; + int arg; + int it_type = SCI_SONG_ITERATOR_TYPE_SCI0; + song_iterator_t *base, *ff; + + printf("FreeSCI %s music player Copyright (C) 1999-2007\n", VERSION); + printf(" Dmitry Jemerov, Christopher T. Lansdown, Sergey Lapin, Rickard Lind,\n" + " Carl Muckenhoupt, Christoph Reichenbach, Magnus Reftel, Lars Skovlund,\n" + " Rink Springer, Petr Vyhnak, Solomon Peachy, Matt Hargett, Alex Angas\n" + " Walter van Niftrik, Rainer Canavan, Ruediger Hanke, Hugues Valois\n" + "This program is free software. You can copy and/or modify it freely\n" + "according to the terms of the GNU general public license, v2.0\n" + "or any later version, at your option.\n" + "It comes with ABSOLUTELY NO WARRANTY.\n"); + if (argc < 3) { + fprintf(stderr, "Syntax: %s <resource dir> <sound number> [<sound number> ...]\n", argv[0]); + return 1; + } + + if (!(resmgr = scir_new_resource_manager(argv[1], res_version, + 0, 1024 * 128))) { + fprintf(stderr, "Could not find any resources; quitting.\n"); + return 2; + } + + if (resmgr->sci_version >= SCI_VERSION_01) + it_type = SCI_SONG_ITERATOR_TYPE_SCI1; + + sfx_init(&sound, resmgr, 0); + sfx_set_volume(&sound, 127); + + arg = 2 - 1; + while (++arg < argc) { + sound_nr = atoi(argv[arg]); + base = ff = build_iterator(resmgr, sound_nr, it_type, + DUMMY_SOUND_HANDLE); + printf("Playing resource %d...\n", sound_nr); + if (sfx_add_song(&sound, ff, + 0, DUMMY_SOUND_HANDLE, sound_nr)) { + fprintf(stderr, "Could not start sound resource. Does it exist?\n"); + return 2; + } + sfx_song_set_status(&sound, DUMMY_SOUND_HANDLE, SOUND_STATUS_PLAYING); + while (sfx_poll(&sound, &dummy1, &dummy2) != SI_FINISHED) {}; + } + sfx_exit(&sound); + scir_free_resource_manager(resmgr); + return 0; +} + + diff --git a/tools/sci/old_objects.cpp b/tools/sci/old_objects.cpp new file mode 100644 index 0000000000..048a0fd2b9 --- /dev/null +++ b/tools/sci/old_objects.cpp @@ -0,0 +1,679 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include <sciresource.h> +#include <console.h> +#include <script.h> +#include <vocabulary.h> +#include <old_objects.h> +#include <stdio.h> +#include <stdlib.h> +#include <util.h> +#include <vm.h> +#include <assert.h> + +#ifdef SCI_CONSOLE +#define printf sciprintf +/* Yeah, I shouldn't be doing this ;-) [CJR] */ +#endif + +FLEXARRAY_NOEXTRA(object*) fobjects; + +static int knames_count; +static char** knames; +static char** snames; +static opcode* opcodes; + +object **object_map, *object_root; +int max_object; + +const char* globals[] = { + /*00*/ + "ego", + "GAMEID", + "roomXX", + "speed", + /*04*/ + "quitFlag", + "cast", + "regions", + "timer", + /*08*/ + "sounds", + "inv", + "eventHandler", + "roomNumberExit", + /*0C*/ + "previousRoomNumber", + "roomNumber", + "enterDebugModeOnRoomExit", + "score", + /*10*/ + "maximumScore", + "11", + "speed", + "13", + /*14*/ + "14", + "loadCursor", + "normalFont", + "restoreSaveFont", /*dialogFont*/ + /*18*/ + "18", + "19", + "defaultFont", + "1B", + /*1C*/ + "pointerToVersionNumber", + "locales", + "pointerToSaveGameDirectory", + "1F" +}; + +static int add_object(object* obj) { + FLEXARRAY_APPEND(object*, fobjects, obj, return 1); + return 0; +} + +static void dump(byte* data, int len) { + int i = 0; + while (i < len) { + printf("%02X ", data[i++]); + if (i % 8 == 0) printf(" "); + if (i % 16 == 0) printf("\n"); + } + if (i % 16) printf("\n"); +} + +static void printMethod(object* obj, int meth, int indent) { + script_method* m = obj->methods[meth]; + int i, j; + + for (j = 0; j < indent*2 - 1; j++) printf(" "); + printf("Method %s\n", snames[m->number]); + + for (i = 0; i < m->used; i++) { + script_opcode op = m->data[i]; + + for (j = 0; j < indent; j++) printf(" "); + printf("%s ", opcodes[op.opcode].name); + + switch (op.opcode) { + case 0x21: { /*callk*/ + if (op.arg1 > knames_count) printf("<no such kernel function %02X> ", op.arg1); + else printf("%s ", knames[op.arg1]); + printf("%02X", op.arg2); + } + break; + case 0x28: { /*class*/ + if (op.arg1 > max_object) printf("<no such class %02X>", op.arg1); + else { + /* [DJ] op.arg1+1 adjusts for the <root> object */ + if (fobjects.data[op.arg1+1] == 0) printf("<null object>"); + else printf("%s", fobjects.data[op.arg1+1]->name); + } + } + break; + case 0x44: { + if (op.arg1 > 0x20) printf("<no such global %02X> ", op.arg1); + else printf("%s ", globals[op.arg1]); + } + break; + default: { + int args[3]; + args[0] = op.arg1; + args[1] = op.arg2; + args[2] = op.arg3; + for (j = 0; j < 3; j++) { + switch (formats[op.opcode][j]) { + case Script_Invalid: { + printf("<invalid> "); + } + break; + case Script_None: { + j = 3; + } + break; + case Script_SByte: + case Script_Byte: { + printf("%02X ", args[j]); + } + break; + case Script_Word: + case Script_SVariable: + case Script_Variable: + case Script_SRelative: + case Script_Property: + case Script_Global: + case Script_Local: + case Script_Temp: + case Script_Param: { + printf("%04X ", args[j]); + } + break; + case Script_SWord: { + if (args[j] < 0) printf("-%04X", -args[j]); + else printf("%04X", args[j]); + } + break; + case Script_End: { + printf("\n"); + return; + } + break; + default: { + printf("<unknown arg type %d> ", formats[op.opcode][j]); + } + } + } + } + break; + } + printf("\n"); + } +} + +static void printObject_r(object* obj, int flags, int level) { + int i; + for (i = 0; i < level; i++) printf(" "); + if (obj == 0) printf("(null)\n"); + else { + printf("%s\n", obj->name); + if (flags&SCRIPT_PRINT_METHODS) { + for (i = 0; i < obj->method_count; i++) { + printMethod(obj, i, level + 1); + } + } + if (flags&SCRIPT_PRINT_CHILDREN) { + for (i = 0; i < obj->children.used; i++) { + printObject_r(obj->children.data[i], flags, level + 1); + } + } + } +} + +void printObject(object* obj, int flags) { + printf("pO(%p, %d)\n", obj, flags); + printObject_r(obj, flags, 0); +} + +static object* object_new() { + object* obj = (object*)sci_malloc(sizeof(object)); + if (obj == 0) return 0; + + obj->parent = 0; + FLEXARRAY_INIT(object*, obj->children); + obj->name = 0; + obj->selector_count = 0; + obj->selector_numbers = 0; + obj->methods = 0; + obj->method_count = 0; + + return obj; +} + +static int add_child(object* parent, object* child) { + FLEXARRAY_APPEND(object*, parent->children, child, return 1); + return 0; +} + +static object* fake_object(const char* reason) { + object* obj = object_new(); + if (obj == 0) { +#ifdef SCRIPT_DEBUG + printf("object_new failed during fake for %s\n", reason); +#endif + free(obj); + return 0; + } + if (add_child(object_root, obj)) { +#ifdef SCRIPT_DEBUG + printf("add_child failed during fake for %s\n", reason); +#endif + free(obj); + return 0; + } + obj->name = reason; + if (add_object(obj)) { +#ifdef SCRIPT_DEBUG + printf("add_object failed during fake for %s\n", reason); +#endif + /*FIXME: clean up parent*/ + return 0; + } + return obj; +} + +static script_method* decode_method(byte* data) { + script_method* m; + int done = 0; + int pos = 0; + static int count = 0; + + count++; + + if ((m = (script_method*)sci_malloc(sizeof(script_method))) == 0) return 0; + FLEXARRAY_INIT(script_opcode, *m); + + while (!done) { + int op = data[pos] >> 1; + int size = 2 - (data[pos] & 1); + int* args[3]; + int arg; + int old_pos; + + FLEXARRAY_ADD_SPACE(script_opcode, *m, 1, return 0); + old_pos = pos; + m->data[m->used-1].pos = pos; + m->data[m->used-1].opcode = op; + + /*Copy the adresses of the args to an array for convenience*/ + args[0] = &m->data[m->used-1].arg1; + args[1] = &m->data[m->used-1].arg2; + args[2] = &m->data[m->used-1].arg3; + + /*Skip past the opcode*/ + pos++; + + for (arg = 0; arg < 4; arg++) { + switch (formats[op][arg]) { + case Script_Invalid: { /*Can't happen(tm)*/ + int i; + printf("Invalid opcode %02X at %04X in method %d\n", op, pos, count); + for (i = m->used - 9; i < m->used - 1; i++) { + printf("%s[%02X] ", opcodes[m->data[i].opcode].name, m->data[i].opcode); + dump(data + m->data[i].pos, m->data[i].size); + } + printf("Dump from %04X-%04X\n", pos - 16, pos + 16); + dump(data + pos - 16, 32); + } + break; + case Script_None: { /*No more args*/ + arg = 4; + } + break; + case Script_Byte: /*Just a one byte arg*/ + case Script_SByte: { + *args[arg] = data[pos++]; + } + break; + case Script_Word: { /*A two byte arg*/ + *args[arg] = getInt16(data + pos); + pos += 2; + } + break; + case Script_SWord: { /*A signed two-byte arg*/ + int t = getInt16(data + pos); + if (t&0x8000) *args[arg] = -(t & 0x7FFF); + else *args[arg] = t; + pos += 2; + } + break; + case Script_Variable: /*Size of arg depends on LSB in opcode*/ + case Script_SVariable: + case Script_SRelative: + case Script_Property: + case Script_Global: + case Script_Local: + case Script_Temp: + case Script_Param: { + if (size == 1) *args[arg] = data[pos++]; + else { + *args[arg] = getInt16(data + pos); + pos += 2; + } + } + break; + case Script_End: { /*Special tag for ret*/ + done = 1; + arg = 4; + } + break; + default: { /*Can't happen(tm)*/ + printf("Unknown argument format %d for op %02X\n", formats[op][arg], op); + } + break; + } + } + fflush(stdout); + if (m->used) m->data[m->used-1].size = pos - old_pos; + } + + return m; +} + +#ifdef SCRIPT_DEBUG +void list_code_blocks(resource_t* r) { + int pos = getInt16(r->data + 2); + while (pos < r->size - 2) { + int type = getInt16(r->data + pos); + int len = getInt16(r->data + pos + 2); + if (type == 2) printf("%X-%X\n", pos, pos + len); + pos += len; + } +} +#endif + + +/*These expect the frame, the whole frame, and, well, other stuff too, + *I guess, as long as it looks like a frame*/ +static int get_type(unsigned char* obj) { + return getInt16(obj); +} + +static int get_length(unsigned char* obj) { + return getInt16(obj + 2); +} + +static int get_selector_count(unsigned char* obj) { + return getInt16(obj + 10); +} + +static int get_selector_value(unsigned char* obj, int sel) { + assert(sel < get_selector_count(obj)); + return getInt16(obj + 12 + sel*2); +} + +/*Bas things happen if the method offset value is wrong*/ +static unsigned char* get_method_area(unsigned char* obj) { + return obj + getInt16(obj + 8) + 10; +} + +static int get_method_count(unsigned char* obj) { + return getInt16(get_method_area(obj)); +} + +static int get_method_number(unsigned char* obj, int i) { + assert(i < get_method_count(obj)); + return getInt16(get_method_area(obj) + 2 + 2*i); +} + +static int get_method_location(unsigned char* obj, int i) { + assert(i < get_method_count(obj)); + return getInt16(get_method_area(obj) + 4 + 2*get_method_count(obj) + 2*i); +} + + +/*Returns the position of the first frame of type 'type' in resource 'r', + *starting from the frame starting at 'start', or -1 on failure. + */ +static int find_frame(resource_t* r, int type, unsigned int start) { + int t = -1; + unsigned int pos = start; + unsigned char* frame; + + assert(start <= r->size - 4); + +#ifdef SCRIPT_DEBUG + printf("Searching for frame of type %d in script %03d, starting at %#x\n", type, r->number, start); + dump(r->data + start, 32); +#endif + + /*Some times there's an extra byte at the beginning. Christoph?*/ +#if 1 + if (pos == 0 && r->size >= 6 && \ + !((0 < getInt16(r->data)) && (10 > getInt16(r->data)))) pos = 2; +#else + if (pos == 0) + pos = 2; +#endif + frame = r->data + pos; + while (1) { +#ifdef SCRIPT_DEBUG + printf("offset = %#x\n", pos); + dump(frame, 32); +#endif + t = get_type(frame); + if (t == type) + break; + + if (t == 0) + return -1; + + pos += get_length(frame); + if (pos > (r->size - 2)) + return -1; + frame += get_length(frame); + } + + return pos; +} + + + +/*FIXME: lots of things are identical to read_object and read_class. Some of + *these would benefit from being put in separate functions.*/ + +static object* read_object(resource_mgr_t *resmgr, int script, int positions[1000]) { + resource_t* r = scir_find_resource(resmgr, sci_script, script, 0); + unsigned char* raw; + int pos; + object* obj; + + printf("Searching for object in script %03d\n", script); + + if (r == 0) return 0; + + /*Skip to the next object*/ +#ifdef SCRIPT_DEBUG + printf("pre skip: pos=%#x\n", positions[script]); +#endif + pos = find_frame(r, 1, positions[script]); +#ifdef SCRIPT_DEBUG + printf("post skip: pos=%#x\n", pos); +#endif + if (pos == -1) return 0; + else positions[script] = pos + get_length(r->data + pos); +#ifdef SCRIPT_DEBUG + printf("post post: pos=%#x (len=%#x)\n", positions[script], get_length(r->data + pos)); +#endif + + /*Construct the object*/ + obj = object_new(); + raw = r->data + pos; + + /*Fill in the name*/ + if (get_selector_count(raw) < 4) obj->name = "<anonymous>"; + else { + if (get_selector_value(raw, 3)) + obj->name = (char *) r->data + get_selector_value(raw, 3); + else obj->name = "<null>"; + } + + /*Fill in the class*/ + if (get_selector_count(raw) == 0) obj->parent = object_root; + else { + int parent_id = get_selector_value(raw, 1); + if (parent_id >= fobjects.used) { + free(obj); + return 0; + } + if (parent_id < 1) obj->parent = object_root; + else obj->parent = fobjects.data[parent_id]; + } + + /*Add the object to the class*/ + if (!obj->parent) { + free(obj); + return 0; + } + if (add_child(obj->parent, obj)) { + free(obj); + return 0; + } + if (add_object(obj)) { + free(obj); + return 0; + } + + /*FIXME: decode selectors here*/ + + obj->method_count = get_method_count(raw); + obj->methods = (script_method**)sci_malloc(obj->method_count * sizeof(script_method)); + if (obj->methods == 0) { + free(obj); + return 0; + } else { + int i; + for (i = 0; i < obj->method_count; i++) { + int number = get_method_number(raw, i); + int position = get_method_location(raw, i); + + if ((obj->methods[i] = decode_method(r->data + position)) == 0) { + obj->method_count = i - 1; + break; + } + obj->methods[i]->number = number; + } + } + + return obj; +} + +static object* read_class(resource_mgr_t *resmgr, int script, int positions[1000]) { + resource_t* r = scir_find_resource(resmgr, sci_script, script, 0); + unsigned char* raw; + int pos; + object* obj; + + printf("Searching for class in script %03d\n", script); + + if (r == 0) return fake_object("<resource not found>"); + + /*Skip to the next class*/ +#ifdef SCRIPT_DEBUG + printf("pre skip: pos=%#x\n", positions[script]); +#endif + pos = find_frame(r, 6, positions[script]); +#ifdef SCRIPT_DEBUG + printf("post skip: pos=%#x\n", pos); +#endif + if (pos == -1) return fake_object("<no more classes in script>"); + else positions[script] = pos + get_length(r->data + pos); +#ifdef SCRIPT_DEBUG + printf("post post: pos=%#x (len=%#x)\n", positions[script], get_length(r->data + pos)); +#endif + + /*Construct the object*/ + obj = object_new(); + raw = r->data + pos; + + /*Fill in the name*/ + if (get_selector_count(raw) < 4) obj->name = "<anonymous>"; + else { + if (get_selector_value(raw, 3)) + obj->name = (char *) r->data + get_selector_value(raw, 3); + else obj->name = "<null>"; + } + + /*Fill in the parent*/ + if (get_selector_count(raw) == 0) obj->parent = object_root; + else { + int superclass_id = get_selector_value(raw, 1); + printf("superclass==%d\n", superclass_id); + if (superclass_id >= fobjects.used) { + free(obj); + return fake_object("<no such superclass>"); + } + if (superclass_id < 1) obj->parent = object_root; + else obj->parent = fobjects.data[superclass_id]; + } + + /*Add the class to the hierarchy*/ + if (!obj->parent) { + free(obj); + return fake_object("<null parent>"); + } + if (add_child(obj->parent, obj)) { + free(obj); + return fake_object("<add_child failed>"); + } + if (add_object(obj)) { + free(obj); + return fake_object("<add_object failed>"); + } + + /*FIXME: decode selectors and methods here*/ + + return obj; +} + +void freeObject(object* obj) { + int i; + for (i = 0; i < obj->children.used; i++) freeObject(obj->children.data[i]); + free(obj); +} + +static int objects_init(resource_mgr_t *resmgr) { + FLEXARRAY_INIT(object*, fobjects); + max_object = 0; + + if ((object_root = object_new()) == 0) return 1; + object_root->name = "<root>"; + add_object(object_root); + + opcodes = vocabulary_get_opcodes(resmgr); + knames = vocabulary_get_knames(resmgr, &knames_count); + snames = vocabulary_get_snames(resmgr, NULL, 0); + + return 0; +} + +int loadObjects(resource_mgr_t *resmgr) { + int i; + int *classes, class_count; + int positions[1000]; + + if (objects_init(resmgr)) { +#ifdef SCRIPT_DEBUG + perror("objects_init"); +#endif + return 1; + } + classes = vocabulary_get_classes(resmgr, &class_count); + + for (i = 0; i < 1000; i++) positions[i] = 0; + for (i = 0; i < class_count; i++) { +#ifdef SCRIPT_DEBUG + printf("\n\nReading class 0x%02X\n", i); +#endif + if (read_class(resmgr, classes[i], positions) == 0) { +#ifdef SCRIPT_DEBUG + fprintf(stderr, "Failed to load class %d, which is a parent.\n", i); +#endif + return 1; + } + } + + for (i = 0; i < 1000; i++) positions[i] = 0; + for (i = 0; i < 1000; i++) while (read_object(resmgr, i, positions)); + + object_map = fobjects.data; + max_object = fobjects.used; + + return 0; +} + + diff --git a/tools/sci/old_objects.h b/tools/sci/old_objects.h new file mode 100644 index 0000000000..fe653a7d3c --- /dev/null +++ b/tools/sci/old_objects.h @@ -0,0 +1,72 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef OLD_OBJECTS_H +#define OLD_OBJECTS_H + +#include "common/scummsys.h" +#include "engine/sci/include/sciresource.h" +#include "engine/sci/include/util.h" + +typedef FLEXARRAY(script_opcode, int number;) script_method; + +typedef struct object_ { + /*These are based on cached selector values, and set to the values + *the selectors had at load time. If the selectors are changed in + *instances, inconsistency will follow*/ + struct object_* parent; + const char* name; + + FLEXARRAY_NOEXTRA(struct object_*) children; + + /*No flexarray, size the size is known from the start*/ + script_method** methods; + int method_count; + + int selector_count; + int* selector_numbers; +} object; + +typedef struct { + int id; + object* classID; + byte* heap; + int offset; +} instance; + +extern object **object_map, *object_root; +extern int max_object; + +#define SCRIPT_PRINT_METHODS 1 +#define SCRIPT_PRINT_CHILDREN 2 +#define SCRIPT_PRINT_SELECTORS 3 +void printObject(object* obj, int flags); + +int loadObjects(resource_mgr_t *resmgr); +void freeObject(object*); + +extern const char* globals[]; + +#endif diff --git a/tools/sci/scidisasm.cpp b/tools/sci/scidisasm.cpp new file mode 100644 index 0000000000..39ea7f9c41 --- /dev/null +++ b/tools/sci/scidisasm.cpp @@ -0,0 +1,987 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ + +#define MALLOC_DEBUG + +#include <sciresource.h> +#include <engine.h> +#include <console.h> +#include <versions.h> + +#ifdef HAVE_GETOPT_H +#include <getopt.h> +#endif /* HAVE_GETOPT_H */ + +static int hexdump = 0; +static int opcode_size = 0; +static int verbose = 0; + +static resource_mgr_t *resmgr; + +#ifdef HAVE_GETOPT_LONG +static struct option options[] = { + {"version", no_argument, 0, 256}, + {"help", no_argument, 0, 'h'}, + {"hexdump", no_argument, &hexdump, 1}, + {"opcode-size", no_argument, &opcode_size, 1}, + {"verbose", no_argument, &verbose, 1}, + {"gamedir", required_argument, 0, 'd'}, + {0, 0, 0, 0} +}; +#endif /* HAVE_GETOPT_LONG */ + +#define SCI_ASSUME_VERSION SCI_VERSION_FTU_NEW_SCRIPT_HEADER + +typedef struct name_s { + int offset; + char *name; + int class_no; + struct name_s *next; +} name_t; + +typedef struct area_s { + int start_offset; + int end_offset; + void *data; + struct area_s *next; +} area_t; + +enum area_type { area_said, area_string, area_object, area_last }; + +typedef struct script_state_s { + int script_no; + name_t *names; + area_t *areas [area_last]; + + struct script_state_s *next; +} script_state_t; + +typedef struct disasm_state_s { + char **snames; + int selector_count; + opcode *opcodes; + int kernel_names_nr; + char **kernel_names; + word_t **words; + int word_count; + + char **class_names; + int *class_selector_count; + short **class_selectors; + int class_count; + int old_header; + + script_state_t *scripts; +} disasm_state_t; + +void +disassemble_script(disasm_state_t *d, int res_no, int pass_no); + +script_state_t * +find_script_state(disasm_state_t *d, int script_no); + +void +script_free_names(script_state_t *s); + +void +script_add_name(script_state_t *s, int aoffset, char *aname, int aclass_no); + +char * +script_find_name(script_state_t *s, int offset, int *class_no); + +void +script_add_area(script_state_t *s, int start_offset, int end_offset, int type, void *data); + +void +script_free_areas(script_state_t *s); + +int +script_get_area_type(script_state_t *s, int offset, void **pdata); + +void +disasm_init(disasm_state_t *d); + +void +disasm_free_state(disasm_state_t *d); + +int main(int argc, char** argv) { + int i; + char outfilename [256]; + int optindex = 0; + int c; + disasm_state_t disasm_state; + char *gamedir = NULL; + int res_version = SCI_VERSION_AUTODETECT; + +#ifdef HAVE_GETOPT_LONG + while ((c = getopt_long(argc, argv, "vhxr:d:", options, &optindex)) > -1) { +#else /* !HAVE_GETOPT_H */ + while ((c = getopt(argc, argv, "vhxr:d:")) > -1) { +#endif /* !HAVE_GETOPT_H */ + + switch (c) { + case 256: + printf("scidisasm ("PACKAGE") "VERSION"\n"); + printf("This program is copyright (C) 1999 Christoph Reichenbach.\n" + "It comes WITHOUT WARRANTY of any kind.\n" + "This is free software, released under the GNU General Public License.\n"); + exit(0); + + case 'h': + printf("Usage: scidisasm\n" + "\nAvailable options:\n" + " --version Prints the version number\n" + " --help -h Displays this help message\n" + " --gamedir <dir> -d<dir> Read game resources from dir\n" + " --hexdump -x Hex dump all script resources\n" + " --verbose Print additional disassembly information\n" + " --opcode-size Print opcode size postfixes\n"); + exit(0); + + case 'd': + if (gamedir) sci_free(gamedir); + gamedir = sci_strdup(optarg); + break; + + case 'r': + res_version = atoi(optarg); + break; + + case 0: /* getopt_long already did this for us */ + case '?': + /* getopt_long already printed an error message. */ + break; + + default: + return -1; + } + } + + if (gamedir) + if (chdir(gamedir)) { + printf("Error changing to game directory '%s'\n", gamedir); + exit(1); + } + + printf("Loading resources...\n"); + if (!(resmgr = scir_new_resource_manager(sci_getcwd(), res_version, + 1, 1024 * 128))) { + fprintf(stderr, "Could not find any resources; quitting.\n"); + exit(1); + } + + disasm_init(&disasm_state); + + script_adjust_opcode_formats(resmgr->sci_version); + + printf("Performing first pass...\n"); + for (i = 0; i < resmgr->resources_nr; i++) + if (resmgr->resources[i].type == sci_script) + disassemble_script(&disasm_state, + resmgr->resources[i].number, 1); + + printf("Performing second pass...\n"); + for (i = 0; i < resmgr->resources_nr; i++) + if (resmgr->resources[i].type == sci_script) { + sprintf(outfilename, "%03d.script", + resmgr->resources[i].number); + open_console_file(outfilename); + disassemble_script(&disasm_state, + resmgr->resources[i].number, 2); + } + + close_console_file(); + disasm_free_state(&disasm_state); + + free(resmgr->resource_path); + scir_free_resource_manager(resmgr); + return 0; +} + +/* -- General operations on disasm_state_t ------------------------------- */ + +void +disasm_init(disasm_state_t *d) { + d->snames = vocabulary_get_snames(resmgr, &d->selector_count, SCI_ASSUME_VERSION); + d->opcodes = vocabulary_get_opcodes(resmgr); + d->kernel_names = vocabulary_get_knames(resmgr, &d->kernel_names_nr); + d->words = vocab_get_words(resmgr, &d->word_count); + d->scripts = NULL; + d->old_header = 0; + + d->class_count = vocabulary_get_class_count(resmgr); + d->class_names = (char **) sci_malloc(d->class_count * sizeof(char *)); + memset(d->class_names, 0, d->class_count * sizeof(char *)); + d->class_selector_count = (int *) sci_malloc(d->class_count * sizeof(int)); + memset(d->class_selector_count, 0, d->class_count * sizeof(int)); + d->class_selectors = (short **) sci_malloc(d->class_count * sizeof(short *)); + memset(d->class_selectors, 0, d->class_count * sizeof(short *)); +} + +void +disasm_free_state(disasm_state_t *d) { + script_state_t *s, *next_script; + int i; + + s = d->scripts; + while (s) { + next_script = s->next; + script_free_names(s); + script_free_areas(s); + s = next_script; + } + + for (i = 0; i < d->class_count; i++) { + if (d->class_names [i]) sci_free(d->class_names [i]); + if (d->class_selectors [i]) sci_free(d->class_selectors [i]); + } + + free(d->class_names); + free(d->class_selectors); + free(d->class_selector_count); + + vocabulary_free_snames(d->snames); + vocabulary_free_opcodes(d->opcodes); + vocabulary_free_knames(d->kernel_names); + vocab_free_words(d->words, d->word_count); +} + +script_state_t * +find_script_state(disasm_state_t *d, int script_no) { + script_state_t *s; + + for (s = d->scripts; s; s = s->next) + if (s->script_no == script_no) return s; + + s = (script_state_t *) sci_malloc(sizeof(script_state_t)); + memset(s, 0, sizeof(script_state_t)); + s->script_no = script_no; + s->next = d->scripts; + + d->scripts = s; + return s; +} + +/* -- Name table operations ---------------------------------------------- */ + +void +script_free_names(script_state_t *s) { + name_t *p = s->names, *next_name; + + while (p) { + next_name = p->next; + free(p->name); + free(p); + p = next_name; + } + + s->names = NULL; +} + +void +script_add_name(script_state_t *s, int aoffset, char *aname, int aclass_no) { + name_t *p; + char *name = script_find_name(s, aoffset, NULL); + if (name) return; + + p = (name_t *) sci_malloc(sizeof(name_t)); + p->offset = aoffset; + p->name = sci_strdup(aname); + p->class_no = aclass_no; + p->next = s->names; + s->names = p; +} + +char * +script_find_name(script_state_t *s, int offset, int *aclass_no) { + name_t *p; + + for (p = s->names; p; p = p->next) + if (p->offset == offset) { + if (aclass_no && p->class_no != -2) *aclass_no = p->class_no; + return p->name; + } + + return NULL; +} + +/* -- Area table operations ---------------------------------------------- */ + +void +script_add_area(script_state_t *s, int start_offset, int end_offset, int type, void *data) { + area_t *area; + + area = (area_t *) sci_malloc(sizeof(area_t)); + area->start_offset = start_offset; + area->end_offset = end_offset; + area->data = data; + area->next = s->areas [type]; + + s->areas [type] = area; +} + +void +script_free_areas(script_state_t *s) { + int i; + + for (i = 0; i < area_last; i++) { + area_t *area = s->areas [i], *next_area; + while (area) { + next_area = area->next; + free(area); + area = next_area; + } + } +} + +int +script_get_area_type(script_state_t *s, int offset, void **pdata) { + int i; + + for (i = 0; i < area_last; i++) { + area_t *area = s->areas [i]; + while (area) { + if (area->start_offset <= offset && area->end_offset >= offset) { + if (pdata != NULL) *pdata = area->data; + return i; + } + area = area->next; + } + } + + return -1; +} + +char * +get_selector_name(disasm_state_t *d, int selector) { + static char selector_name [256]; + + if (d->snames && selector >= 0 && selector < d->selector_count) + return d->snames [selector]; + else { + sprintf(selector_name, "unknown_sel_%X", selector); + return selector_name; + } +} + +const char * +get_class_name(disasm_state_t *d, int class_no) { + static char class_name [256]; + + if (class_no == -1) + return "<none>"; + else if (class_no >= 0 && class_no < d->class_count && d->class_names [class_no]) + return d->class_names [class_no]; + else { + sprintf(class_name, "class_%d", class_no); + return class_name; + } +} + +/* -- Code to dump individual script block types ------------------------- */ + +static void +script_dump_object(disasm_state_t *d, script_state_t *s, + unsigned char *data, int seeker, int objsize, int pass_no) { + int selectors, overloads, selectorsize; + int species = getInt16(data + 8 + seeker); + int superclass = getInt16(data + 10 + seeker); + int namepos = getInt16(data + 14 + seeker); + int i = 0; + short sel; + const char *name; + char buf [256]; + short *sels; + + selectors = (selectorsize = getInt16(data + seeker + 6)); + name = namepos ? ((const char *)data + namepos) : "<unknown>"; + + if (pass_no == 1) + script_add_area(s, seeker, seeker + objsize - 1, area_object, strdup(name)); + + if (pass_no == 2) { + sciprintf(".object\n"); + sciprintf("Name: %s\n", name); + sciprintf("Superclass: %s [%x]\n", get_class_name(d, superclass), superclass); + sciprintf("Species: %s [%x]\n", get_class_name(d, species), species); + + sciprintf("-info-:%x\n", getInt16(data + 12 + seeker) & 0xffff); + + sciprintf("Function area offset: %x\n", getInt16(data + seeker + 4)); + sciprintf("Selectors [%x]:\n", selectors); + } + + seeker += 8; + + if (species < d->class_count) + sels = d->class_selectors [species]; + else + sels = NULL; + + while (selectors--) { + if (pass_no == 2) { + sel = getInt16(data + seeker) & 0xffff; + if (sels && (sels [i] >= 0) && (sels[i] < d->selector_count)) { + sciprintf(" [#%03x] %s = 0x%x\n", i, d->snames [sels [i]], sel); + i++; + } else + sciprintf(" [#%03x] <unknown> = 0x%x\n", i++, sel); + } + + seeker += 2; + } + + selectors = overloads = getInt16(data + seeker); + + if (pass_no == 2) + sciprintf("Overloaded functions: %x\n", overloads); + + seeker += 2; + + while (overloads--) { + word selector = getInt16(data + (seeker)) & 0xffff; + if (d->old_header) selector >>= 1; + + if (pass_no == 1) { + sprintf(buf, "%s::%s", name, get_selector_name(d, selector)); + script_add_name(s, getInt16(data + seeker + selectors*2 + 2), buf, species); + } else { + sciprintf(" [%03x] %s: @", selector, get_selector_name(d, selector)); + sciprintf("%04x\n", getInt16(data + seeker + selectors*2 + 2)); + } + + seeker += 2; + } +} + +static void +script_dump_class(disasm_state_t *d, script_state_t *s, + unsigned char *data, int seeker, int objsize, int pass_no) { + word selectors, overloads, selectorsize; + int species = getInt16(data + 8 + seeker); + int superclass = getInt16(data + 10 + seeker); + int namepos = getInt16(data + 14 + seeker); + const char *name; + char buf [256]; + int i; + + name = namepos ? ((const char *)data + namepos) : "<unknown>"; + selectors = (selectorsize = getInt16(data + seeker + 6)); + + if (pass_no == 1) { + if (species >= 0 && species < d->class_count) { + if (!namepos) { + sprintf(buf, "class_%d", species); + d->class_names [species] = sci_strdup(buf); + } else + d->class_names [species] = sci_strdup(name); + + d->class_selector_count [species] = selectors; + d->class_selectors [species] = (short *) sci_malloc(sizeof(short) * selectors); + } + } + + if (pass_no == 2) { + sciprintf(".class\n"); + sciprintf("Name: %s\n", name); + sciprintf("Superclass: %s [%x]\n", get_class_name(d, superclass), superclass); + sciprintf("Species: %x\n", species); + sciprintf("-info-:%x\n", getInt16(data + 12 + seeker) & 0xffff); + + sciprintf("Function area offset: %x\n", getInt16(data + seeker + 4)); + sciprintf("Selectors [%x]:\n", selectors); + } + + seeker += 8; + selectorsize <<= 1; + + for (i = 0; i < selectors; i++) { + word selector = 0xffff & getInt16(data + (seeker) + selectorsize); + if (d->old_header) selector >>= 1; + + if (pass_no == 1) { + if (species >= 0 && species < d->class_count) + d->class_selectors [species][i] = selector; + } else + sciprintf(" [%03x] %s = 0x%x\n", selector, get_selector_name(d, selector), + getInt16(data + seeker) & 0xffff); + + seeker += 2; + } + + seeker += selectorsize; + + selectors = overloads = getInt16(data + seeker); + + sciprintf("Overloaded functions: %x\n", overloads); + + seeker += 2; + + while (overloads--) { + word selector = getInt16(data + (seeker)) & 0xffff; + if (d->old_header) selector >>= 1; + + if (pass_no == 1) { + sprintf(buf, "%s::%s", name, get_selector_name(d, selector)); + script_add_name(s, getInt16(data + seeker + selectors*2 + 2) & 0xffff, buf, species); + } else { + sciprintf(" [%03x] %s: @", selector & 0xffff, get_selector_name(d, selector)); + sciprintf("%04x\n", getInt16(data + seeker + selectors*2 + 2) & 0xffff); + } + + seeker += 2; + } +} + +static int +script_dump_said_string(disasm_state_t *d, unsigned char *data, int seeker) { + while (1) { + unsigned short nextitem = (unsigned char) data [seeker++]; + if (nextitem == 0xFF) return seeker; + + if (nextitem >= 0xF0) { + switch (nextitem) { + case 0xf0: + sciprintf(", "); + break; + case 0xf1: + sciprintf("& "); + break; + case 0xf2: + sciprintf("/ "); + break; + case 0xf3: + sciprintf("( "); + break; + case 0xf4: + sciprintf(") "); + break; + case 0xf5: + sciprintf("[ "); + break; + case 0xf6: + sciprintf("] "); + break; + case 0xf7: + sciprintf("# "); + break; + case 0xf8: + sciprintf("< "); + break; + case 0xf9: + sciprintf("> "); + break; + } + } else { + nextitem = nextitem << 8 | (unsigned char) data [seeker++]; + sciprintf("%s ", vocab_get_any_group_word(nextitem, d->words, d->word_count)); + if (verbose) + sciprintf("[%03x] ", nextitem); + } + } +} + +static void +script_dump_said(disasm_state_t *d, script_state_t *s, + unsigned char *data, int seeker, int objsize, int pass_no) { + int _seeker = seeker + objsize - 4; + + if (pass_no == 1) { + script_add_area(s, seeker, seeker + objsize - 1, area_said, NULL); + return; + } + + sciprintf(".said\n"); + + while (seeker < _seeker - 1) { + sciprintf("%04x: ", seeker); + seeker = script_dump_said_string(d, data, seeker); + sciprintf("\n"); + } +} + +static void +script_dump_synonyms(disasm_state_t *d, script_state_t *s, + unsigned char *data, int seeker, int objsize, int pass_no) { + int _seeker = seeker + objsize - 4; + + sciprintf("Synonyms:\n"); + while (seeker < _seeker) { + int search = getInt16(data + seeker); + int replace = getInt16(data + seeker + 2); + seeker += 4; + if (search < 0) break; + sciprintf("%s[%03x] ==> %s[%03x]\n", + vocab_get_any_group_word(search, d->words, d->word_count), search, + vocab_get_any_group_word(replace, d->words, d->word_count), replace); + } +} + +static void +script_dump_strings(disasm_state_t *d, script_state_t *s, + unsigned char *data, int seeker, int objsize, int pass_no) { + int endptr = seeker + objsize - 4; + + if (pass_no == 1) { + script_add_area(s, seeker, seeker + objsize - 1, area_string, NULL); + return; + } + + sciprintf(".strings\n"); + while (data [seeker] && seeker < endptr) { + sciprintf("%04x: %s\n", seeker, data + seeker); + seeker += strlen((char *) data + seeker) + 1; + } +} + +static void +script_dump_exports(disasm_state_t *d, script_state_t *s, + unsigned char *data, int seeker, int objsize, int pass_no) { + byte *pexport = (byte *)(data + seeker); + word export_count = getUInt16(pexport); + int i; + char buf [256]; + + pexport += 2; + + if (pass_no == 2) sciprintf(".exports\n"); + + for (i = 0; i < export_count; i++) { + if (pass_no == 1) { + guint16 offset = getUInt16(pexport); + sprintf(buf, "exp_%02X", i); + script_add_name(s, offset, buf, -1); + } else + sciprintf("%02X: %04X\n", i, *pexport); + pexport += 2; + } +} + +/* -- The disassembly code ----------------------------------------------- */ + +static void +script_disassemble_code(disasm_state_t *d, script_state_t *s, + unsigned char *data, int seeker, int objsize, int pass_no) { + int endptr = seeker + objsize - 4; + int i = 0; + int cur_class = -1; + word dest; + void *area_data; + char buf [256]; + char *dest_name; + + if (pass_no == 2) sciprintf(".code\n"); + + while (seeker < endptr - 1) { + unsigned char opsize = data [seeker]; + unsigned char opcode = opsize >> 1; + word param_value; + char *name; + + opsize &= 1; /* byte if true, word if false */ + + if (pass_no == 2) { + name = script_find_name(s, seeker, &cur_class); + if (name) sciprintf(" %s:\n", name); + sciprintf("%04X: ", seeker); + sciprintf("%s", d->opcodes[opcode].name); + if (opcode_size && formats[opcode][0]) + sciprintf(".%c", opsize ? 'b' : 'w'); + sciprintf("\t"); + } + + seeker++; + + for (i = 0; formats[opcode][i]; i++) + + switch (formats[opcode][i]) { + + case Script_Invalid: + if (pass_no == 2) sciprintf("-Invalid operation-"); + break; + + case Script_SByte: + case Script_Byte: + if (pass_no == 2) sciprintf(" %02x", data[seeker]); + seeker++; + break; + + case Script_Word: + case Script_SWord: + if (pass_no == 2) + sciprintf(" %04x", 0xffff & (data[seeker] | (data[seeker+1] << 8))); + seeker += 2; + break; + + case Script_SVariable: + case Script_Variable: + case Script_Global: + case Script_Local: + case Script_Temp: + case Script_Param: + case Script_SRelative: + case Script_Property: + case Script_Offset: + if (opsize) + param_value = data [seeker++]; + else { + param_value = 0xffff & (data[seeker] | (data[seeker+1] << 8)); + seeker += 2; + } + + if (pass_no == 1) { + if (opcode == op_jmp || opcode == op_bt || opcode == op_bnt) { + dest = seeker + (short) param_value; + sprintf(buf, "lbl_%04X", dest); + script_add_name(s, dest, buf, -2); + } + } else if (pass_no == 2) + switch (formats[opcode][i]) { + + case Script_SVariable: + case Script_Variable: + if (opcode == op_callk) { + sciprintf(" #%s", (param_value < d->kernel_names_nr) + ? d->kernel_names[param_value] : "<invalid>"); + if (verbose) sciprintf("[%x]", param_value); + } else if (opcode == op_class || (opcode == op_super && i == 0)) { + sciprintf(" %s", (d->class_names && param_value < d->class_count) + ? d->class_names[param_value] : "<invalid>"); + if (verbose) sciprintf("[%x]", param_value); + } else sciprintf(opsize ? " %02x" : " %04x", param_value); + + if (opcode == op_pushi && param_value > 0 && param_value < d->selector_count) + sciprintf("\t\t; selector <%s>", d->snames [param_value]); + + break; + + case Script_Global: + sciprintf(" global_%d", param_value); + break; + + case Script_Local: + sciprintf(" local_%d", param_value); + break; + + case Script_Temp: + sciprintf(" temp_%d", param_value); + break; + + case Script_Param: + sciprintf(" param_%d", param_value); + break; + + case Script_Offset: + dest = (short) param_value; + dest_name = script_find_name(s, dest, NULL); + if (dest_name) + sciprintf(" %s", dest_name); + else + sciprintf(" %04x", dest); + + if (verbose) + sciprintf(opsize ? " [%02x] " : " [%04x] ", param_value); + + if (opcode == op_lofsa || opcode == op_lofss) { + int atype = script_get_area_type(s, dest, &area_data); + if (atype == area_string) { + strncpy(buf, (char *) &data [dest], sizeof(buf) - 1); + buf [sizeof(buf)-1] = 0; + if (strlen(buf) > 40) { + buf [40] = 0; + strcat(buf, "..."); + } + sciprintf("\t\t; \"%s\"", buf); + } else if (atype == area_said) { + sciprintf("\t\t; said \""); + script_dump_said_string(d, data, dest); + sciprintf("\"\n"); + } else if (atype == area_object) + sciprintf("\t\t; object <%s>", area_data); + } + break; + + case Script_SRelative: + dest = seeker + (short) param_value; + dest_name = script_find_name(s, dest, NULL); + if (dest_name) + sciprintf(" %s", dest_name); + else + sciprintf(" %04x", dest); + + if (verbose) + sciprintf(opsize ? " [%02x] " : " [%04x] ", param_value); + + if (opcode == op_lofsa || opcode == op_lofss) { + int atype = script_get_area_type(s, dest, &area_data); + if (atype == area_string) { + strncpy(buf, (char *) &data [dest], sizeof(buf) - 1); + buf [sizeof(buf)-1] = 0; + if (strlen(buf) > 40) { + buf [40] = 0; + strcat(buf, "..."); + } + sciprintf("\t\t; \"%s\"", buf); + } else if (atype == area_said) { + sciprintf("\t\t; said \""); + script_dump_said_string(d, data, dest); + sciprintf("\"\n"); + } else if (atype == area_object) + sciprintf("\t\t; object <%s>", area_data); + } + break; + + case Script_Property: + if (cur_class != -1 && param_value / 2 < d->class_selector_count [cur_class]) { + sciprintf(" %s", get_selector_name(d, d->class_selectors [cur_class][param_value/2])); + if (verbose) sciprintf("[%x]", param_value); + } else + sciprintf(opsize ? " %02x" : " %04x", param_value); + + break; + + case Script_End: + if (pass_no == 2) sciprintf("\n"); + break; + + default: + sciprintf("Unexpected opcode format %d\n", (formats[opcode][i])); + } + + default: + break; + } + if (pass_no == 2) sciprintf("\n"); + + } + +} + +void +disassemble_script_pass(disasm_state_t *d, script_state_t *s, + resource_t *script, int pass_no) { + int _seeker = 0; + word id = getInt16(script->data); + + if (id > 15) { + if (pass_no == 2) sciprintf("; Old script header detected\n"); + d->old_header = 1; + } + + if (d->old_header) _seeker = 2; + + while (_seeker < script->size) { + int objtype = getInt16(script->data + _seeker); + int objsize; + int seeker = _seeker + 4; + + if (!objtype) return; + + if (pass_no == 2) + sciprintf("\n"); + + objsize = getInt16(script->data + _seeker + 2); + + if (pass_no == 2) { + sciprintf("; Obj type #%x, offset 0x%x, size 0x%x:\n", objtype, _seeker, objsize); + if (hexdump) sci_hexdump(script->data + seeker, objsize - 4, seeker); + } + + _seeker += objsize; + + switch (objtype) { + case sci_obj_object: + script_dump_object(d, s, script->data, seeker, objsize, pass_no); + break; + + case sci_obj_code: + script_disassemble_code(d, s, script->data, seeker, objsize, pass_no); + break; + + case sci_obj_synonyms: + script_dump_synonyms(d, s, script->data, seeker, objsize, pass_no); + break; + + case sci_obj_said: + script_dump_said(d, s, script->data, seeker, objsize, pass_no); + break; + + case sci_obj_strings: + script_dump_strings(d, s, script->data, seeker, objsize, pass_no); + break; + + case sci_obj_class: + script_dump_class(d, s, script->data, seeker, objsize, pass_no); + break; + + case sci_obj_exports: + script_dump_exports(d, s, script->data, seeker, objsize, pass_no); + break; + + case sci_obj_pointers: + if (pass_no == 2) { + sciprintf("Pointers\n"); + sci_hexdump(script->data + seeker, objsize - 4, seeker); + }; + break; + + case sci_obj_preload_text: + if (pass_no == 2) { + sciprintf("The script has a preloaded text resource\n"); + }; + break; + + case sci_obj_localvars: + if (pass_no == 2) { + sciprintf("Local vars\n"); + sci_hexdump(script->data + seeker, objsize - 4, seeker); + }; + break; + + default: + sciprintf("Unsupported %d!\n", objtype); + return; + } + } + + sciprintf("Script ends without terminator\n"); +} + +void +disassemble_script(disasm_state_t *d, int res_no, int pass_no) { + resource_t *script = scir_find_resource(resmgr, sci_script, res_no, 0); + script_state_t *s = find_script_state(d, res_no); + + if (!script) { + sciprintf("Script not found!\n"); + return; + } + + disassemble_script_pass(d, s, script, pass_no); +} diff --git a/tools/sci/scipack.cpp b/tools/sci/scipack.cpp new file mode 100644 index 0000000000..f70d91fabc --- /dev/null +++ b/tools/sci/scipack.cpp @@ -0,0 +1,208 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sciresource.h> +#include <resource.h> +#include <sys/types.h> +#include <sys/stat.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#define COPY_BLOCK_SIZE 512 + +unsigned short *resource_ids = NULL; + +void +help() { + printf("Usage:\n\tscipack <file_0> ... <file_n>\n" + "\nBuilds an uncompressed SCI0 resource.000 and a resource.map\n"); +} + +int /* Returns resource ID on success, -1 on error */ +test_file(char *filename) { + char *dot = strchr(filename, '.'); + char *endptr; + FILE *f; + int res_type, res_index; + + if (!dot) { + fprintf(stderr, "Must contain a period"); + return -1; + } + + *dot = 0; + + for (res_type = 0; res_type < sci_invalid_resource + && scumm_stricmp(filename, sci_resource_types[res_type]); res_type++); + + *dot = '.'; + + if (res_type == sci_invalid_resource) { + fprintf(stderr, "Invalid resource type"); + return -1; + } + + ++dot; + res_index = strtol(dot, &endptr, 10); + + if (!*dot || *endptr) { + fprintf(stderr, "Invalid resource index"); + return -1; + } + + if (res_index < 0) { + fprintf(stderr, "Negative resource index"); + return -1; + } + + if (res_index >= 1000) { + fprintf(stderr, "Resource index too large"); + return -1; + } + + f = fopen(filename, "r"); + if (!f) { + perror("While asserting file"); + return -1; + } + fclose(f); + + return (res_type << 11) | res_index; +} + +int +build_file_ids(int count, char **names) { + int i; + int error = 0; + + resource_ids = (unsigned short*) malloc(sizeof(unsigned short) * count); + + for (i = 0; i < count; i++) { + int id = test_file(names[i]); + if (id < 0) { + error = -1; + fprintf(stderr, ": %s\n", names[i]); + } else resource_ids[i] = id; + } + + return error; +} + + +static inline void +write_uint16(int fd, unsigned int uint) { + unsigned char upper = (uint >> 8) & 0xff; + unsigned char lower = (uint) & 0xff; + + if ((write(fd, &upper, 1) < 1) + || (write(fd, &lower, 1) < 1)) { + perror("While writing"); + exit(1); + } +} + +int +write_files(int count, char **names) { + int resource_000, resource_map; + int i; + + resource_000 = creat("resource.000", 0644); + if (resource_000 < 0) { + perror("While creating 'resource.000'"); + return -1; + } + + resource_map = creat("resource.map", 0644); + if (resource_map < 0) { + perror("While creating 'resource.map'"); + return -1; + } + + for (i = 0; i < count; i++) { + int fd = open(names[i], O_RDONLY); + struct stat fdstat; + int fdsize; + unsigned char buf[512]; + int j; + long offset = lseek(resource_000, SEEK_CUR, 0); + int top_offset = (offset >> 16) & 0xffff; + int bot_offset = offset & 0xffff; + + if (fd < 0) { + perror(names[i]); + return -1; + } + fstat(fd, &fdstat); + fdsize = fdstat.st_size; + + write_uint16(resource_000, resource_ids[i]); + write_uint16(resource_000, fdsize); + write_uint16(resource_000, fdsize); + write_uint16(resource_000, 0); + + do { + j = read(fd, buf, COPY_BLOCK_SIZE); + write(resource_000, buf, j); + } while (j == COPY_BLOCK_SIZE); + close(fd); + + write_uint16(resource_map, resource_ids[i]); + write_uint16(resource_map, bot_offset); + write_uint16(resource_map, top_offset); + } + + /* Terminate resource 000 */ + write_uint16(resource_000, 0); + + /* Terminate resource map */ + write_uint16(resource_map, 0xffff); + write_uint16(resource_map, 0xffff); + + close(resource_000); + close(resource_map); +} + + +int +main(int argc, char **argv) { + printf("scipack.c Copyright (C) 2002 Christoph Reichenbach\n" + "This program is FREE SOFTWARE. You may copy it and/or re-distribute it\n" + "according to the terms of the GNU General Public License. See LICENSING\n" + "for details.\n"); + + if (argc < 1) + help(); + + if (build_file_ids(argc - 1, argv + 1)) + return -1; + + if (write_files(argc - 1, argv + 1)) + return -1; + free(resource_ids); +} diff --git a/tools/sci/sciunpack.cpp b/tools/sci/sciunpack.cpp new file mode 100644 index 0000000000..c9c50dc38b --- /dev/null +++ b/tools/sci/sciunpack.cpp @@ -0,0 +1,473 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif /* HAVE_CONFIG_H */ + +#include "sciunpack.h" + +#include <sciresource.h> +#include <engine.h> +#include <console.h> + +/* #define DRAW_GRAPHICS */ + +#undef HAVE_OBSTACK_H + +#ifdef _MSC_VER +# include <direct.h> +# define extern __declspec(dllimport) extern +#endif + +#ifdef HAVE_GETOPT_H +# ifndef WIN32 +# include <getopt.h> +# else +# include <win32/getopt.h> +# endif +#endif /* HAVE_GETOPT_H */ + +#ifdef DRAW_GRAPHICS +# ifdef HAVE_LIBPNG +# include "graphics_png.h" +# endif /* HAVE_LIBPNG */ +#endif /* DRAW_GRAPHICS */ + +#if defined (_MSC_VER) || defined (__BEOS__) || defined(__amigaos4__) +/* [DJ] fchmod is not in Visual C++ RTL - and probably not needed,anyway */ +/* [RS] (see comment above, but read MS-DOS instead of Visual C++ RTL) */ +# define fchmod(file,mode) +# define CREAT_OPTIONS O_BINARY +#endif + +#ifndef CREAT_OPTIONS +# define CREAT_OPTIONS 0x640 +#endif + + +#define ACT_UNPACK 0 +#define ACT_WORDS 1 +#define ACT_LIST 2 +#define ACT_SCRIPTDUMP 3 +#define ACT_VOCABDUMP 4 + +#define ACT_DEFAULT ACT_UNPACK + +static int conversion = 0; +static int list = 0; +static int verbose = 0; +static int with_header = 1; +static int color_mode = 0; +static int action = ACT_DEFAULT; +static guint8 midimask = 0x01; /* MT-32 */ + +resource_mgr_t *resmgr; + +#ifdef WIN32 +#define fchmod(arg1, arg2) +#endif + +void +print_resource_filename(FILE* file, int type, int number) { + if (resmgr->sci_version < SCI_VERSION_1) + fprintf(file, "%s.%03d", sci_resource_types[type], number); + else + fprintf(file, "%d.%s", number, sci_resource_type_suffixes[type]); +} + +void +sprint_resource_filename(char* buf, int type, int number) { + if (resmgr->sci_version < SCI_VERSION_1) + sprintf(buf, "%s.%03d", sci_resource_types[type], number); + else + sprintf(buf, "%d.%s", number, sci_resource_type_suffixes[type]); +} + +#ifdef HAVE_GETOPT_LONG +static struct option options[] = { + {"conversion", no_argument, &conversion, 1}, + {"version", no_argument, 0, 256}, + {"verbose", no_argument, &verbose, 1}, + {"help", no_argument, 0, 'h'}, + {"output-file", required_argument, 0, 'o'}, + {"unpack", no_argument, &action, ACT_UNPACK}, + {"list", no_argument, &action, ACT_LIST}, + {"words", no_argument, &action, ACT_WORDS}, + {"vocab", no_argument, &action, ACT_VOCABDUMP}, + {"objects", no_argument, &action, ACT_SCRIPTDUMP}, + {"with-header", no_argument, &with_header, 1}, + {"without-header", no_argument, &with_header, 0}, + {"sort-alpha", no_argument, &vocab_sort, SORT_METHOD_ALPHA}, + {"sort-group", no_argument, &vocab_sort, SORT_METHOD_GROUP}, +#ifdef DRAW_GRAPHICS + {"palette-dither", no_argument, &color_mode, SCI_COLOR_DITHER}, + {"palette-interpolate", no_argument, &color_mode, SCI_COLOR_INTERPOLATE}, + {"palette-dither256", no_argument, &color_mode, SCI_COLOR_DITHER256}, +#endif /* DRAW_GRAPHICS */ + {"gamedir", required_argument, 0, 'd'}, + {"midimask", required_argument, 0, 'M'}, + {0, 0, 0, 0} +}; + +#endif /* HAVE_GETOPT_LONG */ + + +void unpack_resource(int stype, int snr, char *outfilename); + + +int main(int argc, char** argv) { + int retval = 0; + int i; + int stype = -1; + int snr; + char *resourcenumber_string = 0; + char *outfilename = 0; + int optindex = 0; + int c; + char *gamedir = sci_getcwd(); + int res_version = SCI_VERSION_AUTODETECT; + +#ifdef HAVE_GETOPT_LONG + while ((c = getopt_long(argc, argv, "WOVUvhLcr:o:d:M:", options, &optindex)) > -1) { +#else /* !HAVE_GETOPT_LONG */ + while ((c = getopt(argc, argv, "WOVUvhLcr:o:d:M:")) > -1) { +#endif /* !HAVE_GETOPT_LONG */ + + switch (c) { + case 256: + printf("sciunpack ("PACKAGE") "VERSION"\n"); + printf("This program is copyright (C) 1999, 2000, 2001 Christoph Reichenbach,\n" + " Lars Skovlund, Magnus Reftel\n" + "It comes WITHOUT WARRANTY of any kind.\n" + "This is free software, released under the GNU General Public License.\n"); + exit(0); + + case 'h': { + char *gcc_3_0_can_kiss_my_ass = + "Usage: sciunpack [options] [-U] <resource.number>\n" + " sciunpack [options] [-U] <resource> <number>\n" + "Unpacks resource data\n" + "If * is specified instead of <number>, \n" + "all resources of given type will be unpacked.\n\n" + " sciunpack [options] -W\n" + "Lists vocabulary words\n\n" + " sciunpack [options] -O\n" + "Dumps the complete object hierarchy\n\n" + " sciunpack [options] -V\n" + "Prints selector names, opcodes, kernel names, and classes\n\n" + "\nAvalable operations:\n" + " --unpack -U Decompress resource\n" + " --list -L List all resources\n" + " --words -W List all vocabulary words\n" + " --objects -O Print all objects\n" + " --vocab -V Lists the complete vocabulary\n" + "\nAvailable options:\n" + "General:\n" + " --version Prints the version number\n" + " --verbose -v Enables additional output\n" + " --help -h Displays this help message\n" + " --midimask -M What 'play mask' to use. Defaults to MT-32 (0x01)\n" + + "Listing words:\n" + " --sort-alpha sort in alphabetical order\n" + " --sort-group sort in group order\n" + "Unpacking:\n" + " --convert -c Converts selected resources\n" + " --output-file -o Selects output file\n" + " --gamedir -d Read game resources from dir\n" + " --with-header Forces the SCI header to be written (default)\n" + " --without-header Prevents the two SCI header bytes from being written\n" +#ifdef DRAW_GRAPHICS + " --palette-dither Forces colors in 16 color games to be dithered\n" + " --palette-interpolate Does color interpolation when drawing picture resources\n" + " --palette-dither256 Does dithering in 256 colors\n" +#endif /* DRAW_GRAPHICS */ + "\nAs a default, 'resource.number' is the output filename.\n" + "If conversion is enabled, the following resources will be treated specially:\n" + " sound resources: Will be converted to MIDI, stored in <number>.midi\n" + " script resources: Will be dissected and stored in <number>.script\n" +#ifdef DRAW_GRAPHICS + " picture resources: Will be converted to PNG, stored in <number>.png\n" + +#endif /* DRAW_GRAPHICS */ + ; + + printf(gcc_3_0_can_kiss_my_ass); + exit(0); + } + + case 'v': + verbose = 1; + break; + + case 'L': + action = ACT_LIST; + break; + + case 'W': + action = ACT_WORDS; + break; + + case 'V': + action = ACT_VOCABDUMP; + break; + + case 'O': + action = ACT_SCRIPTDUMP; + break; + + case 'o': + outfilename = optarg; + break; + + case 'd': + if (gamedir) sci_free(gamedir); + gamedir = sci_strdup(optarg); + break; + + case 'r': + res_version = atoi(optarg); + break; + + case 'c': + conversion = 1; + break; + + case 'M': + midimask = (guint8) strtol(optarg, NULL, 0); + break; + + case 0: /* getopt_long already did this for us */ + case '?': + /* getopt_long already printed an error message. */ + break; + + default: + return -1; + } + } + + if (action == ACT_UNPACK) { + char *resstring = argv[optind]; + + if (optind == argc) { + fprintf(stderr, "Resource identifier required\n"); + return 1; + } + + if ((resourcenumber_string = (char *) strchr(resstring, '.'))) { + *resourcenumber_string++ = 0; + } else if (optind + 1 == argc) { + fprintf(stderr, "Resource number required\n"); + return 1; + } else resourcenumber_string = argv[optind+1]; + + for (i = 0; i < 18; i++) + if ((strcmp(sci_resource_types[i], resstring) == 0)) stype = i; + if (stype == -1) { + printf("Could not find the resource type '%s'.\n", resstring); + return 1; + } + } /* ACT_UNPACK */ + + if (gamedir) + if (chdir(gamedir)) { + printf("Error changing to game directory '%s'\n", gamedir); + exit(1); + } + + if (!(resmgr = scir_new_resource_manager(gamedir, res_version, + 0, 1024 * 128))) { + fprintf(stderr, "Could not find any resources; quitting.\n"); + exit(1); + } + + if (verbose) printf("Autodetect determined: %s\n", + sci_version_types[resmgr->sci_version]); + + + switch (action) { + + case ACT_LIST: { + int i; + + if (verbose) { + for (i = 0; i < resmgr->resources_nr; i++) { + printf("%i: ", i); + print_resource_filename(stdout, + resmgr->resources[i].type, + resmgr->resources[i].number); + printf(" has size %i\n", resmgr->resources[i].size); + } + + fprintf(stderr, " Reading complete. Actual resource count is %i\n", + resmgr->resources_nr); + } else { + for (i = 0; i < resmgr->resources_nr; i++) { + print_resource_filename(stdout, + resmgr->resources[i].type, + resmgr->resources[i].number); + printf("\n"); + } + } + break; + } + + case ACT_UNPACK: { + + if (!strcmp(resourcenumber_string, "*")) { + int i; + for (i = 0; i < resmgr->resources_nr; i++) + if (resmgr->resources[i].type == stype) + unpack_resource(stype, resmgr->resources[i].number, NULL); + } else { + snr = atoi(resourcenumber_string); + unpack_resource(stype, snr, outfilename); + } + break; + } + + case ACT_WORDS: + retval = vocab_print(); + break; + + case ACT_SCRIPTDUMP: + retval = script_dump(); + break; + + case ACT_VOCABDUMP: + retval = vocab_dump(); + break; + + default: + fprintf(stderr, "Invalid action %d- internal error!\n", action); + return 1; + } + + + scir_free_resource_manager(resmgr); + return retval; +} + + +void unpack_resource(int stype, int snr, char *outfilename) { + char fnamebuffer[12]; /* stores default file name */ + resource_t *found; + + if ((stype == sci_sound) && conversion && (resmgr->sci_version > SCI_VERSION_0)) { + fprintf(stderr, "MIDI conversion is only supported for SCI version 0\n"); + conversion = 0; + } + + if (!outfilename) { + outfilename = fnamebuffer; + if ((stype == sci_sound) && conversion) { +#ifdef HAVE_OBSTACK_H + map_MIDI_instruments(resmgr); +#endif + sprintf(outfilename, "%03d.midi", snr); + } +#ifdef DRAW_GRAPHICS + else if ((stype == sci_pic) && conversion) + sprintf(outfilename, "%03d.png", snr); +#endif /* DRAW_GRAPHICS */ + else + sprint_resource_filename(outfilename, stype, snr); + } + + if (verbose) { + printf("seeking "); + print_resource_filename(stdout, stype, snr); + printf("...\n"); + } + + if ((found = scir_find_resource(resmgr, stype, snr, 0))) { + +#ifdef DRAW_GRAPHICS + if ((stype == sci_pic) && conversion) { + int i; + picture_t pic = alloc_empty_picture(SCI_RESOLUTION_320X200, SCI_COLORDEPTH_8BPP); + draw_pic0(pic, 1, 0, found->data); + if ((i = write_pic_png(outfilename, pic->maps[0]))) { + fprintf(stderr, "Writing the png failed (%d)\n", i); + } else if (verbose) printf("Done.\n"); + free_picture(pic); + } else +#endif /* DRAW_GRAPHICS */ + if ((stype == sci_script) && conversion) { + sprintf(outfilename, "%03d.script", snr); + open_console_file(outfilename); + script_dissect(resmgr, snr, NULL, 0); + close_console_file(); + } else { + + /* Visual C++ doesn't allow to specify O_BINARY with creat() */ +#ifdef _MSC_VER + int outf = open(outfilename, _O_CREAT | _O_BINARY | _O_RDWR); +#else + int outf = creat(outfilename, CREAT_OPTIONS); +#endif + +#ifdef HAVE_OBSTACK_H + if ((stype == sci_sound) && conversion) { + int midilength; + guint8 *outdata = makeMIDI0(found->data, &midilength, midimask); + if (!outdata) { + fprintf(stderr, "MIDI conversion failed. Aborting...\n"); + return; + } + if (verbose) printf("MIDI conversion from %d bytes of sound resource" + " to a %d bytes MIDI file.\n", + found->size, midilength); + write(outf, outdata, midilength); + free(outdata); + } else { +#endif /* HAVE_OBSTACK_H */ + guint8 header = 0x80 | found->type; + + if (with_header) { + write(outf, &header, 1); + header = 0x00; + write(outf, &header, 1); + } + + write(outf, found->data, found->size); +#ifdef HAVE_OBSTACK_H + } +#endif /* HAVE_OBSTACK_H */ + + fchmod(outf, 0644); + close(outf); + fchmod(outf, 0644); + + if (verbose) printf("Done.\n"); + } + + } else printf("Resource not found.\n"); +} + + + diff --git a/tools/sci/sciunpack.h b/tools/sci/sciunpack.h new file mode 100644 index 0000000000..df605ed19b --- /dev/null +++ b/tools/sci/sciunpack.h @@ -0,0 +1,68 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef SCI_UNPACK_H_ +#define SCI_UNPACK_H_ + +#include <sciresource.h> + +#define SORT_METHOD_ALPHA 0 +#define SORT_METHOD_GROUP 1 + +#define DEFAULT_SORTING SORT_METHOD_ALPHA + +extern int vocab_sort; /* Sorting strategy for vocab */ +extern resource_mgr_t *resmgr; + +int +vocab_print(void); +/* Prints vocab data +** Parameters: (void) +** Returns : (int) 0 on success, 1 on failure +** Controlled by vocab_sort +*/ + +int +script_dump(void); +/* Prints all object information +** Parameters: (void) +** Returns : (int) 0 on success, 1 on failure +*/ + +int +vocab_dump(void); +/* Prints full vocabulary information +** Parameters: (void) +** Returns : (int) 0 on success, 1 on failure +*/ + +int +print_classes(void); +/* Prints full class information +** Parameters: (void) +** Returns : (int) 0 on success, 1 otherwise +*/ + +#endif diff --git a/tools/sci/scriptdump.cpp b/tools/sci/scriptdump.cpp new file mode 100644 index 0000000000..9a5ef00035 --- /dev/null +++ b/tools/sci/scriptdump.cpp @@ -0,0 +1,45 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include <console.h> +#include <script.h> +#include <vocabulary.h> +#include <old_objects.h> +#include <stdio.h> +#include <stdlib.h> +#include <engine.h> +#include "sciunpack.h" + +int script_dump() { + con_passthrough = 1; + + if (loadObjects(resmgr)) { + fprintf(stderr, "Unable to load object hierarchy\n"); + return 1; + } + + printObject(object_root, SCRIPT_PRINT_METHODS | SCRIPT_PRINT_CHILDREN); + return 0; +} diff --git a/tools/sci/vocabdump.cpp b/tools/sci/vocabdump.cpp new file mode 100644 index 0000000000..26bac4dcf0 --- /dev/null +++ b/tools/sci/vocabdump.cpp @@ -0,0 +1,70 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include <engine.h> +#include "sciunpack.h" + +int +vocab_dump() { + char **names; + opcode *opcodes; + int i = 0, count; + int *classes; + + printf("Selectors:\n"); + names = vocabulary_get_snames(resmgr, NULL, 0); + while (names[i]) { + printf("0x%02X: %s\n", i, names[i]); + i++; + } + vocabulary_free_snames(names); + + i = 0; + printf("\nOpcodes:\n"); + opcodes = vocabulary_get_opcodes(resmgr); + while ((i < 256) && (opcodes[i].name)) { + printf("%s: Type %i, Number %i\n", opcodes[i].name, + opcodes[i].type, opcodes[i].number); + i++; + } + + names = vocabulary_get_knames(resmgr, &count); + printf("\nKernel names:\n"); + if (names == 0) printf("Error loading kernel names\n"); + else { + for (i = 0; i < count; i++) printf("0x%02X: %s\n", i, names[i]); + vocabulary_free_knames(names); + } + + classes = vocabulary_get_classes(resmgr, &count); + printf("\nClasses:\n"); + if (classes == 0) printf("Error loading classes\n"); + else { + for (i = 0; i < count; i++) printf("0x%02X: script %i\n", i, classes [i]); + free(classes); + } + + return 0; +} |