├── .gitignore ├── INSTALL ├── LICENSE ├── Makefile.am ├── NEWS.md ├── README.md ├── bootstrap.sh ├── clp.c ├── configure.ac ├── include └── lcdf │ ├── clp.h │ └── inttypes.h ├── memmem.c ├── strerror.c ├── t1ascii.1 ├── t1ascii.c ├── t1asm.1 ├── t1asm.c ├── t1asmhelp.h ├── t1binary.1 ├── t1binary.c ├── t1disasm.1 ├── t1disasm.c ├── t1lib.c ├── t1lib.h ├── t1mac.1 ├── t1mac.c ├── t1unmac.1 └── t1unmac.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .deps 3 | Makefile 4 | Makefile.in 5 | aclocal.m4 6 | autom4te* 7 | config.cache 8 | config.guess 9 | config.h 10 | config.h.in 11 | config.h.in~ 12 | config.log 13 | config.status 14 | config.sub 15 | configure 16 | depcomp 17 | include 18 | install-sh 19 | missing 20 | stamp-h* 21 | t1ascii 22 | t1asm 23 | t1binary 24 | t1disasm 25 | t1mac 26 | t1unmac 27 | t1utils-*.rpm 28 | t1utils-*.tar.gz 29 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Basic Installation 2 | ================== 3 | 4 | These are generic installation instructions. 5 | 6 | The `configure' shell script attempts to guess correct values for 7 | various system-dependent variables used during compilation. It uses 8 | those values to create a `Makefile' in each directory of the package. 9 | It may also create one or more `.h' files containing system-dependent 10 | definitions. Finally, it creates a shell script `config.status' that 11 | you can run in the future to recreate the current configuration, a file 12 | `config.cache' that saves the results of its tests to speed up 13 | reconfiguring, and a file `config.log' containing compiler output 14 | (useful mainly for debugging `configure'). 15 | 16 | If you need to do unusual things to compile the package, please try 17 | to figure out how `configure' could check whether to do them, and mail 18 | diffs or instructions to the address given in the `README' so they can 19 | be considered for the next release. If at some point `config.cache' 20 | contains results you don't want to keep, you may remove or edit it. 21 | 22 | The file `configure.in' is used to create `configure' by a program 23 | called `autoconf'. You only need `configure.in' if you want to change 24 | it or regenerate `configure' using a newer version of `autoconf'. 25 | 26 | The simplest way to compile this package is: 27 | 28 | 1. `cd' to the directory containing the package's source code and type 29 | `./configure' to configure the package for your system. If you're 30 | using `csh' on an old version of System V, you might need to type 31 | `sh ./configure' instead to prevent `csh' from trying to execute 32 | `configure' itself. 33 | 34 | Running `configure' takes awhile. While running, it prints some 35 | messages telling which features it is checking for. 36 | 37 | 2. Type `make' to compile the package. 38 | 39 | 3. Optionally, type `make check' to run any self-tests that come with 40 | the package. 41 | 42 | 4. Type `make install' to install the programs and any data files and 43 | documentation. 44 | 45 | 5. You can remove the program binaries and object files from the 46 | source code directory by typing `make clean'. To also remove the 47 | files that `configure' created (so you can compile the package for 48 | a different kind of computer), type `make distclean'. There is 49 | also a `make maintainer-clean' target, but that is intended mainly 50 | for the package's developers. If you use it, you may have to get 51 | all sorts of other programs in order to regenerate files that came 52 | with the distribution. 53 | 54 | Compilers and Options 55 | ===================== 56 | 57 | Some systems require unusual options for compilation or linking that 58 | the `configure' script does not know about. You can give `configure' 59 | initial values for variables by setting them in the environment. Using 60 | a Bourne-compatible shell, you can do that on the command line like 61 | this: 62 | CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure 63 | 64 | Or on systems that have the `env' program, you can do it like this: 65 | env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure 66 | 67 | Compiling For Multiple Architectures 68 | ==================================== 69 | 70 | You can compile the package for more than one kind of computer at the 71 | same time, by placing the object files for each architecture in their 72 | own directory. To do this, you must use a version of `make' that 73 | supports the `VPATH' variable, such as GNU `make'. `cd' to the 74 | directory where you want the object files and executables to go and run 75 | the `configure' script. `configure' automatically checks for the 76 | source code in the directory that `configure' is in and in `..'. 77 | 78 | If you have to use a `make' that does not supports the `VPATH' 79 | variable, you have to compile the package for one architecture at a time 80 | in the source code directory. After you have installed the package for 81 | one architecture, use `make distclean' before reconfiguring for another 82 | architecture. 83 | 84 | Installation Names 85 | ================== 86 | 87 | By default, `make install' will install the package's files in 88 | `/usr/local/bin', `/usr/local/man', etc. You can specify an 89 | installation prefix other than `/usr/local' by giving `configure' the 90 | option `--prefix=PATH'. 91 | 92 | You can specify separate installation prefixes for 93 | architecture-specific files and architecture-independent files. If you 94 | give `configure' the option `--exec-prefix=PATH', the package will use 95 | PATH as the prefix for installing programs and libraries. 96 | Documentation and other data files will still use the regular prefix. 97 | 98 | If the package supports it, you can cause programs to be installed 99 | with an extra prefix or suffix on their names by giving `configure' the 100 | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. 101 | 102 | Optional Features 103 | ================= 104 | 105 | Some packages pay attention to `--enable-FEATURE' options to 106 | `configure', where FEATURE indicates an optional part of the package. 107 | They may also pay attention to `--with-PACKAGE' options, where PACKAGE 108 | is something like `gnu-as' or `x' (for the X Window System). The 109 | `README' should mention any `--enable-' and `--with-' options that the 110 | package recognizes. 111 | 112 | For packages that use the X Window System, `configure' can usually 113 | find the X include and library files automatically, but if it doesn't, 114 | you can use the `configure' options `--x-includes=DIR' and 115 | `--x-libraries=DIR' to specify their locations. 116 | 117 | Specifying the System Type 118 | ========================== 119 | 120 | There may be some features `configure' can not figure out 121 | automatically, but needs to determine by the type of host the package 122 | will run on. Usually `configure' can figure that out, but if it prints 123 | a message saying it can not guess the host type, give it the 124 | `--host=TYPE' option. TYPE can either be a short name for the system 125 | type, such as `sun4', or a canonical name with three fields: 126 | CPU-COMPANY-SYSTEM 127 | 128 | See the file `config.sub' for the possible values of each field. If 129 | `config.sub' isn't included in this package, then this package doesn't 130 | need to know the host type. 131 | 132 | If you are building compiler tools for cross-compiling, you can also 133 | use the `--target=TYPE' option to select the type of system they will 134 | produce code for and the `--build=TYPE' option to select the type of 135 | system on which you are compiling the package. 136 | 137 | Sharing Defaults 138 | ================ 139 | 140 | If you want to set default values for `configure' scripts to share, 141 | you can create a site shell script called `config.site' that gives 142 | default values for variables like `CC', `cache_file', and `prefix'. 143 | `configure' looks for `PREFIX/share/config.site' if it exists, then 144 | `PREFIX/etc/config.site' if it exists. Or, you can set the 145 | `CONFIG_SITE' environment variable to the location of the site script. 146 | A warning: not all `configure' scripts look for a site script. 147 | 148 | Operation Controls 149 | ================== 150 | 151 | `configure' recognizes the following options to control how it 152 | operates. 153 | 154 | `--cache-file=FILE' 155 | Use and save the results of the tests in FILE instead of 156 | `./config.cache'. Set FILE to `/dev/null' to disable caching, for 157 | debugging `configure'. 158 | 159 | `--help' 160 | Print a summary of the options to `configure', and exit. 161 | 162 | `--quiet' 163 | `--silent' 164 | `-q' 165 | Do not print messages saying which checks are being made. 166 | 167 | `--srcdir=DIR' 168 | Look for the package's source code in directory DIR. Usually 169 | `configure' can determine that directory automatically. 170 | 171 | `--version' 172 | Print the version of Autoconf used to generate the `configure' 173 | script, and exit. 174 | 175 | `configure' also accepts some other, not widely useful, options. 176 | 177 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Portions of this software are subject to the license below. The relevant 2 | source files are clearly marked; they refer to this file using the phrase 3 | "the Click LICENSE file". This license is an MIT license, plus a clause 4 | (taken from the W3C license) requiring prior written permission to use our 5 | names in publicity. 6 | 7 | =========================================================================== 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a 10 | copy of this software and associated documentation files (the "Software"), 11 | to deal in the Software without restriction, including without limitation 12 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 | and/or sell copies of the Software, and to permit persons to whom the 14 | Software is furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in 17 | all copies or substantial portions of the Software. 18 | 19 | The name and trademarks of copyright holders may NOT be used in advertising 20 | or publicity pertaining to the Software without specific, written prior 21 | permission. Title to copyright in this Software and any associated 22 | documentation will at all times remain with copyright holders. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 29 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 30 | DEALINGS IN THE SOFTWARE. 31 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ## Process this file with automake to produce Makefile.in 2 | AUTOMAKE_OPTIONS = foreign 3 | 4 | bin_PROGRAMS = t1ascii t1binary t1asm t1disasm t1unmac t1mac 5 | man_MANS = t1ascii.1 t1binary.1 t1asm.1 t1disasm.1 t1unmac.1 t1mac.1 6 | 7 | t1ascii_SOURCES = include/lcdf/clp.h include/lcdf/inttypes.h \ 8 | clp.c t1lib.h t1lib.c t1ascii.c 9 | t1binary_SOURCES = include/lcdf/clp.h include/lcdf/inttypes.h \ 10 | clp.c t1lib.h t1lib.c t1binary.c 11 | t1asm_SOURCES = include/lcdf/clp.h include/lcdf/inttypes.h \ 12 | clp.c t1lib.h t1asmhelp.h t1lib.c t1asm.c 13 | t1disasm_SOURCES = include/lcdf/clp.h include/lcdf/inttypes.h \ 14 | clp.c t1lib.h t1asmhelp.h t1lib.c t1disasm.c 15 | t1unmac_SOURCES = include/lcdf/clp.h include/lcdf/inttypes.h \ 16 | clp.c t1lib.h t1lib.c t1unmac.c 17 | t1mac_SOURCES = include/lcdf/clp.h include/lcdf/inttypes.h \ 18 | clp.c t1lib.h t1lib.c t1mac.c 19 | 20 | AM_CPPFLAGS = -I$(top_srcdir)/include 21 | LDADD = @LIBOBJS@ 22 | 23 | EXTRA_DIST = $(man_MANS) INSTALL LICENSE README.md NEWS.md 24 | 25 | versionize: 26 | perl -pi -e "s/^\\.ds V.*/.ds V $(VERSION)/;" t1ascii.1 t1binary.1 t1disasm.1 t1asm.1 t1unmac.1 t1mac.1 27 | 28 | .PHONY: srclinks versionize 29 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | T1utils NEWS 2 | ============ 3 | 4 | ## Version 1.42 – 27.Oct.2020 5 | 6 | * Compile fixes for OSes that do not declare a function. 7 | 8 | 9 | ## Version 1.41 – 16.Aug.2017 10 | 11 | * t1asm, t1disasm: More security fixes. 12 | 13 | 14 | ## Version 1.40 – 23.Jul.2017 15 | 16 | * t1disasm: More security fixes reported by Jakub Wilk and Niels Thykier. 17 | 18 | 19 | ## Version 1.39 – 26.Feb.2015 20 | 21 | * t1disasm: Security fixes for buffer overrun reported by Jakub Wilk 22 | and Niels Thykier. 23 | 24 | 25 | ## Version 1.38 – 29.Sep.2013 26 | 27 | * t1disasm: Fix an infinite loop on some fonts reported by Niels 28 | Thykier. 29 | 30 | 31 | ## Version 1.37 – 29.Jun.2011 32 | 33 | * t1asm: Use a dynamically allocated buffer to handle huge characters 34 | (reported by Werner Lemberg). 35 | 36 | 37 | ## Version 1.36 – 29.May.2010 38 | 39 | * Several minor cleanups. 40 | 41 | 42 | ## Version 1.35 – 22.Oct.2009 43 | 44 | * Don't use "getline" as a symbol (reported by Karl Berry and 45 | C.M. Connelly). 46 | 47 | 48 | ## Version 1.34 – 1.Mar.2008 49 | 50 | * Add `--enable-multiplatform` (requested by Karl Berry). 51 | 52 | 53 | ## Version 1.33 – 8.Jan.2008 54 | 55 | * Several minor cleanups. 56 | 57 | 58 | ## Version 1.32 – 23.Feb.2004 59 | 60 | * t1disasm: Avoid memory corruption bug (strings passed to `eexec_line` are 61 | not null terminated). Reported by Werner Lemberg. 62 | 63 | 64 | ## Version 1.31 – 8.Feb.2004 65 | 66 | * All: Support fonts where the eexec-encrypted portion is binary, and the 67 | first ciphertext byte is 0. Reported by Werner Lemberg. 68 | 69 | 70 | ## Version 1.30 – 6.Jan.2004 71 | 72 | * All: Support fonts, such as those in PostScript files printed by 73 | acroread, where `currentfile eexec` is not followed by a newline. 74 | 75 | 76 | ## Version 1.29 – 6.Oct.2003 77 | 78 | * t1disasm: Support odd fonts where a character is defined on the 79 | "/CharStrings" line. Reported by Werner Lemberg. 80 | 81 | 82 | ## Version 1.28 – 7.Aug.2003 83 | 84 | * Address build problems reported by Nelson H.F. Beebe. 85 | 86 | 87 | ## Version 1.27 – 26.Mar.2003 88 | 89 | * t1ascii: Add optional warning when output lines are longer than 255 90 | characters. Requested by Werner Lemberg . 91 | 92 | 93 | ## Version 1.26 – 16.Apr.2002 94 | 95 | * t1mac: Fix buglet (C++ comment, and temporary file left behind). Reported 96 | by Vladimir Volovich . 97 | 98 | 99 | ## Version 1.25 – 3.Jan.2002 100 | 101 | * t1asm: Beware extra characters after `currentfile closefile`. Reported by 102 | Luc Devroye . 103 | 104 | 105 | ## Version 1.24 – 6.Sep.2001 106 | 107 | * Fixed compilation bugs on various platforms reported by Nelson H. F. 108 | Beebe . 109 | 110 | 111 | ## Version 1.23 – 18.Jun.2001 112 | 113 | * Fixed Macintosh file bugs: the MacBinary CRC was calculated incorrectly, 114 | and extended finder flags were set to random values in BinHex output. 115 | Reported, and patch provided, by Tom Kacvinsky . 116 | 117 | 118 | ## Version 1.22 – 6.Mar.2001 119 | 120 | * Fixed bug on processing PFA fonts with DOS line endings. The symptom was 121 | t1binary producing strange/unusable fonts. Problem: the all-zeros line, 122 | which signals the end of the font's binary section, was not being 123 | recognized because of an extra `\r`. This has been a bug since version 124 | 1.13 -- chagrin! Problem reported by Han The Thanh 125 | . 126 | 127 | 128 | ## Version 1.21 – 9.Feb.2001 129 | 130 | * t1ascii, t1asm, t1unmac: Raised minimum PFA line length to 8. The Adobe 131 | spec may imply that there cannot be whitespace within the first 8 bytes 132 | of an ASCII-encoded eexec section; it's somewhat ambiguous. Reported by 133 | Rainer Menzner . 134 | 135 | 136 | ## Version 1.20 – 22.Jun.2000 137 | 138 | * t1asm: Fixed bug where `t1asm -a` would give a “warning: line length 139 | raised to 4” error message. Reported by Tom Kacvinsky . 140 | 141 | 142 | ## Version 1.19 – 3.May.2000 143 | 144 | * t1mac: Generated Macintosh fonts now use a custom-drawn icon set, rather 145 | than Adobe's default. They also have a t1utils-specific creator signature 146 | (T1UT), and their file information mentions t1utils. 147 | 148 | * t1mac: Added the `--filename` option. 149 | 150 | 151 | ## Version 1.18 – 2.May.2000 152 | 153 | * t1mac: Fixed bug where generated files appeared corrupted to Macintoshes. 154 | Reported by Marten Thavenius . 155 | 156 | 157 | ## Version 1.17 – 27.Apr.2000 158 | 159 | * Added new program, `t1mac`, which translates PFA or PFB fonts into 160 | Macintosh-style fonts. T1mac can output in MacBinary, AppleSingle, 161 | AppleDouble, or BinHex format. Suggested by Marten Thavenius 162 | . 163 | 164 | * t1unmac: Added support for BinHex. 165 | 166 | * t1unmac: Fixed bugs in manual page and program options. 167 | 168 | 169 | ## Version 1.16 – 25.Apr.2000 170 | 171 | * t1unmac: Supports AppleSingle and AppleDouble files with the 172 | `--applesingle/double` option. Requested by Kent Boortz 173 | . 174 | 175 | 176 | ## Version 1.15 – 4.Apr.2000 177 | 178 | * t1ascii, t1binary, and t1disasm: Fixed bad error message. 179 | 180 | * t1unmac: Generates PFB fonts by default. 181 | 182 | 183 | ## Version 1.14 – 25.Aug.1999 184 | 185 | * t1asm: Version 1.13 produced complete crap output. My test cases were too 186 | limited to catch this. Found by Rainer Menzner 187 | . 188 | 189 | 190 | ## Version 1.13 – 2.Aug.1999 191 | 192 | * t1disasm: Complete rewrite. It now uses t1lib.c functions; the goal is to 193 | handle PFA and PFB fonts consistently. This has been extensively tested, 194 | but there may be bugs. 195 | 196 | * t1disasm, t1asm: Fixed to support fonts with multiple Subrs and 197 | CharStrings sections, like some old Oblique fonts. 198 | 199 | * PFA minimum line length raised to 4. 200 | 201 | * t1ascii, t1binary, t1disasm: Changes in t1lib.c to support reading binary 202 | PFA fonts. Requested by Tom Kacvinsky . 203 | 204 | 205 | ## Version 1.12 – 1.Aug.1999 206 | 207 | * t1ascii, t1binary, t1asm, t1disasm: Support fonts with whitespace 208 | following the `currentfile eexec` line. Embedded fonts in PostScript 209 | generated by Acrobat Reader have this property. Reported by Tom Kacvinsky 210 | . 211 | 212 | * t1ascii, t1asm, t1unmac: Use lowercase hex digits instead of uppercase. 213 | 214 | * t1unmac: Added `--line-length` option for PFA output. 215 | 216 | 217 | ## Version 1.11 – 29.May.1999 218 | 219 | * Bug fix in t1asm/t1disasm: if a `readhexstring` procedure was defined, we 220 | got confused. Reported by Luc Devroye . 221 | 222 | * t1binary now has a maximum block length of 2^32 - 1. "Feature" requested 223 | by Werner Lemberg . 224 | 225 | * t1ascii and t1binary each accept both PFA and PFB fonts. If you pass an 226 | ASCII font (PFA) to t1ascii, it will output it mostly unchanged, and 227 | similarly for PFB fonts and t1binary. The `-l` options will still take 228 | effect, so you can use `t1ascii -l 60` to shorten the encrypted line 229 | lengths of a PFA font. t1ascii also does some newline translation 230 | (changes carriage returns to newlines). 231 | 232 | 233 | ## Version 1.10.1 – 12.Apr.1999 234 | 235 | * t1asm: Fixed bug when `-l` option wasn't provided. Caught by Giuseppe 236 | Ghibò . 237 | 238 | 239 | ## Version 1.10 – 11.Apr.1999 240 | 241 | * t1asm/t1disasm: Provide support for Type1C (Compact Font Format) font 242 | files. These fonts have unencrypted character strings, signalled by a 243 | negative lenIV value. Suggestion and patch thanks to Tom Kacvinsky 244 | . 245 | 246 | * t1ascii/t1asm: Added `-l/--line-length` option to control maximum encrypted 247 | line length. Suggestion thanks to Giuseppe Ghibò . 248 | 249 | 250 | ## Version 1.9 – 14.Feb.1999 251 | 252 | * t1asm/t1disasm: Be more robust on fonts that don't end in `mark 253 | currentfile closefile`. John Vromans provided a 254 | font that ended with `mark` on one line and `currentfile closefile` on 255 | another; t1asm and t1disasm did not recognize the encrypted section of 256 | the font had ended, and generated some garbage. 257 | 258 | 259 | ## Version 1.8 – 2.Jan.1999 260 | 261 | * Added some more Type 2 commands (flex, flex1, hflex, hflex1) from a 262 | revision of the Type 2 spec. (I wouldn't have known about this except for 263 | CurveSoft's revised t1utils package, available at 264 | http://www.curvesoft.com. These t1utils are more up-to-date than theirs, 265 | however.) 266 | 267 | * t1asm: Fixed one Type 2 command's translation (cntrmask was incorrectly 268 | mapped to 18, not 20). 269 | 270 | 271 | ## Version 1.7.2 – 11.Dec.1998 272 | 273 | * Integrated patches from Jan-Jaap van der Heijden 274 | to support building t1utils under 275 | 32-bit Windows. 276 | 277 | 278 | ## Version 1.7.1 – 5.Dec.1998 279 | 280 | * The t1utils package now uses automake. 281 | 282 | 283 | ## Version 1.7 – 27.Nov.1998 284 | 285 | * t1asm: Should now work with fonts that have no /Subrs sections. Previously, 286 | assembling such a font would silently fail; all the character definitions 287 | would be mistaken for procedures and t1asm wouldn't translate them. Problem 288 | noticed and fix suggested by Tom Kacvinsky . 289 | 290 | * t1disasm: Removed spurious debugging output and improved warning message 291 | about unknown charstring commands. 292 | 293 | * Changed fgetc/fputc into getc/putc. 294 | 295 | 296 | ## Version 1.6 – 27.Sep.1998 297 | 298 | * `--help` now prints to stdout, following the GNU Coding Standards. 299 | 300 | * Makefiles: Added `make uninstall` target, enabled `./configure`'s 301 | program name transformations, made VPATH builds possible. 302 | 303 | 304 | ## Version 1.5.2 – 6.Aug.1998 305 | 306 | * t1asm/t1disasm: Changed unknown charstring commands at the request of 307 | Werner Lemberg and LEE Chun-Yu. An unknown escape in the charstring, like 308 | 12 X, is translated to "escape_X" rather than "UNKNOWN_12_X". 309 | 310 | 311 | ## Version 1.5.1 – 31.May.1998 312 | 313 | * t1unmac did not actually understand the `-r` and `-b` options. Fixed. 314 | 315 | * t1unmac: Added better diagnostics to help you diagnose seeking problems. 316 | 317 | 318 | ## Version 1.5 – 5.Mar.1998 319 | 320 | * Initial release with Eddie Kohler as maintainer. 321 | 322 | * All: Updated to the GNU program behavior standards (long options, `--help`, 323 | `--version`). Banners removed. Added more error messages. 324 | 325 | * t1binary: Removed fixed limit on line length. 326 | 327 | * t1binary: Supports Macintosh files, whose lines end in `\r`. 328 | 329 | * t1binary: Supports an odd number of hex digits in a line. 330 | 331 | * t1asm/t1disasm: Added support for Type 2 commands like `blend` and `add`, 332 | which also appear in some multiple master fonts like Adobe Jenson. 333 | 334 | * t1asm/t1disasm: Added support for unknown charstring commands. t1disasm 335 | translates an unknown command #X to "UNKNOWN_X", and t1asm does the reverse. 336 | 337 | * t1asm/t1unmac: Changed default output to PFB. 338 | 339 | * t1unmac: Used to be called `unpost`. `t1unmac` is a much better name. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | T1utils 2 | ======= 3 | 4 | T1utils is a collection of simple programs for manipulating PostScript Type 1 5 | fonts. Together, they allow you to convert between PFA (ASCII) and PFB 6 | (binary) formats, disassemble PFA or PFB files into human-readable form, and 7 | reassemble them into PFA or PFB format. Additionally you can extract font 8 | resources from a Macintosh font file or create a Macintosh Type 1 font file 9 | from a PFA or PFB font. 10 | 11 | There are currently six programs: 12 | 13 | * **t1ascii**: Converts PFB files to PFA format. 14 | 15 | * **t1binary**: Converts PFA files to PFB format. 16 | 17 | * **t1disasm**: Disassembles a Type 1 font (PFA or PFB format) into a 18 | raw, human-readable text form for subsequent hand editing, tweaking, hint 19 | fixing, and so forth. 20 | 21 | * **t1asm**: Assembles the human-readable t1disasm text form into a Type 1 22 | font in PFA or PFB format. 23 | 24 | * **t1unmac**: Extracts POST resources from a Macintosh Type 1 font file into 25 | PFA or PFB format for use outside the Macintosh environment. The Macintosh 26 | file should be stored in MacBinary, AppleSingle, AppleDouble, or BinHex 27 | format, or as a raw resource fork. Note that t1unmac does not have to run on 28 | a Macintosh. 29 | 30 | * **t1mac**: Creates a Macintosh Type 1 file from a PFA or PFB-format Type 1 31 | font. Writes the Macintosh file in MacBinary, AppleSingle, AppleDouble, or 32 | BinHex format, or as a raw resource fork. WARNING: This will not suffice to 33 | use the new font on a Macintosh, as Macintoshes cannot read raw Type 1 34 | fonts. You will need to create a font suitcase containing bitmap fonts if 35 | you do not have such a suitcase for the font already. T1utils cannot help 36 | you do this. 37 | 38 | Installation 39 | ------------ 40 | 41 | You need an ANSI C compiler, such as gcc. 42 | 43 | Just type `./configure`, then `make`. `make install` will build and install 44 | the utilities and their manual pages. 45 | 46 | `./configure` accepts the usual options. See `INSTALL` for more details. The 47 | most commonly used option is `--prefix`, which can be used to install the 48 | utilities in a place other than /usr/local. 49 | 50 | Copyright and license 51 | --------------------- 52 | 53 | The original t1utils were (c) 1992 I. Lee Hetherington, . 54 | Changes since version 1.2 are (c) 1998-2017 Eddie Kohler. Distribution is 55 | under the Click LICENSE, a BSD-like license described in the LICENSE file in 56 | this directory. 57 | 58 | Note that these tools should not be used to illegally copy Type 1 font 59 | programs. Typeface design is an intricate art that should be rewarded. 60 | 61 | Eddie Kohler, ekohler@gmail.com 62 | -------------------------------------------------------------------------------- /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | autoreconf -i 4 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | dnl Process this file with autoconf to produce a configure script. 2 | AC_INIT([t1utils], [1.42]) 3 | AC_CONFIG_SRCDIR([t1ascii.c]) 4 | AM_INIT_AUTOMAKE 5 | AC_CONFIG_HEADERS([config.h]) 6 | 7 | AC_PROG_CC 8 | AC_C_CONST 9 | 10 | AC_ARG_ENABLE([warnings], 11 | [AS_HELP_STRING([--enable-warnings], [compile with -W -Wall])], 12 | [if test "$enableval" = yes; then 13 | CFLAGS="$CFLAGS -W -Wall" 14 | fi]) 15 | 16 | 17 | dnl 18 | dnl strerror()? 19 | dnl 20 | 21 | AC_REPLACE_FUNCS([strerror memmem]) 22 | AC_CHECK_DECLS([memmem]) 23 | 24 | 25 | dnl 26 | dnl integer types 27 | dnl 28 | 29 | AC_CHECK_HEADERS(inttypes.h, have_inttypes_h=yes, have_inttypes_h=no) 30 | AC_CHECK_HEADERS(sys/types.h, have_sys_types_h=yes, have_sys_types_h=no) 31 | 32 | if test $have_inttypes_h = no -a $have_sys_types_h = yes; then 33 | AC_CACHE_CHECK([for uintXX_t typedefs], ac_cv_uint_t, 34 | [AC_EGREP_HEADER(dnl 35 | changequote(<<,>>)<<(^|[^a-zA-Z_0-9])uint32_t[^a-zA-Z_0-9]>>changequote([,]), 36 | sys/types.h, ac_cv_uint_t=yes, ac_cv_uint_t=no)]) 37 | fi 38 | if test $have_inttypes_h = no -a $have_sys_types_h = yes -a "$ac_cv_uint_t" = no; then 39 | AC_CACHE_CHECK([for u_intXX_t typedefs], ac_cv_u_int_t, 40 | [AC_EGREP_HEADER(dnl 41 | changequote(<<,>>)<<(^|[^a-zA-Z_0-9])u_int32_t[^a-zA-Z_0-9]>>changequote([,]), 42 | sys/types.h, ac_cv_u_int_t=yes, ac_cv_u_int_t=no)]) 43 | fi 44 | if test $have_inttypes_h = yes -o "$ac_cv_uint_t" = yes; then 45 | : 46 | elif test "$ac_cv_u_int_t" = yes; then 47 | AC_DEFINE(HAVE_U_INT_TYPES, 1, [Define if you have u_intXX_t types but not uintXX_t types.]) 48 | else 49 | AC_MSG_WARN([ 50 | ========================================= 51 | 52 | Neither uint32_t nor u_int32_t defined by or ! 53 | Assuming "short" has 16 bits and "int" has 32 bits. 54 | 55 | =========================================]) 56 | AC_DEFINE(HAVE_FAKE_INT_TYPES, 1, [Define if intXX_t types are not available.]) 57 | fi 58 | 59 | AC_CHECK_TYPES(uintptr_t, [], [], 60 | [#if HAVE_INTTYPES_H 61 | # include 62 | #endif 63 | #if HAVE_SYS_TYPES_H 64 | # include 65 | #endif 66 | ]) 67 | 68 | AC_CHECK_SIZEOF(void *) 69 | AC_CHECK_SIZEOF(unsigned long) 70 | AC_CHECK_SIZEOF(unsigned int) 71 | 72 | 73 | dnl 74 | dnl verbatim portions of the header 75 | dnl 76 | 77 | AH_TOP([#ifndef T1UTILS_CONFIG_H 78 | #define T1UTILS_CONFIG_H]) 79 | 80 | AH_BOTTOM([#include 81 | 82 | #ifdef __cplusplus 83 | extern "C" { 84 | #endif 85 | 86 | /* Prototype strerror if we don't have it. */ 87 | #if !HAVE_STRERROR 88 | char* strerror(int errno); 89 | #endif 90 | 91 | /* Prototype memmem if we don't have it. */ 92 | #if !HAVE_MEMMEM || !HAVE_DECL_MEMMEM 93 | void* memmem(const void* haystack, size_t haystack_len, 94 | const void* needle, size_t needle_len); 95 | #endif 96 | 97 | #ifdef __cplusplus 98 | } 99 | /* Get rid of a possible inline macro under C++. */ 100 | # define inline inline 101 | #endif 102 | 103 | #endif /* T1UTILS_CONFIG_H */]) 104 | 105 | 106 | dnl 107 | dnl Multiplatform output directories (for teTeX and TeX Live) 108 | dnl 109 | 110 | AC_CANONICAL_HOST 111 | AC_ARG_ENABLE([multiplatform], 112 | [AS_HELP_STRING([--enable-multiplatform], 113 | [put executables into bin/PLATFORM and libraries into lib/PLATFORM])]) 114 | if test "x$enable_multiplatform" = xyes; then 115 | test "x$bindir" = 'x${exec_prefix}/bin' && bindir="$bindir/$host" 116 | test "x$libdir" = 'x${exec_prefix}/lib' && libdir="$libdir/$host" 117 | fi 118 | 119 | 120 | dnl 121 | dnl Output 122 | dnl 123 | 124 | AC_CONFIG_FILES([Makefile]) 125 | AC_OUTPUT 126 | -------------------------------------------------------------------------------- /include/lcdf/clp.h: -------------------------------------------------------------------------------- 1 | /* -*- related-file-name: "../../liblcdf/clp.c" -*- */ 2 | #ifndef LCDF_CLP_H 3 | #define LCDF_CLP_H 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | /* clp.h - Public interface to CLP. 9 | * This file is part of CLP, the command line parser package. 10 | * 11 | * Copyright (c) 1997-2014 Eddie Kohler, ekohler@gmail.com 12 | * 13 | * CLP is free software. It is distributed under the GNU General Public 14 | * License, Version 2, or, alternatively and at your discretion, under the 15 | * more permissive (BSD-like) Click LICENSE file as described below. 16 | * 17 | * Permission is hereby granted, free of charge, to any person obtaining a 18 | * copy of this software and associated documentation files (the 19 | * "Software"), to deal in the Software without restriction, subject to the 20 | * conditions listed in the Click LICENSE file, which is available in full at 21 | * http://github.com/kohler/click/blob/master/LICENSE. The conditions 22 | * include: you must preserve this copyright notice, and you cannot mention 23 | * the copyright holders in advertising related to the Software without 24 | * their permission. The Software is provided WITHOUT ANY WARRANTY, EXPRESS 25 | * OR IMPLIED. This notice is a summary of the Click LICENSE file; the 26 | * license in that file is binding. */ 27 | 28 | #include 29 | #include 30 | 31 | typedef struct Clp_Option Clp_Option; 32 | typedef struct Clp_Parser Clp_Parser; 33 | typedef struct Clp_ParserState Clp_ParserState; 34 | 35 | 36 | /** @brief Option description. 37 | * 38 | * CLP users declare arrays of Clp_Option structures to specify what options 39 | * should be parsed. 40 | * @sa Clp_NewParser, Clp_SetOptions */ 41 | struct Clp_Option { 42 | const char *long_name; /**< Name of long option, or NULL if the option 43 | has no long name. */ 44 | int short_name; /**< Character defining short option, or 0 if 45 | the option has no short name. */ 46 | int option_id; /**< User-specified ID defining option, 47 | returned by Clp_Next. */ 48 | int val_type; /**< ID of option's value type, or 0 if option 49 | takes no value. */ 50 | int flags; /**< Option parsing flags. */ 51 | }; 52 | 53 | /** @name Value types 54 | * These values describe the type of an option's argument and are used in 55 | * the Clp_Option val_type field. For example, if an option took integers, its 56 | * Clp_Option structure would have val_type set to Clp_ValInt. */ 57 | /**@{*/ 58 | #define Clp_NoVal 0 /**< @brief Option takes no value. */ 59 | #define Clp_ValString 1 /**< @brief Option value is an 60 | arbitrary string. */ 61 | #define Clp_ValStringNotOption 2 /**< @brief Option value is a 62 | non-option string. 63 | 64 | See Clp_DisallowOptions. */ 65 | #define Clp_ValBool 3 /**< @brief Option value is a 66 | boolean. 67 | 68 | Accepts "true", "false", "yes", "no", "1", and "0", or any 69 | prefixes thereof. The match is case-insensitive. */ 70 | #define Clp_ValInt 4 /**< @brief Option value is a 71 | signed int. 72 | 73 | Accepts an optional "+" or "-" sign, followed by one or more 74 | digits. The digits may be include a "0x" or "0X" prefix, for 75 | a hexadecimal number, or a "0" prefix, for an octal number; 76 | otherwise it is decimal. */ 77 | #define Clp_ValUnsigned 5 /**< @brief Option value is an 78 | unsigned int. 79 | 80 | Accepts an optional "+" sign, followed by one or more 81 | digits. The digits may be include a "0x" or "0X" prefix, for 82 | a hexadecimal number, or a "0" prefix, for an octal number; 83 | otherwise it is decimal. */ 84 | #define Clp_ValLong 6 /**< @brief Option value is a 85 | signed long. */ 86 | #define Clp_ValUnsignedLong 7 /**< @brief Option value is an 87 | unsigned long. */ 88 | #define Clp_ValDouble 8 /**< @brief Option value is a 89 | double. 90 | Accepts a real number as defined by strtod(). */ 91 | #define Clp_ValFirstUser 10 /**< @brief Value types >= 92 | Clp_ValFirstUser are available 93 | for user types. */ 94 | /**@}*/ 95 | 96 | /** @name Option flags 97 | * These flags are used in the Clp_Option flags field. */ 98 | /**@{*/ 99 | #define Clp_Mandatory (1<<0) /**< @brief Option flag: value 100 | is mandatory. 101 | 102 | It is an error if the option has no value. This is the 103 | default if an option has arg_type != 0 and the Clp_Optional 104 | flag is not provided. */ 105 | #define Clp_Optional (1<<1) /**< @brief Option flag: value 106 | is optional. */ 107 | #define Clp_Negate (1<<2) /**< @brief Option flag: option 108 | may be negated. 109 | 110 | --no-[long_name] will be accepted in argument lists. */ 111 | #define Clp_OnlyNegated (1<<3) /**< @brief Option flag: option 112 | must be negated. 113 | 114 | --no-[long_name] will be accepted in argument lists, but 115 | --[long_name] will not. This is the default if long_name 116 | begins with "no-". */ 117 | #define Clp_PreferredMatch (1<<4) /**< @brief Option flag: prefer this 118 | option when matching. 119 | 120 | Prefixes of --[long_name] should map to this option, even if 121 | other options begin with --[long_name]. */ 122 | /**@}*/ 123 | 124 | /** @name Option character types 125 | * These flags are used in to define character types in Clp_SetOptionChar(). */ 126 | /**@{*/ 127 | /* Clp_NotOption 0 */ 128 | #define Clp_Short (1<<0) /**< @brief Option character begins 129 | a set of short options. */ 130 | #define Clp_Long (1<<1) /**< @brief Option character begins 131 | a long option. */ 132 | #define Clp_ShortNegated (1<<2) /**< @brief Option character begins 133 | a set of negated short options. */ 134 | #define Clp_LongNegated (1<<3) /**< @brief Option character begins 135 | a negated long option. */ 136 | #define Clp_LongImplicit (1<<4) /**< @brief Option character can begin 137 | a long option, and is part of that 138 | long option. */ 139 | /**@}*/ 140 | 141 | #define Clp_NotOption 0 /**< @brief Clp_Next value: argument 142 | was not an option. */ 143 | #define Clp_Done -1 /**< @brief Clp_Next value: there are 144 | no more arguments. */ 145 | #define Clp_BadOption -2 /**< @brief Clp_Next value: argument 146 | was an erroneous option. */ 147 | #define Clp_Error -3 /**< @brief Clp_Next value: internal 148 | CLP error. */ 149 | 150 | #define Clp_ValSize 40 /**< @brief Minimum size of the 151 | Clp_Parser val.cs field. */ 152 | #define Clp_ValIntSize 10 /**< @brief Minimum size of the 153 | Clp_Parser val.is field. */ 154 | 155 | 156 | /** @brief A value parsing function. 157 | * @param clp the parser 158 | * @param vstr the value to be parsed 159 | * @param complain if nonzero, report error messages via Clp_OptionError 160 | * @param user_data user data passed to Clp_AddType() 161 | * @return 1 if parsing succeeded, 0 otherwise 162 | */ 163 | typedef int (*Clp_ValParseFunc)(Clp_Parser *clp, const char *vstr, 164 | int complain, void *user_data); 165 | 166 | /** @brief A function for reporting option errors. 167 | * @param clp the parser 168 | * @param message error message 169 | */ 170 | typedef void (*Clp_ErrorHandler)(Clp_Parser *clp, const char *message); 171 | 172 | 173 | /** @brief Command line parser. 174 | * 175 | * A Clp_Parser object defines an instance of CLP, including allowed options, 176 | * value types, and current arguments. 177 | * @sa Clp_NewParser, Clp_SetOptions, Clp_SetArguments */ 178 | struct Clp_Parser { 179 | const Clp_Option *option; /**< The last option. */ 180 | 181 | int negated; /**< Whether the last option was negated. */ 182 | 183 | int have_val; /**< Whether the last option had a value. */ 184 | const char *vstr; /**< The string value provided with the last 185 | option. */ 186 | 187 | union { 188 | int i; 189 | unsigned u; 190 | long l; 191 | unsigned long ul; 192 | double d; 193 | const char *s; 194 | void *pv; 195 | #ifdef HAVE_INT64_TYPES 196 | int64_t i64; 197 | uint64_t u64; 198 | #endif 199 | char cs[Clp_ValSize]; 200 | unsigned char ucs[Clp_ValSize]; 201 | int is[Clp_ValIntSize]; 202 | unsigned us[Clp_ValIntSize]; 203 | } val; /**< The parsed value provided with the last 204 | option. */ 205 | 206 | void *user_data; /**< Uninterpreted by CLP; users can set 207 | arbitrarily. */ 208 | 209 | struct Clp_Internal *internal; 210 | }; 211 | 212 | /** @cond never */ 213 | #if __GNUC__ >= 4 214 | # define CLP_SENTINEL __attribute__((sentinel)) 215 | #else 216 | # define CLP_SENTINEL /* nothing */ 217 | #endif 218 | /** @endcond never */ 219 | 220 | 221 | /** @brief Create a new Clp_Parser. */ 222 | Clp_Parser *Clp_NewParser(int argc, const char * const *argv, 223 | int nopt, const Clp_Option *opt); 224 | 225 | /** @brief Destroy a Clp_Parser object. */ 226 | void Clp_DeleteParser(Clp_Parser *clp); 227 | 228 | 229 | /** @brief Return @a clp's program name. */ 230 | const char *Clp_ProgramName(Clp_Parser *clp); 231 | 232 | /** @brief Set @a clp's program name. */ 233 | const char *Clp_SetProgramName(Clp_Parser *clp, const char *name); 234 | 235 | 236 | /** @brief Set @a clp's error handler function. */ 237 | Clp_ErrorHandler Clp_SetErrorHandler(Clp_Parser *clp, Clp_ErrorHandler errh); 238 | 239 | /** @brief Set @a clp's UTF-8 mode. */ 240 | int Clp_SetUTF8(Clp_Parser *clp, int utf8); 241 | 242 | /** @brief Return @a clp's treatment of character @a c. */ 243 | int Clp_OptionChar(Clp_Parser *clp, int c); 244 | 245 | /** @brief Set @a clp's treatment of character @a c. */ 246 | int Clp_SetOptionChar(Clp_Parser *clp, int c, int type); 247 | 248 | /** @brief Set @a clp's option definitions. */ 249 | int Clp_SetOptions(Clp_Parser *clp, int nopt, const Clp_Option *opt); 250 | 251 | /** @brief Set @a clp's arguments. */ 252 | void Clp_SetArguments(Clp_Parser *clp, int argc, const char * const *argv); 253 | 254 | /** @brief Set whether @a clp is searching for options. */ 255 | int Clp_SetOptionProcessing(Clp_Parser *clp, int on); 256 | 257 | 258 | #define Clp_DisallowOptions (1<<0) /**< @brief Value type flag: value 259 | can't be an option string. 260 | 261 | See Clp_AddType(). */ 262 | 263 | /** @brief Define a new value type for @a clp. */ 264 | int Clp_AddType(Clp_Parser *clp, int val_type, int flags, 265 | Clp_ValParseFunc parser, void *user_data); 266 | 267 | 268 | #define Clp_AllowNumbers (1<<0) /**< @brief String list flag: allow 269 | explicit numbers. 270 | 271 | See Clp_AddStringListType() and Clp_AddStringListTypeVec(). */ 272 | #define Clp_StringListLong (1<<1) /**< @brief String list flag: values 273 | have long type. */ 274 | 275 | /** @brief Define a new string list value type for @a clp. */ 276 | int Clp_AddStringListTypeVec(Clp_Parser *clp, int val_type, int flags, 277 | int nstrs, const char * const *strs, 278 | const int *vals); 279 | 280 | /** @brief Define a new string list value type for @a clp. */ 281 | int Clp_AddStringListType(Clp_Parser *clp, int val_type, int flags, ...) 282 | CLP_SENTINEL; 283 | 284 | 285 | /** @brief Parse and return the next argument from @a clp. */ 286 | int Clp_Next(Clp_Parser *clp); 287 | 288 | /** @brief Return the next argument from @a clp without option parsing. */ 289 | const char *Clp_Shift(Clp_Parser *clp, int allow_options); 290 | 291 | 292 | /** @brief Create a new Clp_ParserState. */ 293 | Clp_ParserState *Clp_NewParserState(void); 294 | 295 | /** @brief Destroy a Clp_ParserState object. */ 296 | void Clp_DeleteParserState(Clp_ParserState *state); 297 | 298 | /** @brief Save @a clp's current state in @a state. */ 299 | void Clp_SaveParser(const Clp_Parser *clp, Clp_ParserState *state); 300 | 301 | /** @brief Restore parser state from @a state into @a clp. */ 302 | void Clp_RestoreParser(Clp_Parser *clp, const Clp_ParserState *state); 303 | 304 | 305 | /** @brief Report a parser error. */ 306 | int Clp_OptionError(Clp_Parser *clp, const char *format, ...); 307 | 308 | /** @brief Format a message. */ 309 | int Clp_vsnprintf(Clp_Parser* clp, char* str, size_t size, 310 | const char* format, va_list val); 311 | 312 | /** @brief Print a message. */ 313 | int Clp_fprintf(Clp_Parser* clp, FILE* f, const char* format, ...); 314 | 315 | /** @brief Print a message. */ 316 | int Clp_vfprintf(Clp_Parser* clp, FILE* f, const char* format, va_list val); 317 | 318 | /** @brief Extract the current option as a string. */ 319 | int Clp_CurOptionNameBuf(Clp_Parser *clp, char *buf, int len); 320 | 321 | /** @brief Extract the current option as a string. */ 322 | const char *Clp_CurOptionName(Clp_Parser *clp); 323 | 324 | /** @brief Test if the current option had long name @a name. */ 325 | int Clp_IsLong(Clp_Parser *clp, const char *long_name); 326 | 327 | /** @brief Test if the current option had short name @a name. */ 328 | int Clp_IsShort(Clp_Parser *clp, int short_name); 329 | 330 | #undef CLP_SENTINEL 331 | #ifdef __cplusplus 332 | } 333 | #endif 334 | #endif 335 | -------------------------------------------------------------------------------- /include/lcdf/inttypes.h: -------------------------------------------------------------------------------- 1 | #ifndef LCDF_INTTYPES_H 2 | #define LCDF_INTTYPES_H 3 | /* Define known-width integer types. */ 4 | 5 | #include 6 | 7 | #ifdef HAVE_INTTYPES_H 8 | # include 9 | #elif defined(HAVE_SYS_TYPES_H) 10 | # include 11 | # ifdef HAVE_U_INT_TYPES 12 | typedef u_int8_t uint8_t; 13 | typedef u_int16_t uint16_t; 14 | typedef u_int32_t uint32_t; 15 | # endif 16 | #endif 17 | 18 | #ifdef HAVE_FAKE_INT_TYPES 19 | typedef signed char int8_t; 20 | typedef unsigned char uint8_t; 21 | typedef signed short int16_t; 22 | typedef unsigned short uint16_t; 23 | typedef signed int int32_t; 24 | typedef unsigned int uint32_t; 25 | #endif 26 | 27 | #ifndef HAVE_UINTPTR_T 28 | # if SIZEOF_VOID_P == SIZEOF_UNSIGNED_INT 29 | typedef unsigned int uintptr_t; 30 | # elif SIZEOF_VOID_P == SIZEOF_UNSIGNED_LONG 31 | typedef unsigned long uintptr_t; 32 | # endif 33 | #endif 34 | 35 | /* Note: Windows compilers call these types '[un]signed __int8', etc. */ 36 | #endif 37 | -------------------------------------------------------------------------------- /memmem.c: -------------------------------------------------------------------------------- 1 | /* Some operating systems might not have memmem. */ 2 | 3 | #ifdef HAVE_CONFIG_H 4 | # include 5 | #endif 6 | #include 7 | #include 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | void* 13 | memmem(const void* haystack, size_t haystack_len, 14 | const void* needle, size_t needle_len) 15 | { 16 | const unsigned char* s = (const unsigned char*) haystack; 17 | const unsigned char* ends = s + haystack_len - needle_len; 18 | const unsigned char* p = (const unsigned char*) needle; 19 | void* try; 20 | if (needle_len == 0) 21 | return (void*) haystack; 22 | while (s <= ends && (try = memchr(s, *p, ends - s + 1))) 23 | if (memcmp(try, p, needle_len) == 0) 24 | return (void*) try; 25 | else 26 | s = (const unsigned char*) try + 1; 27 | return 0; 28 | } 29 | 30 | #ifdef __cplusplus 31 | } 32 | #endif 33 | -------------------------------------------------------------------------------- /strerror.c: -------------------------------------------------------------------------------- 1 | /* Some operating systems don't have strerror. 2 | This file provides a definition which David Mazieres 3 | assures me works. */ 4 | 5 | #ifdef HAVE_CONFIG_H 6 | # include 7 | #endif 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | char * 13 | strerror(int errno) 14 | { 15 | extern int sys_nerr; 16 | extern char *sys_errlist[]; 17 | if (errno < 0 || errno >= sys_nerr) 18 | return (char *)"bad error number"; 19 | else 20 | return sys_errlist[errno]; 21 | } 22 | 23 | #ifdef __cplusplus 24 | } 25 | #endif 26 | -------------------------------------------------------------------------------- /t1ascii.1: -------------------------------------------------------------------------------- 1 | .ds V 1.42 2 | .de M 3 | .BR "\\$1" "(\\$2)\\$3" 4 | .. 5 | .TH T1ASCII 1 "" "Version \*V" 6 | .SH NAME 7 | t1ascii \- convert PostScript Type 1 font from binary to ASCII 8 | .SH SYNOPSIS 9 | .B t1ascii 10 | \%[\fB\-l\fR \fIlength\fR] 11 | \%[\fIinput\fR [\fIoutput\fR]] 12 | .SH DESCRIPTION 13 | .BR t1ascii 14 | converts Adobe Type 1 font programs in PFB (binary) format to PFA 15 | (hexadecimal) format. If the file 16 | .I output 17 | is not specified output goes to the standard output. 18 | If the file 19 | .I input 20 | is not specified input comes from the standard input. 21 | ' 22 | .SH OPTIONS 23 | .TP 5 24 | .BI \-\-line\-length= "num\fR, " \-l " num" 25 | Set the maximum length of encrypted lines in the output to 26 | .I num. 27 | (These are the lines consisting wholly of hexadecimal digits.) The default 28 | is 64. 29 | ' 30 | .TP 5 31 | .BR \-\-warnings ", " \-w 32 | Warn when the input font contains lines longer than 255 characters. 33 | Long lines don't strictly conform to Adobe's Document Structuring 34 | Conventions, and may cause problems with older software. 35 | ' 36 | .SH "SEE ALSO" 37 | .LP 38 | .M t1binary 1 , 39 | .M t1unmac 1 , 40 | .M t1mac 1 , 41 | .M t1asm 1 , 42 | .M t1disasm 1 43 | .LP 44 | .I "Adobe Type 1 Font Format" 45 | .SH AUTHORS 46 | Lee Hetherington (ilh@lcs.mit.edu) 47 | .br 48 | Eddie Kohler (ekohler@gmail.com) 49 | .PP 50 | Ported to Microsoft C/C++ Compiler and MS-DOS operating system by 51 | Kai-Uwe Herbing (herbing@netmbx.netmbx.de). 52 | -------------------------------------------------------------------------------- /t1ascii.c: -------------------------------------------------------------------------------- 1 | /* t1ascii 2 | * 3 | * This program takes an Adobe Type-1 font program in binary (PFB) format and 4 | * converts it to ASCII (PFA) format. 5 | * 6 | * Copyright (c) 1992 by I. Lee Hetherington, all rights reserved. 7 | * Copyright (c) 1998-2017 Eddie Kohler 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a 10 | * copy of this software and associated documentation files (the 11 | * "Software"), to deal in the Software without restriction, subject to the 12 | * conditions listed in the Click LICENSE file, which is available in full at 13 | * http://github.com/kohler/click/blob/master/LICENSE. The conditions 14 | * include: you must preserve this copyright notice, and you cannot mention 15 | * the copyright holders in advertising related to the Software without 16 | * their permission. The Software is provided WITHOUT ANY WARRANTY, EXPRESS 17 | * OR IMPLIED. This notice is a summary of the Click LICENSE file; the 18 | * license in that file is binding. 19 | * 20 | * New change log in `NEWS'. Old change log: 21 | * 22 | * Revision 1.2 92/06/23 10:58:43 ilh 23 | * MSDOS porting by Kai-Uwe Herbing (herbing@netmbx.netmbx.de) 24 | * incoporated. 25 | * 26 | * Revision 1.1 92/05/22 11:47:24 ilh 27 | * initial version 28 | * 29 | * Ported to Microsoft C/C++ Compiler and MS-DOS operating system by 30 | * Kai-Uwe Herbing (herbing@netmbx.netmbx.de) on June 12, 1992. Code 31 | * specific to the MS-DOS version is encapsulated with #ifdef _MSDOS 32 | * ... #endif, where _MSDOS is an identifier, which is automatically 33 | * defined, if you compile with the Microsoft C/C++ Compiler. 34 | * 35 | */ 36 | 37 | /* Note: this is ANSI C. */ 38 | 39 | #ifdef HAVE_CONFIG_H 40 | # include 41 | #endif 42 | #if defined(_MSDOS) || defined(_WIN32) 43 | # include 44 | # include 45 | #endif 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include "t1lib.h" 55 | 56 | #ifdef __cplusplus 57 | extern "C" { 58 | #endif 59 | 60 | static FILE *ofp; 61 | static int line_length = 64; 62 | 63 | 64 | /***** 65 | * Command line 66 | **/ 67 | 68 | #define OUTPUT_OPT 301 69 | #define VERSION_OPT 302 70 | #define HELP_OPT 303 71 | #define LINE_LEN_OPT 304 72 | #define WARNINGS_OPT 305 73 | 74 | static Clp_Option options[] = { 75 | { "help", 0, HELP_OPT, 0, 0 }, 76 | { "line-length", 'l', LINE_LEN_OPT, Clp_ValInt, 0 }, 77 | { "output", 'o', OUTPUT_OPT, Clp_ValString, 0 }, 78 | { "version", 0, VERSION_OPT, 0, 0 }, 79 | { "warnings", 'w', WARNINGS_OPT, 0, Clp_Negate } 80 | }; 81 | static const char *program_name; 82 | static const char *ifp_filename = ""; 83 | static int line_length_warning = -1; 84 | 85 | void 86 | fatal_error(const char *message, ...) 87 | { 88 | va_list val; 89 | va_start(val, message); 90 | fprintf(stderr, "%s: ", program_name); 91 | vfprintf(stderr, message, val); 92 | putc('\n', stderr); 93 | va_end(val); 94 | exit(1); 95 | } 96 | 97 | void 98 | error(const char *message, ...) 99 | { 100 | va_list val; 101 | va_start(val, message); 102 | fprintf(stderr, "%s: ", program_name); 103 | vfprintf(stderr, message, val); 104 | putc('\n', stderr); 105 | va_end(val); 106 | } 107 | 108 | static void 109 | short_usage(void) 110 | { 111 | fprintf(stderr, "Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\ 112 | Try `%s --help' for more information.\n", 113 | program_name, program_name); 114 | } 115 | 116 | static void 117 | usage(void) 118 | { 119 | printf("\ 120 | `T1ascii' translates a PostScript Type 1 font from compact binary (PFB) to\n\ 121 | ASCII (PFA) format. The result is written to the standard output unless an\n\ 122 | OUTPUT file is given.\n\ 123 | \n\ 124 | Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\ 125 | \n\ 126 | Options:\n\ 127 | -l, --line-length=NUM Set max encrypted line length (default 64).\n\ 128 | -o, --output=FILE Write output to FILE.\n\ 129 | -w, --warnings Warn on too-long lines.\n\ 130 | -h, --help Print this message and exit.\n\ 131 | --version Print version number and warranty and exit.\n\ 132 | \n\ 133 | Report bugs to .\n", program_name); 134 | } 135 | 136 | 137 | /***** 138 | * PFA font_reader functions 139 | **/ 140 | 141 | static int hexcol = 0; 142 | 143 | static void 144 | pfa_output_ascii(char *data, int len) 145 | { 146 | if (hexcol) { 147 | putc('\n', ofp); 148 | hexcol = 0; 149 | } 150 | if (line_length_warning == 0 && len > 256) { 151 | line_length_warning = 1; 152 | fprintf(stderr, "%s: warning: %s has lines longer than 255 characters\n%s: (This may cause problems with older printers.)\n", program_name, ifp_filename, program_name); 153 | } 154 | fputs(data, ofp); 155 | if (len && data[len - 1] != '\n') { 156 | int p = len - 2; 157 | while (p > 0 && data[p] != '\n') 158 | p--; 159 | hexcol = (p ? len - p - 1 : hexcol + len); 160 | } 161 | } 162 | 163 | static void 164 | pfa_output_binary(unsigned char *data, int len) 165 | { 166 | static const char *hexchar = "0123456789abcdef"; 167 | for (; len > 0; len--, data++) { 168 | /* trim hexadecimal lines to line_length columns */ 169 | if (hexcol >= line_length) { 170 | putc('\n', ofp); 171 | hexcol = 0; 172 | } 173 | putc(hexchar[(*data >> 4) & 0xf], ofp); 174 | putc(hexchar[*data & 0xf], ofp); 175 | hexcol += 2; 176 | } 177 | } 178 | 179 | static void 180 | pfa_output_end(void) 181 | { 182 | } 183 | 184 | #ifdef __cplusplus 185 | } 186 | #endif 187 | 188 | 189 | /***** 190 | * main() 191 | **/ 192 | 193 | int 194 | main(int argc, char *argv[]) 195 | { 196 | struct font_reader fr; 197 | int c; 198 | FILE *ifp = 0; 199 | 200 | Clp_Parser *clp = 201 | Clp_NewParser(argc, (const char * const *)argv, sizeof(options) / sizeof(options[0]), options); 202 | program_name = Clp_ProgramName(clp); 203 | 204 | /* interpret command line arguments using CLP */ 205 | while (1) { 206 | int opt = Clp_Next(clp); 207 | switch (opt) { 208 | 209 | case LINE_LEN_OPT: 210 | line_length = clp->val.i; 211 | if (line_length < 8) { 212 | line_length = 8; 213 | error("warning: line length raised to %d", line_length); 214 | } else if (line_length > 1024) { 215 | line_length = 1024; 216 | error("warning: line length lowered to %d", line_length); 217 | } 218 | break; 219 | 220 | output_file: 221 | case OUTPUT_OPT: 222 | if (ofp) 223 | fatal_error("output file already specified"); 224 | if (strcmp(clp->vstr, "-") == 0) 225 | ofp = stdout; 226 | else { 227 | ofp = fopen(clp->vstr, "w"); 228 | if (!ofp) fatal_error("%s: %s", clp->vstr, strerror(errno)); 229 | } 230 | break; 231 | 232 | case WARNINGS_OPT: 233 | line_length_warning = (clp->negated ? -1 : 0); 234 | break; 235 | 236 | case HELP_OPT: 237 | usage(); 238 | exit(0); 239 | break; 240 | 241 | case VERSION_OPT: 242 | printf("t1ascii (LCDF t1utils) %s\n", VERSION); 243 | printf("Copyright (C) 1992-2017 I. Lee Hetherington, Eddie Kohler et al.\n\ 244 | This is free software; see the source for copying conditions.\n\ 245 | There is NO warranty, not even for merchantability or fitness for a\n\ 246 | particular purpose.\n"); 247 | exit(0); 248 | break; 249 | 250 | case Clp_NotOption: 251 | if (ifp && ofp) 252 | fatal_error("too many arguments"); 253 | else if (ifp) 254 | goto output_file; 255 | if (strcmp(clp->vstr, "-") == 0) { 256 | ifp_filename = ""; 257 | ifp = stdin; 258 | } else { 259 | ifp_filename = clp->vstr; 260 | ifp = fopen(clp->vstr, "rb"); 261 | if (!ifp) 262 | fatal_error("%s: %s", clp->vstr, strerror(errno)); 263 | } 264 | break; 265 | 266 | case Clp_Done: 267 | goto done; 268 | 269 | case Clp_BadOption: 270 | short_usage(); 271 | exit(1); 272 | break; 273 | 274 | } 275 | } 276 | 277 | done: 278 | if (!ifp) 279 | ifp = stdin; 280 | if (!ofp) 281 | ofp = stdout; 282 | if (line_length > 255 && line_length_warning == 0) 283 | fprintf(stderr, "%s: warning: selected --line-length is greater than 255\n", program_name); 284 | 285 | #if defined(_MSDOS) || defined(_WIN32) 286 | /* As we are processing a PFB (binary) input */ 287 | /* file, we must set its file mode to binary. */ 288 | _setmode(_fileno(ifp), _O_BINARY); 289 | #endif 290 | 291 | /* prepare font reader */ 292 | fr.output_ascii = pfa_output_ascii; 293 | fr.output_binary = pfa_output_binary; 294 | fr.output_end = pfa_output_end; 295 | 296 | /* peek at first byte to see if it is the PFB marker 0x80 */ 297 | c = getc(ifp); 298 | ungetc(c, ifp); 299 | 300 | /* do the file */ 301 | if (c == PFB_MARKER) 302 | process_pfb(ifp, ifp_filename, &fr); 303 | else if (c == '%') 304 | process_pfa(ifp, ifp_filename, &fr); 305 | else 306 | fatal_error("%s does not start with font marker (`%%' or 0x80)", ifp_filename); 307 | 308 | fclose(ifp); 309 | fclose(ofp); 310 | return 0; 311 | } 312 | -------------------------------------------------------------------------------- /t1asm.1: -------------------------------------------------------------------------------- 1 | .ds V 1.42 2 | .de M 3 | .BR "\\$1" "(\\$2)\\$3" 4 | .. 5 | .TH T1ASM 1 "" "Version \*V" 6 | .SH NAME 7 | t1asm \- assemble PostScript Type 1 font 8 | .SH SYNOPSIS 9 | .B t1asm 10 | \%[\fB\-a\fR|\fB\-b\fR] 11 | \%[\fB\-l\fR \fIlength\fR] 12 | \%[\fIinput\fR [\fIoutput\fR]] 13 | .SH DESCRIPTION 14 | .B t1asm 15 | assembles Adobe Type 1 font programs into either PFA (hexadecimal) or PFB 16 | (binary) formats from a human-readable form. If the file 17 | .I output 18 | is not specified output goes to the standard output. If the file 19 | .I input 20 | is not specified input comes from the standard input. 21 | 22 | .B t1asm 23 | tokenizes the charstring data and performs eexec and charstring encryption 24 | as specified in the ``black book,'' 25 | .I "Adobe Type 1 Font Format." 26 | 27 | The input must have a line of the form 28 | .RS 29 | .nf 30 | .ft B 31 | /-|{string currentfile exch readstring pop}executeonly def 32 | .ft R 33 | .fi 34 | .RE 35 | which defines the command, in this case `\-|', that is to start charstring 36 | data. It is an error not to define such a command. Another common name for 37 | this command is `RD'. 38 | 39 | After the start of the 40 | .B Subrs 41 | array in the input, all open braces `{' not in a comment begin a 42 | charstring. Such a charstring is terminated by the next non-comment close 43 | brace `}'. Within such a charstring, only comments, integers, and valid 44 | charstring commands are allowed. Valid charstring command names can be 45 | found in 46 | .I "Adobe Type 1 Font Format" 47 | and other documents describing the newer Type 2 opcodes. The format within 48 | a charstring is unimportant as long as integers and commands are separated 49 | by at least a one whitespace (space, tab, newline) character. Note that 50 | within charstrings, comments are discarded because they cannot be encoded. 51 | .SH OPTIONS 52 | .TP 5 53 | .BR \-\-pfa ", " \-a 54 | Output in PFA (ASCII) format. 55 | .TP 5 56 | .BR \-\-pfb ", " \-b 57 | Output in PFB (binary) format. This is the default. 58 | .TP 59 | .BI \-\-block\-length= "num\fR, " \-l " num" 60 | PFB only: Set the maximum output block length to 61 | .I num. 62 | The default length is as large as memory allows. 63 | .TP 64 | .BI \-\-line\-length= "num\fR, " \-l " num" 65 | PFA only: Set the maximum length of encrypted lines in the output to 66 | .I num. 67 | (These are the lines consisting wholly of hexadecimal digits.) The default 68 | is 64. 69 | .SH EXAMPLES 70 | .LP 71 | .nf 72 | % t1asm Utopia-Regular.raw > Utopia-Regular.pfb 73 | % t1asm -a Utopia-Regular.raw > Utopia-Regular.pfa 74 | .fi 75 | .SH "SEE ALSO" 76 | .LP 77 | .M t1disasm 1 , 78 | .M t1ascii 1 , 79 | .M t1binary 1 , 80 | .M t1unmac 1 , 81 | .M t1mac 1 82 | .LP 83 | .I "Adobe Type 1 Font Format" 84 | is available free from Adobe as a PDF file. 85 | http://partners.adobe.com/asn/developer/PDFS/TN/T1_SPEC.PDF 86 | .LP 87 | .I "The Type 2 Charstring Format," 88 | also available from Adobe as a PDF file, describes the newer Type 2 89 | operators, which are also used in some multiple-master Type 1 fonts like 90 | Adobe Jenson and Kepler. 91 | http://partners.adobe.com/asn/developer/PDFS/TN/5177.Type2.pdf 92 | ' 93 | .SH AUTHORS 94 | Lee Hetherington (ilh@lcs.mit.edu) 95 | .br 96 | Eddie Kohler (ekohler@gmail.com) 97 | -------------------------------------------------------------------------------- /t1asm.c: -------------------------------------------------------------------------------- 1 | /* t1asm -*- c-basic-offset: 2 -*- 2 | * 3 | * This program `assembles' Adobe Type-1 font programs in pseudo-PostScript 4 | * form into either PFB or PFA format. The human readable/editable input is 5 | * charstring- and eexec-encrypted as specified in the `Adobe Type 1 Font 6 | * Format' version 1.1 (the `black book'). There is a companion program, 7 | * t1disasm, which `disassembles' PFB and PFA files into a pseudo-PostScript 8 | * file. 9 | * 10 | * Copyright (c) 1992 by I. Lee Hetherington, all rights reserved. 11 | * Copyright (c) 1998-2017 Eddie Kohler 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a 14 | * copy of this software and associated documentation files (the 15 | * "Software"), to deal in the Software without restriction, subject to the 16 | * conditions listed in the Click LICENSE file, which is available in full at 17 | * http://github.com/kohler/click/blob/master/LICENSE. The conditions 18 | * include: you must preserve this copyright notice, and you cannot mention 19 | * the copyright holders in advertising related to the Software without 20 | * their permission. The Software is provided WITHOUT ANY WARRANTY, EXPRESS 21 | * OR IMPLIED. This notice is a summary of the Click LICENSE file; the 22 | * license in that file is binding. 23 | * 24 | * New change log in `NEWS'. Old change log: 25 | * 26 | * Revision 1.4 92/07/10 10:53:09 ilh 27 | * Added support for additional PostScript after the closefile command 28 | * (ie., some fonts have {restore}if after the cleartomark). 29 | * 30 | * Revision 1.3 92/06/23 10:58:25 ilh 31 | * MSDOS porting by Kai-Uwe Herbing (herbing@netmbx.netmbx.de) 32 | * incoporated. 33 | * 34 | * Revision 1.2 92/05/22 11:54:45 ilh 35 | * Fixed bug where integers larger than 32000 could not be encoded in 36 | * charstrings. Now integer range is correct for four-byte 37 | * twos-complement integers: -(1<<31) <= i <= (1<<31)-1. Bug detected by 38 | * Piet Tutelaers (rcpt@urc.tue.nl). 39 | * 40 | * Revision 1.1 92/05/22 11:48:46 ilh 41 | * initial version 42 | * 43 | * Ported to Microsoft C/C++ Compiler and MS-DOS operating system by 44 | * Kai-Uwe Herbing (herbing@netmbx.netmbx.de) on June 12, 1992. Code 45 | * specific to the MS-DOS version is encapsulated with #ifdef _MSDOS 46 | * ... #endif, where _MSDOS is an identifier, which is automatically 47 | * defined, if you compile with the Microsoft C/C++ Compiler. 48 | * 49 | */ 50 | 51 | /* Note: this is ANSI C. */ 52 | 53 | #ifdef HAVE_CONFIG_H 54 | # include 55 | #endif 56 | #if defined(_MSDOS) || defined(_WIN32) 57 | # include 58 | # include 59 | #endif 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include "t1lib.h" 69 | #include "t1asmhelp.h" 70 | 71 | #define LINESIZE 512 72 | 73 | #ifdef __cplusplus 74 | extern "C" { 75 | #endif 76 | 77 | typedef unsigned char byte; 78 | 79 | static FILE *ifp; 80 | static FILE *ofp; 81 | static struct pfb_writer w; 82 | static int blocklen = -1; 83 | 84 | /* flags */ 85 | static int pfb = 1; 86 | static int active = 0; 87 | static int ever_active = 0; 88 | static int start_charstring = 0; 89 | static int in_eexec = 0; 90 | 91 | /* need to add 1 as space for \0 */ 92 | static char line[LINESIZE + 1]; 93 | 94 | /* for charstring buffering */ 95 | static byte *charstring_buf, *charstring_bp; 96 | static int charstring_bufsiz; 97 | 98 | /* decryption stuff */ 99 | static uint16_t er, cr; 100 | static const uint32_t c1 = 52845; 101 | static const uint32_t c2 = 22719; 102 | 103 | /* table of charstring commands */ 104 | static struct command { 105 | const char *name; 106 | int one, two; 107 | } command_table[] = { 108 | { "abs", 12, 9 }, /* Type 2 */ 109 | { "add", 12, 10 }, /* Type 2 */ 110 | { "and", 12, 3 }, /* Type 2 */ 111 | { "blend", 16, -1 }, /* Type 2 */ 112 | { "callgsubr", 29, -1 }, /* Type 2 */ 113 | { "callother", 12, 16 }, /* Type 1 ONLY */ 114 | { "callothersubr", 12, 16 }, /* Type 1 ONLY */ 115 | { "callsubr", 10, -1 }, 116 | { "closepath", 9, -1 }, /* Type 1 ONLY */ 117 | { "cntrmask", 20, -1 }, /* Type 2 */ 118 | { "div", 12, 12 }, 119 | { "dotsection", 12, 0 }, /* Type 1 ONLY */ 120 | { "drop", 12, 18 }, /* Type 2 */ 121 | { "dup", 12, 27 }, /* Type 2 */ 122 | { "endchar", 14, -1 }, 123 | { "eq", 12, 15 }, /* Type 2 */ 124 | { "error", 0, -1 }, /* special */ 125 | { "escape", 12, -1 }, /* special */ 126 | { "exch", 12, 28 }, /* Type 2 */ 127 | { "flex", 12, 35 }, /* Type 2 */ 128 | { "flex1", 12, 37 }, /* Type 2 */ 129 | { "get", 12, 21 }, /* Type 2 */ 130 | { "hflex", 12, 34 }, /* Type 2 */ 131 | { "hflex1", 12, 36 }, /* Type 2 */ 132 | { "hhcurveto", 27, -1 }, /* Type 2 */ 133 | { "hintmask", 19, -1 }, /* Type 2 */ 134 | { "hlineto", 6, -1 }, 135 | { "hmoveto", 22, -1 }, 136 | { "hsbw", 13, -1 }, /* Type 1 ONLY */ 137 | { "hstem", 1, -1 }, 138 | { "hstem3", 12, 2 }, /* Type 1 ONLY */ 139 | { "hstemhm", 18, -1 }, /* Type 2 */ 140 | { "hvcurveto", 31, -1 }, 141 | { "ifelse", 12, 22 }, /* Type 2 */ 142 | { "index", 12, 29 }, /* Type 2 */ 143 | { "load", 12, 13 }, /* Type 2 */ 144 | { "mul", 12, 24 }, /* Type 2 */ 145 | { "neg", 12, 14 }, /* Type 2 */ 146 | { "not", 12, 5 }, /* Type 2 */ 147 | { "or", 12, 4 }, /* Type 2 */ 148 | { "pop", 12, 17 }, /* Type 1 ONLY */ 149 | { "put", 12, 20 }, /* Type 2 */ 150 | { "random", 12, 23 }, /* Type 2 */ 151 | { "rcurveline", 24, -1 }, /* Type 2 */ 152 | { "return", 11, -1 }, 153 | { "rlinecurve", 25, -1 }, /* Type 2 */ 154 | { "rlineto", 5, -1 }, 155 | { "rmoveto", 21, -1 }, 156 | { "roll", 12, 30 }, /* Type 2 */ 157 | { "rrcurveto", 8, -1 }, 158 | { "sbw", 12, 7 }, /* Type 1 ONLY */ 159 | { "seac", 12, 6 }, /* Type 1 ONLY */ 160 | { "setcurrentpoint", 12, 33 }, /* Type 1 ONLY */ 161 | { "sqrt", 12, 26 }, /* Type 2 */ 162 | { "store", 12, 8 }, /* Type 2 */ 163 | { "sub", 12, 11 }, /* Type 2 */ 164 | { "vhcurveto", 30, -1 }, 165 | { "vlineto", 7, -1 }, 166 | { "vmoveto", 4, -1 }, 167 | { "vstem", 3, -1 }, 168 | { "vstem3", 12, 1 }, /* Type 1 ONLY */ 169 | { "vstemhm", 23, -1 }, /* Type 2 */ 170 | { "vvcurveto", 26, -1 }, /* Type 2 */ 171 | }; /* alphabetical */ 172 | 173 | /* Two separate encryption functions because eexec and charstring encryption 174 | must proceed in parallel. */ 175 | 176 | static byte eencrypt(byte plain) 177 | { 178 | byte cipher; 179 | 180 | cipher = (byte)(plain ^ (er >> 8)); 181 | er = (uint16_t)((cipher + er) * c1 + c2); 182 | return cipher; 183 | } 184 | 185 | static byte cencrypt(byte plain) 186 | { 187 | byte cipher; 188 | 189 | /* Thanks to Tom Kacvinsky who reported that lenIV == -1 means 190 | unencrypted charstrings. */ 191 | if (lenIV < 0) return plain; 192 | 193 | cipher = (byte)(plain ^ (cr >> 8)); 194 | cr = (uint16_t)((cipher + cr) * c1 + c2); 195 | return cipher; 196 | } 197 | 198 | /* This function outputs a single byte. If output is in PFB format then output 199 | is buffered through blockbuf[]. If output is in PFA format, then output 200 | will be hexadecimal if in_eexec is set, ASCII otherwise. */ 201 | 202 | static void output_byte(byte b) 203 | { 204 | static const char *hexchar = "0123456789abcdef"; 205 | static int hexcol = 0; 206 | 207 | if (pfb) { 208 | /* PFB */ 209 | PFB_OUTPUT_BYTE(&w, b); 210 | } else { 211 | /* PFA */ 212 | if (in_eexec) { 213 | /* trim hexadecimal lines to `blocklen' columns */ 214 | if (hexcol >= blocklen) { 215 | putc('\n', ofp); 216 | hexcol = 0; 217 | } 218 | putc(hexchar[(b >> 4) & 0xf], ofp); 219 | putc(hexchar[b & 0xf], ofp); 220 | hexcol += 2; 221 | } else { 222 | putc(b, ofp); 223 | } 224 | } 225 | } 226 | 227 | /* This function outputs a byte through possible eexec encryption. */ 228 | 229 | static void eexec_byte(byte b) 230 | { 231 | if (in_eexec) 232 | output_byte(eencrypt(b)); 233 | else 234 | output_byte(b); 235 | } 236 | 237 | /* This function outputs a null-terminated string through possible eexec 238 | encryption. */ 239 | 240 | static void eexec_string(const char *string) 241 | { 242 | while (*string) 243 | eexec_byte(*string++); 244 | } 245 | 246 | /* This function gets ready for the eexec-encrypted data. If output is in 247 | PFB format then flush current ASCII block and get ready for binary block. 248 | We start encryption with four random (zero) bytes. */ 249 | 250 | static void eexec_start(char *string) 251 | { 252 | eexec_string("currentfile eexec\n"); 253 | if (pfb && w.blocktyp != PFB_BINARY) { 254 | pfb_writer_output_block(&w); 255 | w.blocktyp = PFB_BINARY; 256 | } 257 | 258 | in_eexec = 1; 259 | er = 55665; 260 | eexec_byte(0); 261 | eexec_byte(0); 262 | eexec_byte(0); 263 | eexec_byte(0); 264 | eexec_string(string); 265 | } 266 | 267 | /* 25.Aug.1999 -- Return 1 if this line actually looks like the start of a 268 | charstring. We use the heuristic that it should start with `/' (a name) or 269 | `dup' (a subroutine). Previous heuristic caused killa bad output. */ 270 | 271 | static int check_line_charstring(void) 272 | { 273 | char *p = line; 274 | while (isspace((unsigned char) *p)) 275 | p++; 276 | return (*p == '/' || (p[0] == 'd' && p[1] == 'u' && p[2] == 'p')); 277 | } 278 | 279 | /* This function returns an input line of characters. A line is terminated by 280 | length (including terminating null) greater than LINESIZE, \r, \n, \r\n, or 281 | when active (looking for charstrings) by '{'. When terminated by a newline 282 | the newline is put into line[]. When terminated by '{', the '{' is not put 283 | into line[], and the flag start_charstring is set to 1. */ 284 | 285 | static void t1utils_getline(void) 286 | { 287 | int c; 288 | char *p = line; 289 | int comment = 0; 290 | start_charstring = 0; 291 | 292 | while (p < line + LINESIZE) { 293 | c = getc(ifp); 294 | 295 | if (c == EOF) 296 | break; 297 | else if (c == '%') 298 | comment = 1; 299 | else if (active && !comment && c == '{') { 300 | /* 25.Aug.1999 -- new check for whether we should stop be active */ 301 | if (check_line_charstring()) { 302 | start_charstring = 1; 303 | break; 304 | } else 305 | active = 0; 306 | } 307 | 308 | *p++ = (char) c; 309 | 310 | /* end of line processing: change CR or CRLF into LF, and exit */ 311 | if (c == '\r') { 312 | c = getc(ifp); 313 | if (c != '\n') 314 | ungetc(c, ifp); 315 | p[-1] = '\n'; 316 | break; 317 | } else if (c == '\n') 318 | break; 319 | } 320 | 321 | *p = '\0'; 322 | } 323 | 324 | /* This function wraps-up the eexec-encrypted data and writes ASCII trailer. 325 | If output is in PFB format then this entails flushing binary block and 326 | starting an ASCII block. */ 327 | 328 | static void eexec_end(void) 329 | { 330 | int i, j; 331 | 332 | if (!pfb) 333 | putc('\n', ofp); 334 | else if (w.blocktyp != PFB_ASCII) { 335 | pfb_writer_output_block(&w); 336 | w.blocktyp = PFB_ASCII; 337 | } 338 | 339 | in_eexec = active = 0; 340 | 341 | for (i = 0; i < 8; i++) { 342 | for (j = 0; j < 64; j++) 343 | eexec_byte('0'); 344 | eexec_byte('\n'); 345 | } 346 | } 347 | 348 | /* This function is used by the binary search, bsearch(), for command names in 349 | the command table. */ 350 | 351 | static int CDECL command_compare(const void *key, const void *item) 352 | { 353 | return strcmp((const char *) key, ((const struct command *) item)->name); 354 | } 355 | 356 | /* This function returns 1 if the string is an integer and 0 otherwise. */ 357 | 358 | static int is_integer(char *string) 359 | { 360 | if (isdigit((unsigned char) string[0]) || string[0] == '-' || string[0] == '+') { 361 | while (*++string && isdigit((unsigned char) *string)) 362 | ; /* deliberately empty */ 363 | if (!*string) 364 | return 1; 365 | } 366 | return 0; 367 | } 368 | 369 | /* This function initializes charstring encryption. Note that this is called 370 | at the beginning of every charstring. */ 371 | 372 | static void charstring_start(void) 373 | { 374 | int i; 375 | 376 | if (!charstring_buf) { 377 | charstring_bufsiz = 65536; 378 | if (!(charstring_buf = (byte *) malloc(charstring_bufsiz))) 379 | fatal_error("out of memory"); 380 | } 381 | 382 | charstring_bp = charstring_buf; 383 | cr = 4330; 384 | for (i = 0; i < lenIV; i++) 385 | *charstring_bp++ = cencrypt((byte) 0); 386 | } 387 | 388 | /* This function encrypts and buffers a single byte of charstring data. */ 389 | 390 | static void charstring_byte(int v) 391 | { 392 | byte b = (byte)(v & 0xff); 393 | if (charstring_bp - charstring_buf == charstring_bufsiz) { 394 | charstring_bufsiz *= 2; 395 | if (!(charstring_buf = (byte *) realloc(charstring_buf, charstring_bufsiz))) 396 | fatal_error("out of memory"); 397 | charstring_bp = charstring_buf + charstring_bufsiz / 2; 398 | } 399 | *charstring_bp++ = cencrypt(b); 400 | } 401 | 402 | /* This function outputs buffered, encrypted charstring data through possible 403 | eexec encryption. */ 404 | 405 | static void charstring_end(void) 406 | { 407 | byte *bp; 408 | 409 | sprintf(line, "%d ", (int) (charstring_bp - charstring_buf)); 410 | eexec_string(line); 411 | sprintf(line, "%s ", cs_start); 412 | eexec_string(line); 413 | for (bp = charstring_buf; bp < charstring_bp; bp++) 414 | eexec_byte(*bp); 415 | } 416 | 417 | /* This function generates the charstring representation of an integer. */ 418 | 419 | static void charstring_int(int num) 420 | { 421 | int x; 422 | 423 | if (num >= -107 && num <= 107) { 424 | charstring_byte(num + 139); 425 | } else if (num >= 108 && num <= 1131) { 426 | x = num - 108; 427 | charstring_byte(x / 256 + 247); 428 | charstring_byte(x % 256); 429 | } else if (num >= -1131 && num <= -108) { 430 | x = abs(num) - 108; 431 | charstring_byte(x / 256 + 251); 432 | charstring_byte(x % 256); 433 | } else if (num >= (-2147483647-1) && num <= 2147483647) { 434 | charstring_byte(255); 435 | charstring_byte(num >> 24); 436 | charstring_byte(num >> 16); 437 | charstring_byte(num >> 8); 438 | charstring_byte(num); 439 | } else { 440 | error("can't format huge number `%d'", num); 441 | /* output 0 instead */ 442 | charstring_byte(139); 443 | } 444 | } 445 | 446 | /* This function returns one charstring token. It ignores comments. */ 447 | 448 | static void get_charstring_token(void) 449 | { 450 | int c = getc(ifp); 451 | while (isspace(c)) 452 | c = getc(ifp); 453 | 454 | if (c == '%') { 455 | while (c != EOF && c != '\r' && c != '\n') 456 | c = getc(ifp); 457 | get_charstring_token(); 458 | 459 | } else if (c == '}') { 460 | line[0] = '}'; 461 | line[1] = 0; 462 | 463 | } else { 464 | char *p = line; 465 | while (p < line + LINESIZE) { 466 | *p++ = c; 467 | c = getc(ifp); 468 | if (c == EOF || isspace(c) || c == '%' || c == '}') { 469 | ungetc(c, ifp); 470 | break; 471 | } 472 | } 473 | *p = 0; 474 | } 475 | } 476 | 477 | 478 | /* This function parses an entire charstring into integers and commands, 479 | outputting bytes through the charstring buffer. */ 480 | 481 | static void parse_charstring(void) 482 | { 483 | struct command *cp; 484 | 485 | charstring_start(); 486 | while (!feof(ifp)) { 487 | get_charstring_token(); 488 | if (line[0] == '}') 489 | break; 490 | if (is_integer(line)) { 491 | charstring_int(atoi(line)); 492 | } else { 493 | int one; 494 | int two; 495 | int ok = 0; 496 | 497 | cp = (struct command *) 498 | bsearch((void *) line, (void *) command_table, 499 | sizeof(command_table) / sizeof(struct command), 500 | sizeof(struct command), 501 | command_compare); 502 | 503 | if (cp) { 504 | one = cp->one; 505 | two = cp->two; 506 | ok = 1; 507 | 508 | } else if (strncmp(line, "escape_", 7) == 0) { 509 | /* Parse the `escape' keyword requested by Lee Chun-Yu and Werner 510 | Lemberg */ 511 | one = 12; 512 | if (sscanf(line + 7, "%d", &two) == 1) 513 | ok = 1; 514 | 515 | } else if (strncmp(line, "UNKNOWN_", 8) == 0) { 516 | /* Allow unanticipated UNKNOWN commands. */ 517 | one = 12; 518 | if (sscanf(line + 8, "12_%d", &two) == 1) 519 | ok = 1; 520 | else if (sscanf(line + 8, "%d", &one) == 1) { 521 | two = -1; 522 | ok = 1; 523 | } 524 | } 525 | 526 | if (!ok) 527 | error("unknown charstring command `%s'", line); 528 | else if (one < 0 || one > 255) 529 | error("bad charstring command number `%d'", one); 530 | else if (two > 255) 531 | error("bad charstring command number `%d'", two); 532 | else if (two < 0) 533 | charstring_byte(one); 534 | else { 535 | charstring_byte(one); 536 | charstring_byte(two); 537 | } 538 | } 539 | } 540 | charstring_end(); 541 | } 542 | 543 | 544 | /***** 545 | * Command line 546 | **/ 547 | 548 | #define BLOCK_LEN_OPT 300 549 | #define OUTPUT_OPT 301 550 | #define VERSION_OPT 302 551 | #define HELP_OPT 303 552 | #define PFB_OPT 304 553 | #define PFA_OPT 305 554 | 555 | static Clp_Option options[] = { 556 | { "block-length", 'l', BLOCK_LEN_OPT, Clp_ValInt, 0 }, 557 | { "help", 0, HELP_OPT, 0, 0 }, 558 | { "line-length", 0, BLOCK_LEN_OPT, Clp_ValInt, 0 }, 559 | { "output", 'o', OUTPUT_OPT, Clp_ValString, 0 }, 560 | { "pfa", 'a', PFA_OPT, 0, 0 }, 561 | { "pfb", 'b', PFB_OPT, 0, 0 }, 562 | { "version", 0, VERSION_OPT, 0, 0 }, 563 | }; 564 | static const char *program_name; 565 | 566 | void 567 | fatal_error(const char *message, ...) 568 | { 569 | va_list val; 570 | va_start(val, message); 571 | fprintf(stderr, "%s: ", program_name); 572 | vfprintf(stderr, message, val); 573 | putc('\n', stderr); 574 | va_end(val); 575 | exit(1); 576 | } 577 | 578 | void 579 | error(const char *message, ...) 580 | { 581 | va_list val; 582 | va_start(val, message); 583 | fprintf(stderr, "%s: ", program_name); 584 | vfprintf(stderr, message, val); 585 | putc('\n', stderr); 586 | va_end(val); 587 | } 588 | 589 | static void 590 | short_usage(void) 591 | { 592 | fprintf(stderr, "Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\ 593 | Try `%s --help' for more information.\n", 594 | program_name, program_name); 595 | } 596 | 597 | static void 598 | usage(void) 599 | { 600 | printf("\ 601 | `T1asm' translates a human-readable version of a PostScript Type 1 font into\n\ 602 | standard PFB or PFA format. The result is written to the standard output\n\ 603 | unless an OUTPUT file is given.\n\ 604 | \n\ 605 | Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\ 606 | \n\ 607 | Options:\n\ 608 | -a, --pfa Output font in ASCII (PFA) format.\n\ 609 | -b, --pfb Output font in binary (PFB) format. This is\n\ 610 | the default.\n\ 611 | -l, --block-length NUM Set max block length for PFB output.\n\ 612 | -l, --line-length NUM Set max encrypted line length for PFA output.\n\ 613 | -o, --output=FILE Write output to FILE.\n\ 614 | -h, --help Print this message and exit.\n\ 615 | --version Print version number and warranty and exit.\n\ 616 | \n\ 617 | Report bugs to .\n", program_name); 618 | } 619 | 620 | #ifdef __cplusplus 621 | } 622 | #endif 623 | 624 | 625 | int main(int argc, char *argv[]) 626 | { 627 | char *p, *q; 628 | 629 | Clp_Parser *clp = 630 | Clp_NewParser(argc, (const char * const *)argv, sizeof(options) / sizeof(options[0]), options); 631 | program_name = Clp_ProgramName(clp); 632 | 633 | /* interpret command line arguments using CLP */ 634 | while (1) { 635 | int opt = Clp_Next(clp); 636 | switch (opt) { 637 | 638 | case BLOCK_LEN_OPT: 639 | blocklen = clp->val.i; 640 | break; 641 | 642 | output_file: 643 | case OUTPUT_OPT: 644 | if (ofp) 645 | fatal_error("output file already specified"); 646 | if (strcmp(clp->vstr, "-") == 0) 647 | ofp = stdout; 648 | else if (!(ofp = fopen(clp->vstr, "w"))) 649 | fatal_error("%s: %s", clp->vstr, strerror(errno)); 650 | break; 651 | 652 | case PFB_OPT: 653 | pfb = 1; 654 | break; 655 | 656 | case PFA_OPT: 657 | pfb = 0; 658 | break; 659 | 660 | case HELP_OPT: 661 | usage(); 662 | exit(0); 663 | break; 664 | 665 | case VERSION_OPT: 666 | printf("t1asm (LCDF t1utils) %s\n", VERSION); 667 | printf("Copyright (C) 1992-2017 I. Lee Hetherington, Eddie Kohler et al.\n\ 668 | This is free software; see the source for copying conditions.\n\ 669 | There is NO warranty, not even for merchantability or fitness for a\n\ 670 | particular purpose.\n"); 671 | exit(0); 672 | break; 673 | 674 | case Clp_NotOption: 675 | if (ifp && ofp) 676 | fatal_error("too many arguments"); 677 | else if (ifp) 678 | goto output_file; 679 | if (strcmp(clp->vstr, "-") == 0) 680 | ifp = stdin; 681 | else if (!(ifp = fopen(clp->vstr, "r"))) 682 | fatal_error("%s: %s", clp->vstr, strerror(errno)); 683 | break; 684 | 685 | case Clp_Done: 686 | goto done; 687 | 688 | case Clp_BadOption: 689 | short_usage(); 690 | exit(1); 691 | break; 692 | 693 | } 694 | } 695 | 696 | done: 697 | if (!pfb) { 698 | if (blocklen == -1) 699 | blocklen = 64; 700 | else if (blocklen < 8) { 701 | blocklen = 8; 702 | error("warning: line length raised to %d", blocklen); 703 | } else if (blocklen > 1024) { 704 | blocklen = 1024; 705 | error("warning: line length lowered to %d", blocklen); 706 | } 707 | } 708 | 709 | if (!ifp) ifp = stdin; 710 | if (!ofp) ofp = stdout; 711 | 712 | if (pfb) 713 | init_pfb_writer(&w, blocklen, ofp); 714 | 715 | #if defined(_MSDOS) || defined(_WIN32) 716 | /* If we are processing a PFB (binary) output */ 717 | /* file, we must set its file mode to binary. */ 718 | if (pfb) 719 | _setmode(_fileno(ofp), _O_BINARY); 720 | #endif 721 | 722 | /* Finally, we loop until no more input. Some special things to look for are 723 | the `currentfile eexec' line, the beginning of the `/Subrs' or 724 | `/CharStrings' definition, the definition of `/lenIV', and the definition 725 | of the charstring start command which has `...string currentfile...' in 726 | it. 727 | 728 | Being careful: Check with `/Subrs' and `/CharStrings' to see that a 729 | number follows the token -- otherwise, the token is probably nested in a 730 | subroutine a la Adobe Jenson, and we shouldn't pay attention to it. 731 | 732 | Bugs: Occurrence of `/Subrs 9' in a comment will fool t1asm. 733 | 734 | Thanks to Tom Kacvinsky who reported that some fonts come 735 | without /Subrs sections and provided a patch. */ 736 | 737 | while (!feof(ifp) && !ferror(ifp)) { 738 | t1utils_getline(); 739 | 740 | if (!ever_active) { 741 | if (strncmp(line, "currentfile eexec", 17) == 0 && isspace((unsigned char) line[17])) { 742 | /* Allow arbitrary whitespace after "currentfile eexec". 743 | Thanks to Tom Kacvinsky for reporting this. 744 | Note: strlen("currentfile eexec") == 17. */ 745 | for (p = line + 18; isspace((unsigned char) *p); p++) 746 | ; 747 | eexec_start(p); 748 | continue; 749 | } else if (strncmp(line, "/lenIV", 6) == 0) { 750 | set_lenIV(line, strlen(line)); 751 | } else if ((p = strstr(line, "string currentfile"))) { 752 | set_cs_start(line, strlen(line)); 753 | } 754 | } 755 | 756 | if (!active) { 757 | if ((p = strstr(line, "/Subrs")) && isdigit((unsigned char) p[7])) 758 | ever_active = active = 1; 759 | else if ((p = strstr(line, "/CharStrings")) && isdigit((unsigned char) p[13])) 760 | ever_active = active = 1; 761 | } 762 | if ((p = strstr(line, "currentfile closefile"))) { 763 | /* 2/14/99 -- happy Valentine's day! -- don't look for `mark 764 | currentfile closefile'; the `mark' might be on a different line */ 765 | /* 1/3/2002 -- happy new year! -- Luc Devroye reports a failure with 766 | some printers when `currentfile closefile' is followed by space */ 767 | p += sizeof("currentfile closefile") - 1; 768 | for (q = p; isspace((unsigned char) *q) && *q != '\n'; q++) 769 | /* nada */; 770 | if (q == p && !*q) 771 | error("warning: `currentfile closefile' line too long"); 772 | else if (q != p) { 773 | if (*q != '\n') 774 | error("text after `currentfile closefile' ignored"); 775 | *p++ = '\n'; 776 | *p++ = '\0'; 777 | } 778 | eexec_string(line); 779 | break; 780 | } 781 | 782 | eexec_string(line); 783 | 784 | /* output line data */ 785 | if (start_charstring) { 786 | if (!cs_start[0]) 787 | fatal_error("couldn't find charstring start command"); 788 | parse_charstring(); 789 | } 790 | } 791 | 792 | /* Handle remaining PostScript after the eexec section */ 793 | if (in_eexec) 794 | eexec_end(); 795 | 796 | /* There may be additional code. */ 797 | while (!feof(ifp) && !ferror(ifp)) { 798 | t1utils_getline(); 799 | eexec_string(line); 800 | } 801 | 802 | if (pfb) 803 | pfb_writer_end(&w); 804 | 805 | /* the end! */ 806 | if (!ever_active) 807 | error("warning: no charstrings found in input file"); 808 | fclose(ifp); 809 | fclose(ofp); 810 | return 0; 811 | } 812 | -------------------------------------------------------------------------------- /t1asmhelp.h: -------------------------------------------------------------------------------- 1 | #ifndef T1ASMHELP_H 2 | #define T1ASMHELP_H 3 | 4 | static int lenIV = 4; 5 | 6 | /* If the line contains an entry of the form `/lenIV ' then set the global 7 | lenIV to . This indicates the number of random bytes at the beginning 8 | of each charstring. */ 9 | 10 | static void 11 | set_lenIV(const char* line, size_t line_len) 12 | { 13 | char* p = memmem(line, line_len, "/lenIV ", 7); 14 | 15 | /* Allow lenIV to be negative. Thanks to Tom Kacvinsky */ 16 | if (p && p + 7 < line + line_len) { 17 | const char* x = p + 7 + (p[7] == '+' || p[7] == '-'); 18 | if (x < line + line_len && isdigit((unsigned char) *x)) { 19 | lenIV = (unsigned char) *x - '0'; 20 | for (++x; x < line + line_len && isdigit((unsigned char) *x); ++x) 21 | lenIV = 10 * lenIV + (unsigned char) *x - '0'; 22 | if (p[7] == '-') 23 | lenIV = -lenIV; 24 | } 25 | } 26 | } 27 | 28 | 29 | static const char* cs_start = ""; 30 | 31 | static void 32 | set_cs_start(const char* line, size_t line_len) 33 | { 34 | static int cs_start_set = 0; 35 | char *p, *q, *r; 36 | 37 | if ((p = memmem(line, line_len, "string currentfile", 18)) 38 | && memmem(line, line_len, "readstring", 10)) { 39 | /* locate the name of the charstring start command */ 40 | for (q = p; q != line && q[-1] != '/'; --q) 41 | /* nada */; 42 | if (q != line) { 43 | for (r = q; r != p && !isspace((unsigned char) *r) && *r != '{'; ++r) 44 | /* nada */; 45 | if (cs_start_set) 46 | free((char*) cs_start); 47 | cs_start = p = malloc(r - q + 1); 48 | memcpy(p, q, r - q); 49 | p[r - q] = 0; 50 | cs_start_set = 1; 51 | } 52 | } 53 | } 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /t1binary.1: -------------------------------------------------------------------------------- 1 | .ds V 1.42 2 | .de M 3 | .BR "\\$1" "(\\$2)\\$3" 4 | .. 5 | .TH T1BINARY 1 "" "Version \*V" 6 | .SH NAME 7 | t1binary \- convert PostScript Type 1 font from ASCII to binary 8 | .SH SYNOPSIS 9 | .B t1binary 10 | \%[\fB\-l\fR \fIlength\fR] 11 | \%[\fIinput\fR [\fIoutput\fR]] 12 | .SH DESCRIPTION 13 | .B t1binary 14 | converts Adobe Type 1 font programs in PFA (hexadecimal) format to PFB 15 | (binary) format. If the file 16 | .I output 17 | is not specified output goes to the standard output. 18 | If the file 19 | .I input 20 | is not specified input comes from the standard input. 21 | .SH OPTIONS 22 | .TP 5 23 | .BI \-\-block\-length= "length\fR, " \-l " length" 24 | Set the maximum length of sections in PFB output to 25 | .I length. 26 | The default length is as large as memory allows. 27 | .SH "SEE ALSO" 28 | .LP 29 | .M t1ascii 1 , 30 | .M t1unmac 1 , 31 | .M t1mac 1 , 32 | .M t1disasm 1 , 33 | .M t1asm 1 34 | .LP 35 | .I "Adobe Type 1 Font Format" 36 | .SH AUTHORS 37 | Lee Hetherington (ilh@lcs.mit.edu) 38 | .br 39 | Eddie Kohler (ekohler@gmail.com) 40 | .PP 41 | Ported to Microsoft C/C++ Compiler and MS-DOS operating system by 42 | Kai-Uwe Herbing (herbing@netmbx.netmbx.de). 43 | -------------------------------------------------------------------------------- /t1binary.c: -------------------------------------------------------------------------------- 1 | /* t1binary 2 | * 3 | * This program takes an Adobe Type-1 font program in ASCII (PFA) format and 4 | * converts it to binary (PFB) format. 5 | * 6 | * Copyright (c) 1992 by I. Lee Hetherington, all rights reserved. 7 | * Copyright (c) 1998-2017 Eddie Kohler 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a 10 | * copy of this software and associated documentation files (the 11 | * "Software"), to deal in the Software without restriction, subject to the 12 | * conditions listed in the Click LICENSE file, which is available in full at 13 | * http://github.com/kohler/click/blob/master/LICENSE. The conditions 14 | * include: you must preserve this copyright notice, and you cannot mention 15 | * the copyright holders in advertising related to the Software without 16 | * their permission. The Software is provided WITHOUT ANY WARRANTY, EXPRESS 17 | * OR IMPLIED. This notice is a summary of the Click LICENSE file; the 18 | * license in that file is binding. 19 | * 20 | * New change log in `NEWS'. Old change log: 21 | * 22 | * Revision 1.2 92/06/23 10:58:08 ilh 23 | * MSDOS porting by Kai-Uwe Herbing (herbing@netmbx.netmbx.de) 24 | * incoporated. 25 | * 26 | * Revision 1.1 92/05/22 11:58:17 ilh 27 | * initial version 28 | * 29 | * Ported to Microsoft C/C++ Compiler and MS-DOS operating system by 30 | * Kai-Uwe Herbing (herbing@netmbx.netmbx.de) on June 12, 1992. Code 31 | * specific to the MS-DOS version is encapsulated with #ifdef _MSDOS 32 | * ... #endif, where _MSDOS is an identifier, which is automatically 33 | * defined, if you compile with the Microsoft C/C++ Compiler. 34 | * 35 | */ 36 | 37 | /* Note: this is ANSI C. */ 38 | 39 | #ifdef HAVE_CONFIG_H 40 | # include 41 | #endif 42 | #if defined(_MSDOS) || defined(_WIN32) 43 | # include 44 | # include 45 | #endif 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include "t1lib.h" 55 | 56 | #ifdef __cplusplus 57 | extern "C" { 58 | #endif 59 | 60 | typedef unsigned char byte; 61 | 62 | /* for PFB block buffering */ 63 | static struct pfb_writer w; 64 | 65 | 66 | /* PFB font_reader functions */ 67 | 68 | static void 69 | pfb_output_ascii(char *s, int len) 70 | { 71 | if (w.blocktyp == PFB_BINARY) { 72 | pfb_writer_output_block(&w); 73 | w.blocktyp = PFB_ASCII; 74 | } 75 | for (; len > 0; len--, s++) 76 | PFB_OUTPUT_BYTE(&w, (byte)*s); 77 | } 78 | 79 | static void 80 | pfb_output_binary(unsigned char *s, int len) 81 | { 82 | if (w.blocktyp == PFB_ASCII) { 83 | pfb_writer_output_block(&w); 84 | w.blocktyp = PFB_BINARY; 85 | } 86 | for (; len > 0; len--, s++) 87 | PFB_OUTPUT_BYTE(&w, *s); 88 | } 89 | 90 | static void 91 | pfb_output_end(void) 92 | { 93 | pfb_writer_end(&w); 94 | } 95 | 96 | 97 | /***** 98 | * Command line 99 | **/ 100 | 101 | #define BLOCK_LEN_OPT 300 102 | #define OUTPUT_OPT 301 103 | #define VERSION_OPT 302 104 | #define HELP_OPT 303 105 | 106 | static Clp_Option options[] = { 107 | { "block-length", 'l', BLOCK_LEN_OPT, Clp_ValInt, 0 }, 108 | { "help", 0, HELP_OPT, 0, 0 }, 109 | { "length", 0, BLOCK_LEN_OPT, Clp_ValInt, 0 }, 110 | { "output", 'o', OUTPUT_OPT, Clp_ValString, 0 }, 111 | { "version", 0, VERSION_OPT, 0, 0 }, 112 | }; 113 | static const char *program_name; 114 | 115 | 116 | void 117 | fatal_error(const char *message, ...) 118 | { 119 | va_list val; 120 | va_start(val, message); 121 | fprintf(stderr, "%s: ", program_name); 122 | vfprintf(stderr, message, val); 123 | putc('\n', stderr); 124 | va_end(val); 125 | exit(1); 126 | } 127 | 128 | void 129 | error(const char *message, ...) 130 | { 131 | va_list val; 132 | va_start(val, message); 133 | fprintf(stderr, "%s: ", program_name); 134 | vfprintf(stderr, message, val); 135 | putc('\n', stderr); 136 | va_end(val); 137 | } 138 | 139 | 140 | static void 141 | short_usage(void) 142 | { 143 | fprintf(stderr, "Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\ 144 | Try `%s --help' for more information.\n", 145 | program_name, program_name); 146 | } 147 | 148 | 149 | static void 150 | usage(void) 151 | { 152 | printf("\ 153 | `T1binary' translates a PostScript Type 1 font from ASCII (PFA) to compact\n\ 154 | binary (PFB) format. The result is written to the standard output unless an\n\ 155 | OUTPUT file is given.\n\ 156 | \n\ 157 | Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\ 158 | \n\ 159 | Options:\n\ 160 | -l, --block-length=NUM Set max output block length.\n\ 161 | -o, --output=FILE Write output to FILE.\n\ 162 | -h, --help Print this message and exit.\n\ 163 | --version Print version number and warranty and exit.\n\ 164 | \n\ 165 | Report bugs to .\n", program_name); 166 | } 167 | 168 | #ifdef __cplusplus 169 | } 170 | #endif 171 | 172 | 173 | int 174 | main(int argc, char *argv[]) 175 | { 176 | int c; 177 | FILE *ifp = 0, *ofp = 0; 178 | const char *ifp_filename = ""; 179 | struct font_reader fr; 180 | int max_blocklen = -1; 181 | 182 | Clp_Parser *clp = 183 | Clp_NewParser(argc, (const char * const *)argv, sizeof(options) / sizeof(options[0]), options); 184 | program_name = Clp_ProgramName(clp); 185 | 186 | /* interpret command line arguments using CLP */ 187 | while (1) { 188 | int opt = Clp_Next(clp); 189 | switch (opt) { 190 | 191 | case BLOCK_LEN_OPT: 192 | max_blocklen = clp->val.i; 193 | if (max_blocklen <= 0) { 194 | max_blocklen = 1; 195 | error("warning: block length raised to %d", max_blocklen); 196 | } 197 | break; 198 | 199 | output_file: 200 | case OUTPUT_OPT: 201 | if (ofp) 202 | fatal_error("output file already specified"); 203 | if (strcmp(clp->vstr, "-") == 0) 204 | ofp = stdout; 205 | else { 206 | ofp = fopen(clp->vstr, "wb"); 207 | if (!ofp) fatal_error("%s: %s", clp->vstr, strerror(errno)); 208 | } 209 | break; 210 | 211 | case HELP_OPT: 212 | usage(); 213 | exit(0); 214 | break; 215 | 216 | case VERSION_OPT: 217 | printf("t1binary (LCDF t1utils) %s\n", VERSION); 218 | printf("Copyright (C) 1992-2017 I. Lee Hetherington, Eddie Kohler et al.\n\ 219 | This is free software; see the source for copying conditions.\n\ 220 | There is NO warranty, not even for merchantability or fitness for a\n\ 221 | particular purpose.\n"); 222 | exit(0); 223 | break; 224 | 225 | case Clp_NotOption: 226 | if (ifp && ofp) 227 | fatal_error("too many arguments"); 228 | else if (ifp) 229 | goto output_file; 230 | if (strcmp(clp->vstr, "-") == 0) 231 | ifp = stdin; 232 | else { 233 | ifp_filename = clp->vstr; 234 | ifp = fopen(clp->vstr, "r"); 235 | if (!ifp) fatal_error("%s: %s", clp->vstr, strerror(errno)); 236 | } 237 | break; 238 | 239 | case Clp_Done: 240 | goto done; 241 | 242 | case Clp_BadOption: 243 | short_usage(); 244 | exit(1); 245 | break; 246 | 247 | } 248 | } 249 | 250 | done: 251 | if (!ifp) ifp = stdin; 252 | if (!ofp) ofp = stdout; 253 | 254 | #if defined(_MSDOS) || defined(_WIN32) 255 | /* As we are processing a PFB (binary) output */ 256 | /* file, we must set its file mode to binary. */ 257 | _setmode(_fileno(ofp), _O_BINARY); 258 | #endif 259 | 260 | /* prepare font reader and pfb writer */ 261 | fr.output_ascii = pfb_output_ascii; 262 | fr.output_binary = pfb_output_binary; 263 | fr.output_end = pfb_output_end; 264 | init_pfb_writer(&w, max_blocklen, ofp); 265 | 266 | /* peek at first byte to see if it is the PFB marker 0x80 */ 267 | c = getc(ifp); 268 | ungetc(c, ifp); 269 | 270 | /* do the file */ 271 | if (c == PFB_MARKER) 272 | process_pfb(ifp, ifp_filename, &fr); 273 | else if (c == '%') 274 | process_pfa(ifp, ifp_filename, &fr); 275 | else 276 | fatal_error("%s does not start with font marker (`%%' or 0x80)", ifp_filename); 277 | 278 | fclose(ifp); 279 | fclose(ofp); 280 | 281 | if (!w.binary_blocks_written) 282 | fatal_error("no binary blocks written! Are you sure this was a font?"); 283 | 284 | return 0; 285 | } 286 | -------------------------------------------------------------------------------- /t1disasm.1: -------------------------------------------------------------------------------- 1 | .ds V 1.42 2 | .de M 3 | .BR "\\$1" "(\\$2)\\$3" 4 | .. 5 | .TH T1DISASM 1 "" "Version \*V" 6 | .SH NAME 7 | t1disasm \- disassemble PostScript Type 1 font 8 | .SH SYNOPSIS 9 | .B t1disasm 10 | \%[\fIinput\fR [\fIoutput\fR]] 11 | .SH DESCRIPTION 12 | .B t1disasm 13 | disassembles Adobe Type 1 font programs in either PFA (hexadecimal) or PFB 14 | (binary) formats into human-readable form. If the file 15 | .I output 16 | is not specified output goes to the standard output. 17 | If the file 18 | .I input 19 | is not specified input comes from the standard input. 20 | 21 | .B t1disasm 22 | performs eexec and charstring decryption as specified in the ``black 23 | book'', 24 | .I "Adobe Type 1 Font Format." 25 | Additionally, the charstring binary tokens are expanded into human-readable 26 | text form, using the names given in the black book and later documents 27 | describing Type 2 opcodes. 28 | .SH EXAMPLES 29 | .LP 30 | .nf 31 | % t1disasm Utopia-Regular.pfb Utopia-Regular.raw 32 | % t1disasm Utopia-Regular.pfa Utopia-Regular.raw 33 | .fi 34 | 35 | In 36 | .B Subrs 37 | entries in Utopia-Regular.raw will look like 38 | .RS 39 | .nf 40 | .ft B 41 | dup 5 { 42 | 8 111 vstem 43 | \-12 128 hstem 44 | 707 \-20 hstem 45 | return 46 | } | 47 | .ft R 48 | .fi 49 | .RE 50 | and the 51 | .B CharStrings 52 | entries like 53 | .RS 54 | .nf 55 | .ft B 56 | /exclam { 57 | 58 242 hsbw 58 | 6 callsubr 59 | 5 4 callsubr 60 | 63 707 rmoveto 61 | \-54 0 \-5 \-22 4 \-45 rrcurveto 62 | 40 \-431 rlineto 63 | 29 hlineto 64 | 42 431 rlineto 65 | 4 45 \-5 22 \-55 0 rrcurveto 66 | closepath 67 | 6 4 callsubr 68 | \-719 vmoveto 69 | 243 callsubr 70 | endchar 71 | } |\- 72 | .ft R 73 | .fi 74 | .RE 75 | .SH "SEE ALSO" 76 | .LP 77 | .M t1asm 1 , 78 | .M t1ascii 1 , 79 | .M t1binary 1 , 80 | .M t1unmac 1 , 81 | .M t1mac 1 82 | .LP 83 | .I "Adobe Type 1 Font Format" 84 | is available free from Adobe as a PDF file: 85 | http://partners.adobe.com/asn/developer/PDFS/TN/T1_SPEC.PDF 86 | .LP 87 | .I "The Type 2 Charstring Format," 88 | also available from Adobe as a PDF file, describes the newer Type 2 89 | operators, which are also used in some multiple-master Type 1 fonts like 90 | Adobe Jenson and Kepler: 91 | http://partners.adobe.com/asn/developer/PDFS/TN/5177.Type2.pdf 92 | ' 93 | .SH AUTHORS 94 | Lee Hetherington (ilh@lcs.mit.edu) 95 | .br 96 | Eddie Kohler (ekohler@gmail.com) 97 | -------------------------------------------------------------------------------- /t1disasm.c: -------------------------------------------------------------------------------- 1 | /* t1disasm 2 | * 3 | * This program `disassembles' Adobe Type-1 font programs in either PFB or PFA 4 | * format. It produces a human readable/editable pseudo-PostScript file by 5 | * performing eexec and charstring decryption as specified in the `Adobe Type 1 6 | * Font Format' version 1.1 (the `black book'). There is a companion program, 7 | * t1asm, which `assembles' such a pseudo-PostScript file into either PFB or 8 | * PFA format. 9 | * 10 | * Copyright (c) 1992 by I. Lee Hetherington, all rights reserved. 11 | * Copyright (c) 1998-2017 Eddie Kohler 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a 14 | * copy of this software and associated documentation files (the 15 | * "Software"), to deal in the Software without restriction, subject to the 16 | * conditions listed in the Click LICENSE file, which is available in full at 17 | * http://github.com/kohler/click/blob/master/LICENSE. The conditions 18 | * include: you must preserve this copyright notice, and you cannot mention 19 | * the copyright holders in advertising related to the Software without 20 | * their permission. The Software is provided WITHOUT ANY WARRANTY, EXPRESS 21 | * OR IMPLIED. This notice is a summary of the Click LICENSE file; the 22 | * license in that file is binding. 23 | * 24 | * New change log in `NEWS'. Old change log: 25 | * 26 | * Revision 1.4 92/07/10 10:55:08 ilh 27 | * Added support for additional PostScript after the closefile command 28 | * (ie., some fonts have {restore}if' after the cleartomark). Also, 29 | * removed hardwired charstring start command (-| or RD) in favor of 30 | * automatically determining it. 31 | * 32 | * Revision 1.3 92/06/23 10:57:53 ilh 33 | * MSDOS porting by Kai-Uwe Herbing (herbing@netmbx.netmbx.de) 34 | * incoporated. 35 | * 36 | * Revision 1.2 92/05/22 12:05:33 ilh 37 | * Fixed bug where we were counting on sprintf to return its first 38 | * argument---not true in ANSI C. This bug was detected by Piet 39 | * Tutelaers (rcpt@urc.tue.nl). Also, fixed (signed) integer overflow 40 | * error when testing high-order bit of integer for possible 41 | * sign-extension by making comparison between unsigned integers. 42 | * 43 | * Revision 1.1 92/05/22 12:04:07 ilh 44 | * initial version 45 | * 46 | * Ported to Microsoft C/C++ Compiler and MS-DOS operating system by 47 | * Kai-Uwe Herbing (herbing@netmbx.netmbx.de) on June 12, 1992. Code 48 | * specific to the MS-DOS version is encapsulated with #ifdef _MSDOS 49 | * ... #endif, where _MSDOS is an identifier, which is automatically 50 | * defined, if you compile with the Microsoft C/C++ Compiler. 51 | * 52 | */ 53 | 54 | /* Note: this is ANSI C. */ 55 | 56 | #ifdef HAVE_CONFIG_H 57 | # include 58 | #endif 59 | #if defined(_MSDOS) || defined(_WIN32) 60 | # include 61 | # include 62 | #endif 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include "t1lib.h" 73 | #include "t1asmhelp.h" 74 | 75 | #ifdef __cplusplus 76 | extern "C" { 77 | #endif 78 | 79 | typedef unsigned char byte; 80 | 81 | static FILE *ofp; 82 | static int unknown = 0; 83 | 84 | /* decryption stuff */ 85 | static const uint32_t c1 = 52845; 86 | static const uint32_t c2 = 22719; 87 | static uint16_t cr_default = 4330; 88 | static uint16_t er_default = 55665; 89 | 90 | static int error_count = 0; 91 | 92 | 93 | /* Subroutine to output strings. */ 94 | 95 | static void 96 | output(const char *string) 97 | { 98 | fprintf(ofp, "%s", string); 99 | } 100 | 101 | /* Subroutine to neatly format output of charstring tokens. If token = "\n", 102 | then a newline is output. If at start of line (start == 1), prefix token 103 | with tab, otherwise a space. */ 104 | 105 | static void 106 | output_token(const char *token) 107 | { 108 | static int start = 1; 109 | if (strcmp(token, "\n") == 0) { 110 | fprintf(ofp, "\n"); 111 | start = 1; 112 | } else { 113 | fprintf(ofp, "%s%s", start ? "\t" : " ", token); 114 | start = 0; 115 | } 116 | } 117 | 118 | /* Subroutine to decrypt and ASCII-ify tokens in charstring data. The 119 | charstring decryption machinery is fired up, skipping the first lenIV 120 | bytes, and the decrypted tokens are expanded into human-readable form. */ 121 | 122 | static void 123 | decrypt_charstring(unsigned char *line, int len) 124 | { 125 | int i; 126 | int32_t val; 127 | char buf[20]; 128 | 129 | /* decrypt charstring */ 130 | if (lenIV >= 0) { 131 | /* only decrypt if lenIV >= 0 -- negative lenIV means unencrypted 132 | charstring. Thanks to Tom Kacvinsky */ 133 | uint16_t cr = cr_default; 134 | byte plain; 135 | for (i = 0; i < len; i++) { 136 | byte cipher = line[i]; 137 | plain = (byte)(cipher ^ (cr >> 8)); 138 | cr = (uint16_t)((cipher + cr) * c1 + c2); 139 | line[i] = plain; 140 | } 141 | line += lenIV; 142 | len -= lenIV; 143 | } 144 | 145 | /* handle each charstring command */ 146 | for (i = 0; i < len; i++) { 147 | byte b = line[i]; 148 | 149 | if (b >= 32) { 150 | if (b >= 32 && b <= 246) 151 | val = b - 139; 152 | else if (b >= 247 && b <= 250) { 153 | i++; 154 | val = (b - 247)*256 + 108 + line[i]; 155 | } else if (b >= 251 && b <= 254) { 156 | i++; 157 | val = -(b - 251)*256 - 108 - line[i]; 158 | } else { 159 | uint32_t uval; 160 | uval = (uint32_t) line[i+1] << 24; 161 | uval |= (uint32_t) line[i+2] << 16; 162 | uval |= (uint32_t) line[i+3] << 8; 163 | uval |= (uint32_t) line[i+4] << 0; 164 | /* in case an int32 is larger than four bytes---sign extend */ 165 | #if INT_MAX > 0x7FFFFFFFUL 166 | if (uval & 0x80000000U) 167 | uval |= ~0x7FFFFFFFU; 168 | #endif 169 | val = (int32_t) uval; 170 | i += 4; 171 | } 172 | sprintf(buf, "%d", val); 173 | output_token(buf); 174 | 175 | } else { 176 | switch (b) { 177 | case 0: output_token("error"); break; /* special */ 178 | case 1: output_token("hstem"); break; 179 | case 3: output_token("vstem"); break; 180 | case 4: output_token("vmoveto"); break; 181 | case 5: output_token("rlineto"); break; 182 | case 6: output_token("hlineto"); break; 183 | case 7: output_token("vlineto"); break; 184 | case 8: output_token("rrcurveto"); break; 185 | case 9: output_token("closepath"); break; /* Type 1 ONLY */ 186 | case 10: output_token("callsubr"); break; 187 | case 11: output_token("return"); break; 188 | case 13: output_token("hsbw"); break; /* Type 1 ONLY */ 189 | case 14: output_token("endchar"); break; 190 | case 16: output_token("blend"); break; /* Type 2 */ 191 | case 18: output_token("hstemhm"); break; /* Type 2 */ 192 | case 19: output_token("hintmask"); break; /* Type 2 */ 193 | case 20: output_token("cntrmask"); break; /* Type 2 */ 194 | case 21: output_token("rmoveto"); break; 195 | case 22: output_token("hmoveto"); break; 196 | case 23: output_token("vstemhm"); break; /* Type 2 */ 197 | case 24: output_token("rcurveline"); break; /* Type 2 */ 198 | case 25: output_token("rlinecurve"); break; /* Type 2 */ 199 | case 26: output_token("vvcurveto"); break; /* Type 2 */ 200 | case 27: output_token("hhcurveto"); break; /* Type 2 */ 201 | case 28: { /* Type 2 */ 202 | /* short integer */ 203 | val = (line[i+1] & 0xff) << 8; 204 | val |= (line[i+2] & 0xff); 205 | i += 2; 206 | if (val & 0x8000) 207 | val |= ~0x7FFF; 208 | sprintf(buf, "%d", val); 209 | output_token(buf); 210 | } 211 | case 29: output_token("callgsubr"); break; /* Type 2 */ 212 | case 30: output_token("vhcurveto"); break; 213 | case 31: output_token("hvcurveto"); break; 214 | case 12: 215 | i++; 216 | b = line[i]; 217 | switch (b) { 218 | case 0: output_token("dotsection"); break; /* Type 1 ONLY */ 219 | case 1: output_token("vstem3"); break; /* Type 1 ONLY */ 220 | case 2: output_token("hstem3"); break; /* Type 1 ONLY */ 221 | case 3: output_token("and"); break; /* Type 2 */ 222 | case 4: output_token("or"); break; /* Type 2 */ 223 | case 5: output_token("not"); break; /* Type 2 */ 224 | case 6: output_token("seac"); break; /* Type 1 ONLY */ 225 | case 7: output_token("sbw"); break; /* Type 1 ONLY */ 226 | case 8: output_token("store"); break; /* Type 2 */ 227 | case 9: output_token("abs"); break; /* Type 2 */ 228 | case 10: output_token("add"); break; /* Type 2 */ 229 | case 11: output_token("sub"); break; /* Type 2 */ 230 | case 12: output_token("div"); break; 231 | case 13: output_token("load"); break; /* Type 2 */ 232 | case 14: output_token("neg"); break; /* Type 2 */ 233 | case 15: output_token("eq"); break; /* Type 2 */ 234 | case 16: output_token("callothersubr"); break; /* Type 1 ONLY */ 235 | case 17: output_token("pop"); break; /* Type 1 ONLY */ 236 | case 18: output_token("drop"); break; /* Type 2 */ 237 | case 20: output_token("put"); break; /* Type 2 */ 238 | case 21: output_token("get"); break; /* Type 2 */ 239 | case 22: output_token("ifelse"); break; /* Type 2 */ 240 | case 23: output_token("random"); break; /* Type 2 */ 241 | case 24: output_token("mul"); break; /* Type 2 */ 242 | case 26: output_token("sqrt"); break; /* Type 2 */ 243 | case 27: output_token("dup"); break; /* Type 2 */ 244 | case 28: output_token("exch"); break; /* Type 2 */ 245 | case 29: output_token("index"); break; /* Type 2 */ 246 | case 30: output_token("roll"); break; /* Type 2 */ 247 | case 33: output_token("setcurrentpoint"); break;/* Type 1 ONLY */ 248 | case 34: output_token("hflex"); break; /* Type 2 */ 249 | case 35: output_token("flex"); break; /* Type 2 */ 250 | case 36: output_token("hflex1"); break; /* Type 2 */ 251 | case 37: output_token("flex1"); break; /* Type 2 */ 252 | default: 253 | sprintf(buf, "escape_%d", b); 254 | unknown++; 255 | output_token(buf); 256 | break; 257 | } 258 | break; 259 | default: 260 | sprintf(buf, "UNKNOWN_%d", b); 261 | unknown++; 262 | output_token(buf); 263 | break; 264 | } 265 | output_token("\n"); 266 | } 267 | } 268 | if (i > len) { 269 | output("\terror\n"); 270 | error("disassembly error: charstring too short"); 271 | } 272 | } 273 | 274 | 275 | /* Disassembly font_reader functions */ 276 | 277 | static int in_eexec = 0; 278 | static unsigned char *save = 0; 279 | static int save_len = 0; 280 | static int save_cap = 0; 281 | 282 | static void 283 | append_save(const unsigned char *line, int len) 284 | { 285 | if (line == save) { 286 | assert(len <= save_cap); 287 | save_len = len; 288 | return; 289 | } 290 | if (save_len + len >= save_cap) { 291 | unsigned char *new_save; 292 | if (!save_cap) save_cap = 1024; 293 | while (save_len + len >= save_cap) save_cap *= 2; 294 | new_save = (unsigned char *)malloc(save_cap); 295 | if (!new_save) 296 | fatal_error("out of memory"); 297 | memcpy(new_save, save, save_len); 298 | free(save); 299 | save = new_save; 300 | } 301 | memcpy(save + save_len, line, len); 302 | save_len += len; 303 | } 304 | 305 | 306 | static unsigned char* 307 | check_eexec_charstrings_begin(unsigned char* line, int line_len) 308 | { 309 | unsigned char* line_end = line + line_len; 310 | line = memmem(line, line_len, "/CharStrings ", 13); 311 | if (!line) 312 | return 0; 313 | line += 13; 314 | while (line < line_end && isspace(*line)) 315 | ++line; 316 | if (line == line_end || !isdigit(*line)) 317 | return 0; 318 | while (line < line_end && isdigit(*line)) 319 | ++line; 320 | if (line == line_end || !isspace(*line)) 321 | return 0; 322 | while (line < line_end && isspace(*line)) 323 | ++line; 324 | if (line_end - line < 14 || memcmp(line, "dict dup begin", 14) != 0) 325 | return 0; 326 | line += 14; 327 | while (line < line_end && isspace(*line)) 328 | ++line; 329 | if (line == line_end || *line != '/') 330 | return 0; 331 | return line; 332 | } 333 | 334 | 335 | /* returns 1 if next \n should be deleted */ 336 | 337 | static int 338 | eexec_line(unsigned char *line, int line_len) 339 | { 340 | int cs_start_len = strlen(cs_start); 341 | int pos; 342 | int first_space; 343 | int digits; 344 | int cut_newline = 0; 345 | 346 | /* append this data to the end of `save' if necessary */ 347 | if (save_len) { 348 | append_save(line, line_len); 349 | line = save; 350 | line_len = save_len; 351 | save_len = 0; 352 | } 353 | 354 | if (!line_len) 355 | return 0; 356 | 357 | /* Look for charstring start */ 358 | 359 | /* skip first word */ 360 | for (pos = 0; pos < line_len && isspace(line[pos]); pos++) 361 | ; 362 | while (pos < line_len && !isspace(line[pos])) 363 | pos++; 364 | if (pos >= line_len) 365 | goto not_charstring; 366 | 367 | /* skip spaces */ 368 | first_space = pos; 369 | while (pos < line_len && isspace(line[pos])) 370 | pos++; 371 | if (pos >= line_len || !isdigit(line[pos])) 372 | goto not_charstring; 373 | 374 | /* skip number */ 375 | digits = pos; 376 | while (pos < line_len && isdigit(line[pos])) 377 | pos++; 378 | 379 | /* check for subr (another number) */ 380 | if (pos < line_len - 1 && isspace(line[pos]) && isdigit(line[pos+1])) { 381 | first_space = pos; 382 | digits = pos + 1; 383 | for (pos = digits; pos < line_len && isdigit(line[pos]); pos++) 384 | ; 385 | } 386 | 387 | /* check for charstring start */ 388 | if (pos + 2 + cs_start_len < line_len 389 | && pos > digits 390 | && line[pos] == ' ' 391 | && strncmp((const char *)(line + pos + 1), cs_start, cs_start_len) == 0 392 | && line[pos + 1 + cs_start_len] == ' ') { 393 | /* check if charstring is long enough */ 394 | int cs_len = atoi((const char *)(line + digits)); 395 | if (pos + 2 + cs_start_len + cs_len < line_len) { 396 | /* long enough! */ 397 | if (line[line_len - 1] == '\r') { 398 | line[line_len - 1] = '\n'; 399 | cut_newline = 1; 400 | } 401 | fprintf(ofp, "%.*s {\n", first_space, line); 402 | decrypt_charstring(line + pos + 2 + cs_start_len, cs_len); 403 | pos += 2 + cs_start_len + cs_len; 404 | fprintf(ofp, "\t}%.*s", line_len - pos, line + pos); 405 | return cut_newline; 406 | } else { 407 | /* not long enough! */ 408 | append_save(line, line_len); 409 | return 0; 410 | } 411 | } 412 | 413 | /* otherwise, just output the line */ 414 | not_charstring: 415 | /* 6.Oct.2003 - Werner Lemberg reports a stupid Omega font that behaves 416 | badly: a charstring definition follows "/Charstrings ... begin", ON THE 417 | SAME LINE. */ 418 | { 419 | unsigned char* csbegin = check_eexec_charstrings_begin(line, line_len); 420 | if (csbegin) { 421 | int len = csbegin - line; 422 | fprintf(ofp, "%.*s\n", len, line); 423 | return eexec_line(csbegin, line_len - len); 424 | } 425 | } 426 | 427 | if (line[line_len - 1] == '\r') { 428 | line[line_len - 1] = '\n'; 429 | cut_newline = 1; 430 | } 431 | set_lenIV((char*) line, line_len); 432 | set_cs_start((char*) line, line_len); 433 | fprintf(ofp, "%.*s", line_len, line); 434 | 435 | /* look for `currentfile closefile' to see if we should stop decrypting */ 436 | if (memmem(line, line_len, "currentfile closefile", 21) != 0) 437 | in_eexec = -1; 438 | 439 | return cut_newline; 440 | } 441 | 442 | static int 443 | all_zeroes(const char *string) 444 | { 445 | if (*string != '0') 446 | return 0; 447 | while (*string == '0') 448 | string++; 449 | return *string == '\0' || *string == '\n'; 450 | } 451 | 452 | static void 453 | disasm_output_ascii(char *line, int len) 454 | { 455 | int was_in_eexec = in_eexec; 456 | (void) len; /* avoid warning */ 457 | in_eexec = 0; 458 | 459 | /* if we came from a binary section, we need to process that too */ 460 | if (was_in_eexec > 0) { 461 | unsigned char zero = 0; 462 | eexec_line(&zero, 0); 463 | } 464 | 465 | /* if we just came from the "ASCII part" of an eexec section, we need to 466 | process the saved lines */ 467 | if (was_in_eexec < 0) { 468 | int i = 0; 469 | int save_char = 0; /* note: save[] is unsigned char * */ 470 | 471 | while (i < save_len) { 472 | /* grab a line */ 473 | int start = i; 474 | while (i < save_len && save[i] != '\r' && save[i] != '\n') 475 | i++; 476 | if (i < save_len) { 477 | if (i < save_len - 1 && save[i] == '\r' && save[i+1] == '\n') 478 | save_char = -1; 479 | else 480 | save_char = save[i+1]; 481 | save[i] = '\n'; 482 | save[i+1] = 0; 483 | } else 484 | save[i] = 0; 485 | 486 | /* output it */ 487 | disasm_output_ascii((char *)(save + start), -1); 488 | 489 | /* repair damage */ 490 | if (i < save_len) { 491 | if (save_char >= 0) { 492 | save[i+1] = save_char; 493 | i++; 494 | } else 495 | i += 2; 496 | } 497 | } 498 | save_len = 0; 499 | } 500 | 501 | if (!all_zeroes(line)) 502 | output(line); 503 | } 504 | 505 | /* collect until '\n' or end of binary section */ 506 | 507 | static void 508 | disasm_output_binary(unsigned char *data, int len) 509 | { 510 | static int ignore_newline; 511 | static uint16_t er; 512 | 513 | byte plain; 514 | int i; 515 | 516 | /* in the ASCII portion of a binary section, just save this data */ 517 | if (in_eexec < 0) { 518 | append_save(data, len); 519 | return; 520 | } 521 | 522 | /* eexec initialization */ 523 | if (in_eexec == 0) { 524 | er = er_default; 525 | ignore_newline = 0; 526 | in_eexec = 0; 527 | } 528 | if (in_eexec < 4) { 529 | for (i = 0; i < len && in_eexec < 4; i++, in_eexec++) { 530 | byte cipher = data[i]; 531 | plain = (byte)(cipher ^ (er >> 8)); 532 | er = (uint16_t)((cipher + er) * c1 + c2); 533 | data[i] = plain; 534 | } 535 | data += i; 536 | len -= i; 537 | } 538 | 539 | /* now make lines: collect until '\n' or '\r' and pass them off to 540 | eexec_line. */ 541 | i = 0; 542 | while (in_eexec > 0) { 543 | int start = i; 544 | 545 | for (; i < len; i++) { 546 | byte cipher = data[i]; 547 | plain = (byte)(cipher ^ (er >> 8)); 548 | er = (uint16_t)((cipher + er) * c1 + c2); 549 | data[i] = plain; 550 | if (plain == '\r' || plain == '\n') 551 | break; 552 | } 553 | 554 | if (ignore_newline && start < i && data[start] == '\n') { 555 | ignore_newline = 0; 556 | continue; 557 | } 558 | 559 | if (i >= len) { 560 | if (start < len) 561 | append_save(data + start, i - start); 562 | break; 563 | } 564 | 565 | i++; 566 | ignore_newline = eexec_line(data + start, i - start); 567 | } 568 | 569 | /* if in_eexec < 0, we have some plaintext lines sitting around in a binary 570 | section of the PFB. save them for later */ 571 | if (in_eexec < 0 && i < len) 572 | append_save(data + i, len - i); 573 | } 574 | 575 | static void 576 | disasm_output_end(void) 577 | { 578 | /* take care of leftover saved data */ 579 | static char crap[1] = ""; 580 | disasm_output_ascii(crap, 0); 581 | } 582 | 583 | 584 | /***** 585 | * Command line 586 | **/ 587 | 588 | #define OUTPUT_OPT 301 589 | #define VERSION_OPT 302 590 | #define HELP_OPT 303 591 | 592 | static Clp_Option options[] = { 593 | { "help", 0, HELP_OPT, 0, 0 }, 594 | { "output", 'o', OUTPUT_OPT, Clp_ValString, 0 }, 595 | { "version", 0, VERSION_OPT, 0, 0 }, 596 | }; 597 | static const char *program_name; 598 | 599 | void 600 | fatal_error(const char *message, ...) 601 | { 602 | va_list val; 603 | va_start(val, message); 604 | fprintf(stderr, "%s: ", program_name); 605 | vfprintf(stderr, message, val); 606 | fputc('\n', stderr); 607 | va_end(val); 608 | exit(1); 609 | } 610 | 611 | void 612 | error(const char *message, ...) 613 | { 614 | va_list val; 615 | va_start(val, message); 616 | fprintf(stderr, "%s: ", program_name); 617 | vfprintf(stderr, message, val); 618 | fputc('\n', stderr); 619 | error_count++; 620 | va_end(val); 621 | } 622 | 623 | static void 624 | short_usage(void) 625 | { 626 | fprintf(stderr, "Usage: %s [INPUT [OUTPUT]]\n\ 627 | Try `%s --help' for more information.\n", 628 | program_name, program_name); 629 | } 630 | 631 | static void 632 | usage(void) 633 | { 634 | printf("\ 635 | `T1disasm' translates a PostScript Type 1 font in PFB or PFA format into a\n\ 636 | human-readable, human-editable form. The result is written to the standard\n\ 637 | output unless an OUTPUT file is given.\n\ 638 | \n\ 639 | Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\ 640 | \n\ 641 | Options:\n\ 642 | -o, --output=FILE Write output to FILE.\n\ 643 | -h, --help Print this message and exit.\n\ 644 | --version Print version number and warranty and exit.\n\ 645 | \n\ 646 | Report bugs to .\n", program_name); 647 | } 648 | 649 | #ifdef __cplusplus 650 | } 651 | #endif 652 | 653 | 654 | int 655 | main(int argc, char *argv[]) 656 | { 657 | struct font_reader fr; 658 | int c; 659 | FILE *ifp = 0; 660 | const char *ifp_filename = ""; 661 | 662 | Clp_Parser *clp = 663 | Clp_NewParser(argc, (const char * const *)argv, sizeof(options) / sizeof(options[0]), options); 664 | program_name = Clp_ProgramName(clp); 665 | 666 | /* interpret command line arguments using CLP */ 667 | while (1) { 668 | int opt = Clp_Next(clp); 669 | switch (opt) { 670 | 671 | output_file: 672 | case OUTPUT_OPT: 673 | if (ofp) 674 | fatal_error("output file already specified"); 675 | if (strcmp(clp->vstr, "-") == 0) 676 | ofp = stdout; 677 | else { 678 | ofp = fopen(clp->vstr, "w"); 679 | if (!ofp) fatal_error("%s: %s", clp->vstr, strerror(errno)); 680 | } 681 | break; 682 | 683 | case HELP_OPT: 684 | usage(); 685 | exit(0); 686 | break; 687 | 688 | case VERSION_OPT: 689 | printf("t1disasm (LCDF t1utils) %s\n", VERSION); 690 | printf("Copyright (C) 1992-2017 I. Lee Hetherington, Eddie Kohler et al.\n\ 691 | This is free software; see the source for copying conditions.\n\ 692 | There is NO warranty, not even for merchantability or fitness for a\n\ 693 | particular purpose.\n"); 694 | exit(0); 695 | break; 696 | 697 | case Clp_NotOption: 698 | if (ifp && ofp) 699 | fatal_error("too many arguments"); 700 | else if (ifp) 701 | goto output_file; 702 | if (strcmp(clp->vstr, "-") == 0) 703 | ifp = stdin; 704 | else { 705 | ifp_filename = clp->vstr; 706 | ifp = fopen(clp->vstr, "rb"); 707 | if (!ifp) fatal_error("%s: %s", clp->vstr, strerror(errno)); 708 | } 709 | break; 710 | 711 | case Clp_Done: 712 | goto done; 713 | 714 | case Clp_BadOption: 715 | short_usage(); 716 | exit(1); 717 | break; 718 | 719 | } 720 | } 721 | 722 | done: 723 | if (!ifp) ifp = stdin; 724 | if (!ofp) ofp = stdout; 725 | 726 | #if defined(_MSDOS) || defined(_WIN32) 727 | /* As we might be processing a PFB (binary) input file, we must set its file 728 | mode to binary. */ 729 | _setmode(_fileno(ifp), _O_BINARY); 730 | #endif 731 | 732 | /* prepare font reader */ 733 | fr.output_ascii = disasm_output_ascii; 734 | fr.output_binary = disasm_output_binary; 735 | fr.output_end = disasm_output_end; 736 | 737 | /* peek at first byte to see if it is the PFB marker 0x80 */ 738 | c = getc(ifp); 739 | ungetc(c, ifp); 740 | 741 | /* do the file */ 742 | if (c == PFB_MARKER) 743 | process_pfb(ifp, ifp_filename, &fr); 744 | else if (c == '%') 745 | process_pfa(ifp, ifp_filename, &fr); 746 | else 747 | fatal_error("%s does not start with font marker (`%%' or 0x80)", ifp_filename); 748 | 749 | fclose(ifp); 750 | fclose(ofp); 751 | 752 | if (unknown) 753 | error((unknown > 1 754 | ? "encountered %d unknown charstring commands" 755 | : "encountered %d unknown charstring command"), 756 | unknown); 757 | 758 | return (error_count ? 1 : 0); 759 | } 760 | -------------------------------------------------------------------------------- /t1lib.c: -------------------------------------------------------------------------------- 1 | /* t1lib 2 | * 3 | * This file contains functions for reading PFA and PFB files. 4 | * 5 | * Copyright (c) 1998-2017 Eddie Kohler 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a 8 | * copy of this software and associated documentation files (the 9 | * "Software"), to deal in the Software without restriction, subject to the 10 | * conditions listed in the Click LICENSE file, which is available in full at 11 | * http://github.com/kohler/click/blob/master/LICENSE. The conditions 12 | * include: you must preserve this copyright notice, and you cannot mention 13 | * the copyright holders in advertising related to the Software without 14 | * their permission. The Software is provided WITHOUT ANY WARRANTY, EXPRESS 15 | * OR IMPLIED. This notice is a summary of the Click LICENSE file; the 16 | * license in that file is binding. 17 | */ 18 | 19 | #ifdef HAVE_CONFIG_H 20 | # include 21 | #endif 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "t1lib.h" 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #define PFA_ASCII 1 32 | #define PFA_EEXEC_TEST 2 33 | #define PFA_HEX 3 34 | #define PFA_BINARY 4 35 | 36 | /* This function returns the value (0-15) of a single hex digit. It returns 37 | 0 for an invalid hex digit. */ 38 | 39 | static int 40 | hexval(char c) 41 | { 42 | if (c >= 'A' && c <= 'F') 43 | return c - 'A' + 10; 44 | else if (c >= 'a' && c <= 'f') 45 | return c - 'a' + 10; 46 | else if (c >= '0' && c <= '9') 47 | return c - '0'; 48 | else 49 | return 0; 50 | } 51 | 52 | /* This function translates a string of hexadecimal digits into binary data. 53 | We allow an odd number of digits. Returns length of binary data. */ 54 | 55 | static int 56 | translate_hex_string(char *s, char *saved_orphan) 57 | { 58 | int c1 = *saved_orphan; 59 | char *start = s; 60 | char *t = s; 61 | for (; *s; s++) { 62 | if (isspace((unsigned char) *s)) 63 | continue; 64 | if (c1) { 65 | *t++ = (hexval(c1) << 4) + hexval(*s); 66 | c1 = 0; 67 | } else 68 | c1 = *s; 69 | } 70 | *saved_orphan = c1; 71 | return t - start; 72 | } 73 | 74 | /* This function returns 1 if the string contains all '0's. */ 75 | 76 | static int 77 | all_zeroes(char *s) 78 | { 79 | if (*s == '\0' || *s == '\n') 80 | return 0; 81 | while (*s == '0') 82 | s++; 83 | return *s == '\0' || *s == '\n'; 84 | } 85 | 86 | /* This function handles the entire file. */ 87 | 88 | #define LINESIZE 1024 89 | 90 | void 91 | process_pfa(FILE *ifp, const char *ifp_filename, struct font_reader *fr) 92 | { 93 | /* Loop until no more input. We need to look for `currentfile eexec' to 94 | start eexec section (hex to binary conversion) and line of all zeros to 95 | switch back to ASCII. */ 96 | 97 | /* Don't use fgets() in case line-endings are indicated by bare \r's, as 98 | occurs in Macintosh fonts. */ 99 | 100 | /* 2.Aug.1999 - At the behest of Tom Kacvinsky , support 101 | binary PFA fonts. */ 102 | 103 | char buffer[LINESIZE]; 104 | int c = 0; 105 | int blocktyp = PFA_ASCII; 106 | char saved_orphan = 0; 107 | (void)ifp_filename; 108 | 109 | while (c != EOF) { 110 | char *line = buffer, *last = buffer; 111 | int crlf = 0; 112 | c = getc(ifp); 113 | while (c != EOF && c != '\r' && c != '\n' && last < buffer + LINESIZE - 1) { 114 | *last++ = c; 115 | c = getc(ifp); 116 | } 117 | 118 | /* handle the end of the line */ 119 | if (last == buffer + LINESIZE - 1) 120 | /* buffer overrun: don't append newline even if we have it */ 121 | ungetc(c, ifp); 122 | else if (c == '\r' && blocktyp != PFA_BINARY) { 123 | /* change CR or CR/LF into LF, unless reading binary data! (This 124 | condition was wrong before, caused Thanh problems - 125 | 6.Mar.2001) */ 126 | c = getc(ifp); 127 | if (c != '\n') 128 | ungetc(c, ifp), crlf = 1; 129 | else 130 | crlf = 2; 131 | *last++ = '\n'; 132 | } else if (c != EOF) 133 | *last++ = c; 134 | 135 | *last = 0; 136 | 137 | /* now that we have the line, handle it */ 138 | if (blocktyp == PFA_ASCII) { 139 | if (strncmp(line, "currentfile eexec", 17) == 0 && isspace((unsigned char) line[17])) { 140 | char saved_p; 141 | /* assert(line == buffer); */ 142 | for (line += 18; isspace((unsigned char) *line); line++) 143 | /* nada */; 144 | saved_p = *line; 145 | *line = 0; 146 | fr->output_ascii(buffer, line - buffer); 147 | *line = saved_p; 148 | blocktyp = PFA_EEXEC_TEST; 149 | if (!*line) 150 | continue; 151 | } else { 152 | fr->output_ascii(line, last - line); 153 | continue; 154 | } 155 | } 156 | 157 | /* check immediately after "currentfile eexec" for ASCII or binary */ 158 | if (blocktyp == PFA_EEXEC_TEST) { 159 | /* 8.Feb.2004: fix bug if first character in a binary eexec block 160 | is 0, reported by Werner Lemberg */ 161 | for (; line < last && isspace((unsigned char) *line); line++) 162 | /* nada */; 163 | if (line == last) 164 | continue; 165 | else if (last >= line + 4 && isxdigit((unsigned char) line[0]) 166 | && isxdigit((unsigned char) line[1]) 167 | && isxdigit((unsigned char) line[2]) 168 | && isxdigit((unsigned char) line[3])) 169 | blocktyp = PFA_HEX; 170 | else 171 | blocktyp = PFA_BINARY; 172 | memmove(buffer, line, last - line + 1); 173 | last = buffer + (last - line); 174 | line = buffer; 175 | /* patch up crlf fix */ 176 | if (blocktyp == PFA_BINARY && crlf) { 177 | last[-1] = '\r'; 178 | if (crlf == 2) 179 | *last++ = '\n'; 180 | } 181 | } 182 | 183 | /* blocktyp == PFA_HEX || blocktyp == PFA_BINARY */ 184 | if (all_zeroes(line)) { /* XXX not safe */ 185 | fr->output_ascii(line, last - line); 186 | blocktyp = PFA_ASCII; 187 | } else if (blocktyp == PFA_HEX) { 188 | int len = translate_hex_string(line, &saved_orphan); 189 | if (len) 190 | fr->output_binary((unsigned char *)line, len); 191 | } else 192 | fr->output_binary((unsigned char *)line, last - line); 193 | } 194 | 195 | fr->output_end(); 196 | } 197 | 198 | /* Process a PFB file. */ 199 | 200 | /* XXX Doesn't handle "currentfile eexec" as intelligently as process_pfa 201 | does. */ 202 | 203 | static int 204 | handle_pfb_ascii(struct font_reader *fr, char *line, int len) 205 | { 206 | /* Divide PFB_ASCII blocks into lines */ 207 | int start = 0; 208 | 209 | while (1) { 210 | int pos = start; 211 | 212 | while (pos < len && line[pos] != '\n' && line[pos] != '\r') 213 | pos++; 214 | 215 | if (pos >= len) { 216 | if (pos == start) 217 | return 0; 218 | else if (start == 0 && pos == LINESIZE - 1) { 219 | line[pos] = 0; 220 | fr->output_ascii(line, pos); 221 | return 0; 222 | } else { 223 | memmove(line, line + start, pos - start); 224 | return pos - start; 225 | } 226 | 227 | } else if (pos < len - 1 && line[pos] == '\r' && line[pos+1] == '\n') { 228 | line[pos] = '\n'; 229 | line[pos+1] = 0; 230 | fr->output_ascii(line + start, pos + 1 - start); 231 | start = pos + 2; 232 | 233 | } else { 234 | char save = line[pos+1]; 235 | line[pos] = '\n'; 236 | line[pos+1] = 0; 237 | fr->output_ascii(line + start, pos + 1 - start); 238 | line[pos+1] = save; 239 | start = pos + 1; 240 | } 241 | } 242 | } 243 | 244 | 245 | void 246 | process_pfb(FILE *ifp, const char *ifp_filename, struct font_reader *fr) 247 | { 248 | int blocktyp = 0; 249 | unsigned block_len = 0; 250 | int c = 0; 251 | unsigned filepos = 0; 252 | int linepos = 0; 253 | char line[LINESIZE]; 254 | 255 | while (1) { 256 | while (block_len == 0) { 257 | c = getc(ifp); 258 | blocktyp = getc(ifp); 259 | if (c != PFB_MARKER 260 | || (blocktyp != PFB_ASCII && blocktyp != PFB_BINARY 261 | && blocktyp != PFB_DONE)) { 262 | if (c == EOF || blocktyp == EOF) 263 | error("%s corrupted: no end-of-file marker", ifp_filename); 264 | else 265 | error("%s corrupted: bad block marker at position %u", 266 | ifp_filename, filepos); 267 | blocktyp = PFB_DONE; 268 | } 269 | if (blocktyp == PFB_DONE) 270 | goto done; 271 | 272 | block_len = getc(ifp) & 0xFF; 273 | block_len |= (getc(ifp) & 0xFF) << 8; 274 | block_len |= (getc(ifp) & 0xFF) << 16; 275 | block_len |= (unsigned) (getc(ifp) & 0xFF) << 24; 276 | if (feof(ifp)) { 277 | error("%s corrupted: bad block length at position %u", 278 | ifp_filename, filepos); 279 | blocktyp = PFB_DONE; 280 | goto done; 281 | } 282 | filepos += 6; 283 | } 284 | 285 | /* read the block in its entirety, in LINESIZE chunks */ 286 | while (block_len > 0) { 287 | unsigned rest = LINESIZE - 1 - linepos; /* leave space for '\0' */ 288 | unsigned n = (block_len > rest ? rest : block_len); 289 | int actual = fread(line + linepos, 1, n, ifp); 290 | if (actual != (int) n) { 291 | error("%s corrupted: block short by %u bytes at position %u", 292 | ifp_filename, block_len - actual, filepos); 293 | block_len = actual; 294 | } 295 | 296 | if (blocktyp == PFB_BINARY) 297 | fr->output_binary((unsigned char *)line, actual); 298 | else 299 | linepos = handle_pfb_ascii(fr, line, linepos + actual); 300 | 301 | block_len -= actual; 302 | filepos += actual; 303 | } 304 | 305 | /* handle any leftover line */ 306 | if (linepos > 0) { 307 | line[linepos] = 0; 308 | fr->output_ascii(line, linepos); 309 | linepos = 0; 310 | } 311 | } 312 | 313 | done: 314 | c = getc(ifp); 315 | if (c != EOF) 316 | error("%s corrupted: data after PFB end marker at position %u", 317 | ifp_filename, filepos - 2); 318 | fr->output_end(); 319 | } 320 | 321 | 322 | #define DEFAULT_BLOCKLEN (1L<<12) 323 | 324 | void 325 | init_pfb_writer(struct pfb_writer *w, int blocklen, FILE *f) 326 | { 327 | w->len = DEFAULT_BLOCKLEN; 328 | w->buf = (unsigned char *)malloc(w->len); 329 | if (!w->buf) 330 | fatal_error("out of memory"); 331 | w->max_len = (blocklen <= 0 ? 0xFFFFFFFFU : (unsigned)blocklen); 332 | w->pos = 0; 333 | w->blocktyp = PFB_ASCII; 334 | w->binary_blocks_written = 0; 335 | w->f = f; 336 | } 337 | 338 | void 339 | pfb_writer_output_block(struct pfb_writer *w) 340 | { 341 | /* do nothing if nothing in block */ 342 | if (w->pos == 0) 343 | return; 344 | 345 | /* output four-byte block length */ 346 | putc(PFB_MARKER, w->f); 347 | putc(w->blocktyp, w->f); 348 | putc((int)(w->pos & 0xff), w->f); 349 | putc((int)((w->pos >> 8) & 0xff), w->f); 350 | putc((int)((w->pos >> 16) & 0xff), w->f); 351 | putc((int)((w->pos >> 24) & 0xff), w->f); 352 | 353 | /* output block data */ 354 | fwrite(w->buf, 1, w->pos, w->f); 355 | 356 | /* mark block buffer empty and uninitialized */ 357 | w->pos = 0; 358 | if (w->blocktyp == PFB_BINARY) 359 | w->binary_blocks_written++; 360 | } 361 | 362 | void 363 | pfb_writer_grow_buf(struct pfb_writer *w) 364 | { 365 | if (w->len < w->max_len) { 366 | /* grow w->buf */ 367 | unsigned new_len = w->len * 2; 368 | unsigned char *new_buf; 369 | if (new_len > w->max_len) 370 | new_len = w->max_len; 371 | new_buf = (unsigned char *)malloc(new_len); 372 | if (!new_buf) { 373 | error("out of memory; continuing with a smaller block size"); 374 | w->max_len = w->len; 375 | pfb_writer_output_block(w); 376 | } else { 377 | memcpy(new_buf, w->buf, w->len); 378 | free(w->buf); 379 | w->buf = new_buf; 380 | w->len = new_len; 381 | } 382 | 383 | } else 384 | /* buf already the right size, just output the block */ 385 | pfb_writer_output_block(w); 386 | } 387 | 388 | void 389 | pfb_writer_end(struct pfb_writer *w) 390 | { 391 | if (w->pos) 392 | pfb_writer_output_block(w); 393 | putc(PFB_MARKER, w->f); 394 | putc(PFB_DONE, w->f); 395 | } 396 | 397 | /* This CRC table and routine were borrowed from macutils-2.0b3 */ 398 | 399 | static unsigned short crctab[256] = { 400 | 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 401 | 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 402 | 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 403 | 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 404 | 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 405 | 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 406 | 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 407 | 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 408 | 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 409 | 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 410 | 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 411 | 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 412 | 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 413 | 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 414 | 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 415 | 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, 416 | 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 417 | 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, 418 | 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 419 | 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 420 | 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 421 | 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 422 | 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 423 | 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, 424 | 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 425 | 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, 426 | 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 427 | 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 428 | 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 429 | 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 430 | 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 431 | 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0, 432 | }; 433 | 434 | /* 435 | * Update a CRC check on the given buffer. 436 | */ 437 | 438 | int 439 | crcbuf(int crc, unsigned int len, const char *buf) 440 | { 441 | const unsigned char *ubuf = (const unsigned char *)buf; 442 | while (len--) 443 | crc = ((crc << 8) & 0xFF00) ^ crctab[((crc >> 8) & 0xFF) ^ *ubuf++]; 444 | return crc; 445 | } 446 | 447 | #ifdef __cplusplus 448 | } 449 | #endif 450 | -------------------------------------------------------------------------------- /t1lib.h: -------------------------------------------------------------------------------- 1 | #ifndef T1LIB_H 2 | #define T1LIB_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | #ifdef WIN32 8 | # pragma warning (disable: 4007 4096) 9 | # define CDECL __cdecl 10 | #else 11 | # define CDECL 12 | #endif 13 | 14 | #define PFB_MARKER 128 15 | #define PFB_ASCII 1 16 | #define PFB_BINARY 2 17 | #define PFB_DONE 3 18 | 19 | struct font_reader { 20 | void (*output_ascii)(char *, int); 21 | void (*output_binary)(unsigned char *, int); 22 | void (*output_end)(); 23 | }; 24 | 25 | void process_pfa(FILE *, const char *filename, struct font_reader *); 26 | void process_pfb(FILE *, const char *filename, struct font_reader *); 27 | 28 | struct pfb_writer { 29 | unsigned char *buf; 30 | unsigned len; 31 | unsigned max_len; 32 | unsigned pos; 33 | int blocktyp; 34 | int binary_blocks_written; 35 | FILE *f; 36 | }; 37 | 38 | void init_pfb_writer(struct pfb_writer *, int, FILE *); 39 | void pfb_writer_output_block(struct pfb_writer *); 40 | void pfb_writer_grow_buf(struct pfb_writer *); 41 | void pfb_writer_end(struct pfb_writer *); 42 | #define PFB_OUTPUT_BYTE(w, b) do { \ 43 | if ((w)->pos >= (w)->len) pfb_writer_grow_buf(w); \ 44 | (w)->buf[(w)->pos++] = (b); \ 45 | } while (0) 46 | 47 | int crcbuf(int crc, unsigned int len, const char *buf); 48 | 49 | /* whoever uses this code must provide a definition for these functions */ 50 | extern void error(const char *, ...); 51 | extern void fatal_error(const char *, ...); 52 | 53 | #ifdef __cplusplus 54 | } 55 | #endif 56 | #endif 57 | -------------------------------------------------------------------------------- /t1mac.1: -------------------------------------------------------------------------------- 1 | .ds V 1.42 2 | .de M 3 | .BR "\\$1" "(\\$2)\\$3" 4 | .. 5 | .TH T1MAC 1 "" "Version \*V" 6 | .SH NAME 7 | t1mac \- translate a PFA or PFB PostScript Type 1 font into Macintosh format 8 | .SH SYNOPSIS 9 | .B t1mac 10 | \%[\fB\-\-macbinary\fR | \fB\-\-applesingle\fR | 11 | \fB\-\-appledouble\fR | \fB\-\-binhex\fR | \fB\-\-raw\fR] 12 | \%[\fB\-\-filename\fR \fIname\fR] 13 | \%[\fIinput\fR [\fIoutput\fR]] 14 | .SH DESCRIPTION 15 | .B t1mac 16 | reads a PFA (hexadecimal) or PFB (binary) PostScript Type 1 font file and 17 | generates an equivalent Macintosh Type 1 font file. The output file can be 18 | in MacBinary II, AppleSingle, AppleDouble, or BinHex format, or it can be a 19 | raw resource fork. The default is MacBinary II; use an option to choose a 20 | different format. If the 21 | .I output 22 | file is not specified output goes to the standard output. 23 | .PP 24 | WARNING: The output of 25 | .B t1mac 26 | is not sufficient to use the font, since Macintoshes can't read raw Type 1 27 | fonts. You will need to create a font suitcase containing bitmap fonts if 28 | you do not have such a suitcase for the font already. 29 | .B t1mac 30 | cannot help you do this. 31 | .SH OPTIONS 32 | .TP 5 33 | .BR \-\-raw ", " \-r 34 | Indicates that output should be a raw resource fork. 35 | .TP 5 36 | .BR \-\-macbinary 37 | Indicates that output should be in MacBinary I or II format. This is the 38 | default. 39 | .TP 5 40 | .BR \-\-applesingle 41 | Indicates that output should be in AppleSingle format. 42 | .TP 5 43 | .BR \-\-appledouble 44 | Indicates that output should be in AppleDouble format. 45 | .TP 5 46 | .BR \-\-binhex 47 | Indicates that output should be in BinHex 4.0 format. 48 | .TP 5 49 | .BR \-\-filename "=\fIname\fR, " \-n " \fIname\fR" 50 | Sets the Macintosh filename of the output font to \fIname\fR. The default 51 | is to construct the filename from the font's name using established 52 | Macintosh conventions. This option is not useful when output is a raw 53 | resource fork. 54 | .SH "SEE ALSO" 55 | .LP 56 | .M t1unmac 1 , 57 | .M t1ascii 1 , 58 | .M t1binary 1 , 59 | .M t1asm 1 , 60 | .M t1disasm 1 61 | .SH AUTHORS 62 | Eddie Kohler (ekohler@gmail.com) 63 | -------------------------------------------------------------------------------- /t1mac.c: -------------------------------------------------------------------------------- 1 | /* t1mac 2 | * 3 | * This program converts Type 1 fonts in PFA or PFB format into Macintosh Type 4 | * 1 fonts stored in MacBinary (I or II), AppleSingle, AppleDouble, BinHex, or 5 | * raw resource fork format. 6 | * 7 | * Copyright (c) 2000-2017 Eddie Kohler 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a 10 | * copy of this software and associated documentation files (the 11 | * "Software"), to deal in the Software without restriction, subject to the 12 | * conditions listed in the Click LICENSE file, which is available in full at 13 | * http://github.com/kohler/click/blob/master/LICENSE. The conditions 14 | * include: you must preserve this copyright notice, and you cannot mention 15 | * the copyright holders in advertising related to the Software without 16 | * their permission. The Software is provided WITHOUT ANY WARRANTY, EXPRESS 17 | * OR IMPLIED. This notice is a summary of the Click LICENSE file; the 18 | * license in that file is binding. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | # include 23 | #endif 24 | #if defined(_MSDOS) || defined(_WIN32) 25 | # include 26 | # include 27 | #endif 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include "t1lib.h" 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | #endif 42 | 43 | typedef unsigned char byte; 44 | 45 | /* resource fork layout */ 46 | #define RFORK_HEADERLEN 256 47 | #define RFORK_MAP_RESERVEDLEN 22 48 | #define RFORK_MAP_HEADERLEN 28 49 | #define RFORK_RTYPE_LEN 8 50 | #define RFORK_RSRC_LEN 12 51 | 52 | /* Macintosh times are # seconds since 1/1/1904, not 1/1/1970 */ 53 | #define MAC_TIME_DELTA 2082844800 54 | 55 | /* POST resource information */ 56 | #define POST_ASCII 1 57 | #define POST_BINARY 2 58 | #define POST_END 5 59 | 60 | /* Adobe font file information */ 61 | #define T1_FILETYPE 0x4C57464E /* LWFN */ 62 | #define T1_FILECREATOR 0x54315554 /* T1UT */ 63 | #define T1_FINDERFLAGS 33 /* Bundle + Inited */ 64 | 65 | #define MAX_RSRC_LEN 2048 66 | static byte rbuf[MAX_RSRC_LEN]; 67 | static int rbufpos; 68 | static int blocktyp; 69 | 70 | static char *font_name; 71 | 72 | /* information about the resources being built */ 73 | typedef struct Rsrc { 74 | int32_t type; 75 | int id; 76 | int attrs; 77 | int data_offset; 78 | uint32_t data_len; 79 | int next_in_type; 80 | int next_type; 81 | } Rsrc; 82 | static Rsrc *rsrc = 0; 83 | static int nrsrc = 0; 84 | static int rsrc_cap = 0; 85 | static int cur_post_id = 0; 86 | 87 | /* output resource fork */ 88 | static FILE *rfork_f = 0; 89 | 90 | /* ICN# data */ 91 | static const unsigned char icon_bw_data[] = { 92 | 0,0,0,0,255,255,255,255,128,0,0,1,128,0,0,1,128,0,0,1, 93 | 128,0,0,1,128,0,0,1,128,0,0,1,128,0,0,1,128,0,0,33, 94 | 128,0,0,97,128,0,0,225,128,0,1,225,128,0,3,225,128,0,7,225, 95 | 128,0,15,225,128,0,31,225,128,0,55,225,159,128,103,249,144,128,199,9, 96 | 240,129,135,15,0,131,7,0,0,134,7,0,15,140,7,240,8,31,255,240, 97 | 8,63,255,240,8,96,7,240,8,192,7,240,9,192,15,240,11,224,31,240, 98 | 15,240,63,240,15,255,255,240,0,0,0,0,255,255,255,255,255,255,255,255, 99 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 100 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 101 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 102 | 255,255,255,255,240,255,255,15,240,255,255,15,0,255,255,0,0,255,255,0, 103 | 15,255,255,240,15,255,255,240,15,255,255,240,15,255,255,240,15,255,255,240, 104 | 15,255,255,240,15,255,255,240,15,255,255,240,15,255,255,240,}; 105 | 106 | static const unsigned char small_icon_bw_data[] = { 107 | 255,255,128,1,128,1,128,1,128,5,128,13,128,29,128,61,128,125,184,253, 108 | 201,179,59,60,39,252,44,60,60,124,63,252,255,255,255,255,255,255,255,255, 109 | 255,255,255,255,255,255,255,255,255,255,255,255,207,243,63,252,63,252,63,252, 110 | 63,252,63,252,}; 111 | 112 | static const unsigned char icon_8_data[] = { 113 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 114 | 0,0,0,0,0,0,0,0,0,0,0,0,92,92,92,92,92,92,92,92, 115 | 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 116 | 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 117 | 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,105,92,92,92,92, 118 | 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 119 | 92,92,92,92,92,92,92,105,92,92,92,92,92,92,92,92,92,92,92,92, 120 | 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,105, 121 | 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 122 | 92,92,92,92,92,92,92,92,92,92,92,105,92,92,92,92,92,92,92,92, 123 | 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 124 | 92,92,92,105,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 125 | 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,105,92,92,92,92, 126 | 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 127 | 92,92,92,92,92,92,92,105,92,92,92,92,92,92,92,92,92,92,92,92, 128 | 92,92,92,92,92,92,92,92,92,92,92,92,92,92,5,92,92,92,92,105, 129 | 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 130 | 92,92,92,92,92,5,5,92,92,92,92,105,92,92,92,92,92,92,92,92, 131 | 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,5,5,5,92, 132 | 92,92,92,105,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 133 | 92,92,92,92,92,92,92,5,5,5,5,92,92,92,92,105,92,92,92,92, 134 | 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,5,5, 135 | 5,5,5,92,92,92,92,105,92,92,92,92,92,92,92,92,92,92,92,92, 136 | 92,92,92,92,92,92,92,92,92,5,5,5,5,5,5,92,92,92,92,105, 137 | 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 138 | 5,5,5,5,5,5,5,92,92,92,92,105,92,92,92,92,92,92,92,92, 139 | 92,92,92,92,92,92,92,92,92,92,92,5,5,5,5,5,5,5,5,92, 140 | 92,92,92,105,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 141 | 92,92,5,5,92,5,5,5,5,5,5,92,92,92,92,105,92,92,92,105, 142 | 105,105,105,105,92,92,92,92,92,92,92,92,92,5,5,92,92,5,5,105, 143 | 105,105,105,105,92,92,92,105,92,92,92,105,0,0,0,0,92,92,92,92, 144 | 92,92,92,92,5,5,92,92,92,5,5,105,0,0,0,0,92,92,92,105, 145 | 105,105,105,105,0,0,0,0,92,92,92,92,92,92,92,5,5,92,92,92, 146 | 92,5,5,105,0,0,0,0,105,105,105,105,0,0,0,0,0,0,0,0, 147 | 92,92,92,92,92,92,5,5,92,92,92,92,92,5,5,105,0,0,0,0, 148 | 0,0,0,0,0,0,0,0,0,0,0,0,92,92,92,92,92,5,5,92, 149 | 92,92,92,92,92,5,5,105,0,0,0,0,0,0,0,0,0,0,0,0, 150 | 92,92,92,92,92,92,92,92,5,5,92,92,92,92,92,92,92,5,5,5, 151 | 5,5,5,92,0,0,0,0,0,0,0,0,92,92,92,92,92,92,92,5, 152 | 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,105,0,0,0,0, 153 | 0,0,0,0,92,92,92,92,92,92,5,5,5,5,5,5,5,5,5,5, 154 | 5,5,5,5,5,5,5,105,0,0,0,0,0,0,0,0,92,92,92,92, 155 | 92,5,5,92,92,92,92,92,92,92,92,92,92,5,5,5,5,5,5,105, 156 | 0,0,0,0,0,0,0,0,92,92,92,92,5,5,92,92,92,92,92,92, 157 | 92,92,92,92,92,5,5,5,5,5,5,105,0,0,0,0,0,0,0,0, 158 | 92,92,92,5,5,5,92,92,92,92,92,92,92,92,92,92,5,5,5,5, 159 | 5,5,5,105,0,0,0,0,0,0,0,0,92,92,5,5,5,5,5,92, 160 | 92,92,92,92,92,92,92,5,5,5,5,5,5,5,5,105,0,0,0,0, 161 | 0,0,0,0,92,5,5,5,5,5,5,5,92,92,92,92,92,92,5,5, 162 | 5,5,5,5,5,5,5,105,0,0,0,0,0,0,0,0,92,105,105,105, 163 | 105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 164 | 0,0,0,0,}; 165 | 166 | static const unsigned char small_icon_8_data[] = { 167 | 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 168 | 92,92,92,92,92,92,92,92,92,92,92,105,92,92,92,92,92,92,92,92, 169 | 92,92,92,92,92,92,92,105,92,92,92,92,92,92,92,92,92,92,92,92, 170 | 92,92,92,105,92,92,92,92,92,92,92,92,92,92,92,92,92,5,92,105, 171 | 92,92,92,92,92,92,92,92,92,92,92,92,5,5,92,105,92,92,92,92, 172 | 92,92,92,92,92,92,92,5,5,5,92,105,92,92,92,92,92,92,92,92, 173 | 92,92,5,5,5,5,92,105,92,92,92,92,92,92,92,92,92,5,92,5, 174 | 5,5,92,105,92,105,105,105,92,92,92,92,5,92,92,5,105,105,92,105, 175 | 92,105,0,0,92,92,92,5,92,92,92,5,0,0,105,105,0,0,92,92, 176 | 92,92,5,92,92,92,92,5,5,5,0,0,0,0,92,92,92,5,5,5, 177 | 5,5,5,5,5,5,0,0,0,0,92,92,5,92,92,92,92,92,92,5, 178 | 5,5,0,0,0,0,92,5,5,92,92,92,92,92,5,5,5,5,0,0, 179 | 0,0,5,5,5,5,105,105,105,5,5,5,5,5,0,0,}; 180 | 181 | static const unsigned char icon_4_data[] = { 182 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,69,69,69,69, 183 | 69,69,69,69,69,69,69,69,69,69,69,69,84,84,84,84,84,84,84,84, 184 | 84,84,84,84,84,84,84,85,69,69,69,69,69,69,69,69,69,69,69,69, 185 | 69,69,69,69,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,85, 186 | 69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,84,84,84,84, 187 | 84,84,84,84,84,84,84,84,84,84,84,85,69,69,69,69,69,69,69,69, 188 | 69,69,69,69,69,69,69,69,84,84,84,84,84,84,84,84,84,84,84,84, 189 | 84,84,84,85,69,69,69,69,69,69,69,69,69,69,69,69,69,21,69,69, 190 | 84,84,84,84,84,84,84,84,84,84,84,84,81,20,84,85,69,69,69,69, 191 | 69,69,69,69,69,69,69,69,17,21,69,69,84,84,84,84,84,84,84,84, 192 | 84,84,84,81,17,20,84,85,69,69,69,69,69,69,69,69,69,69,69,17, 193 | 17,21,69,69,84,84,84,84,84,84,84,84,84,84,81,17,17,20,84,85, 194 | 69,69,69,69,69,69,69,69,69,69,17,17,17,21,69,69,84,84,84,84, 195 | 84,84,84,84,84,81,17,17,17,20,84,85,69,69,69,69,69,69,69,69, 196 | 69,17,65,17,17,21,69,69,84,85,85,85,84,84,84,84,81,20,81,21, 197 | 85,85,84,85,69,69,0,0,69,69,69,69,17,69,65,21,0,0,69,69, 198 | 85,85,0,0,84,84,84,81,20,84,81,21,0,0,85,85,0,0,0,0, 199 | 69,69,69,17,69,69,65,21,0,0,0,0,0,0,0,0,84,84,81,20, 200 | 84,84,81,21,0,0,0,0,0,0,69,69,69,69,17,69,69,69,65,17, 201 | 17,30,0,0,0,0,84,84,84,81,17,17,17,17,17,17,17,21,0,0, 202 | 0,0,69,69,69,17,17,17,17,17,17,17,17,21,0,0,0,0,84,84, 203 | 81,20,84,84,84,84,81,17,17,21,0,0,0,0,69,69,17,69,69,69, 204 | 69,69,65,17,17,21,0,0,0,0,84,81,17,84,84,84,84,84,17,17, 205 | 17,21,0,0,0,0,69,17,17,21,69,69,69,65,17,17,17,21,0,0, 206 | 0,0,81,17,17,17,84,84,84,17,17,17,17,21,0,0,0,0,229,85, 207 | 85,85,85,85,85,85,85,85,85,85,0,0,}; 208 | 209 | static const unsigned char small_icon_4_data[] = { 210 | 84,84,84,84,84,84,84,85,69,69,69,69,69,69,69,69,84,84,84,84, 211 | 84,84,84,85,69,69,69,69,69,69,69,69,84,84,84,84,84,84,81,85, 212 | 69,69,69,69,69,69,17,69,84,84,84,84,84,81,17,85,69,69,69,69, 213 | 69,17,17,69,84,84,84,84,81,81,17,85,69,85,69,69,21,65,85,69, 214 | 85,0,84,81,84,81,0,85,0,69,69,21,69,65,17,0,0,84,81,17, 215 | 17,17,17,0,0,69,21,69,69,65,17,0,0,81,20,84,84,17,17,0, 216 | 0,17,17,85,81,17,17,0,}; 217 | 218 | 219 | /* fseek with fatal_error */ 220 | 221 | static void 222 | reposition(FILE *fi, int32_t absolute) 223 | { 224 | if (fseek(fi, absolute, 0) == -1) 225 | fatal_error("can't seek to position %d", absolute); 226 | } 227 | 228 | /* Some functions to write one, two, three, and four byte integers in 68000 229 | byte order (most significant byte first). */ 230 | 231 | static void 232 | write_one(int c, FILE *f) 233 | { 234 | putc(c, f); 235 | } 236 | 237 | static void 238 | write_two(int c, FILE *f) 239 | { 240 | putc((c >> 8) & 255, f); 241 | putc(c & 255, f); 242 | } 243 | 244 | static void 245 | write_three(int32_t c, FILE *f) 246 | { 247 | putc((c >> 16) & 255, f); 248 | putc((c >> 8) & 255, f); 249 | putc(c & 255, f); 250 | } 251 | 252 | static void 253 | write_four(int32_t c, FILE *f) 254 | { 255 | putc((c >> 24) & 255, f); 256 | putc((c >> 16) & 255, f); 257 | putc((c >> 8) & 255, f); 258 | putc(c & 255, f); 259 | } 260 | 261 | /* Some functions to store one, two, three, and four byte integers in 68000 262 | byte order (most significant byte first). */ 263 | 264 | static void 265 | store_one(int c, char *s) 266 | { 267 | s[0] = (char)(c & 255); 268 | } 269 | 270 | static void 271 | store_two(int c, char *s) 272 | { 273 | s[0] = (char)((c >> 8) & 255); 274 | s[1] = (char)(c & 255); 275 | } 276 | 277 | static void 278 | store_four(int32_t c, char *s) 279 | { 280 | s[0] = (char)((c >> 24) & 255); 281 | s[1] = (char)((c >> 16) & 255); 282 | s[2] = (char)((c >> 8) & 255); 283 | s[3] = (char)(c & 255); 284 | } 285 | 286 | static void 287 | output_new_rsrc(const char *rtype, int rid, int attrs, 288 | const char *data, uint32_t len) 289 | { 290 | Rsrc *r; 291 | if (nrsrc >= rsrc_cap) { 292 | rsrc_cap = (rsrc_cap ? rsrc_cap * 2 : 256); 293 | r = (Rsrc *)malloc(sizeof(Rsrc) * rsrc_cap); 294 | if (!r) 295 | fatal_error("out of memory"); 296 | memcpy(r, rsrc, sizeof(Rsrc) * nrsrc); 297 | free(rsrc); 298 | rsrc = r; 299 | } 300 | r = &rsrc[nrsrc]; 301 | nrsrc++; 302 | 303 | /* prepare resource record */ 304 | { 305 | const unsigned char *b = (const unsigned char *)rtype; 306 | r->type = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; 307 | } 308 | r->id = rid; 309 | r->attrs = attrs; 310 | if (nrsrc == 1) 311 | r->data_offset = 0; 312 | else 313 | r->data_offset = rsrc[nrsrc-2].data_offset + rsrc[nrsrc-2].data_len + 4; 314 | r->data_len = len; 315 | r->next_in_type = r->next_type = -2; 316 | 317 | /* resource consists of length, then data */ 318 | write_four(r->data_len, rfork_f); 319 | fwrite(data, 1, len, rfork_f); 320 | } 321 | 322 | static void 323 | init_current_post(void) 324 | { 325 | rbufpos = 2; 326 | cur_post_id = 501; 327 | blocktyp = POST_ASCII; 328 | } 329 | 330 | static void 331 | output_current_post(void) 332 | { 333 | if (blocktyp != POST_END && rbufpos <= 2) 334 | return; 335 | rbuf[0] = blocktyp; 336 | rbuf[1] = 0; 337 | output_new_rsrc("POST", cur_post_id, 0, (char *)rbuf, rbufpos); 338 | rbufpos = 2; 339 | cur_post_id++; 340 | } 341 | 342 | /* font_reader functions */ 343 | 344 | static void 345 | t1mac_output_data(byte *s, int len) 346 | { 347 | while (len > 0) { 348 | int n; 349 | /* In some Mac fonts, the ASCII sections terminate with a line-end */ 350 | if (rbufpos >= MAX_RSRC_LEN 351 | || (blocktyp == POST_ASCII && len + rbufpos > MAX_RSRC_LEN && rbufpos)) 352 | output_current_post(); 353 | n = (len + rbufpos <= MAX_RSRC_LEN ? len : MAX_RSRC_LEN - rbufpos); 354 | memcpy(rbuf + rbufpos, s, n); 355 | rbufpos += n; 356 | s += n; 357 | len -= n; 358 | } 359 | } 360 | 361 | static void 362 | t1mac_output_ascii(char *s, int len) 363 | { 364 | if (blocktyp == POST_BINARY) { 365 | output_current_post(); 366 | blocktyp = POST_ASCII; 367 | } 368 | /* Mac line endings */ 369 | if (len > 0 && s[len-1] == '\n') 370 | s[len-1] = '\r'; 371 | t1mac_output_data((byte *)s, len); 372 | if (strncmp(s, "/FontName", 9) == 0) { 373 | for (s += 9; isspace((unsigned char) *s); s++) 374 | /* skip */; 375 | if (*s == '/') { 376 | const char *t = ++s; 377 | while (*t && !isspace((unsigned char) *t)) t++; 378 | free(font_name); 379 | font_name = (char *)malloc(t - s + 1); 380 | memcpy(font_name, s, t - s); 381 | font_name[t - s] = 0; 382 | } 383 | } 384 | } 385 | 386 | static void 387 | t1mac_output_binary(unsigned char *s, int len) 388 | { 389 | if (blocktyp == POST_ASCII) { 390 | output_current_post(); 391 | blocktyp = POST_BINARY; 392 | } 393 | t1mac_output_data(s, len); 394 | } 395 | 396 | static void 397 | t1mac_output_end(void) 398 | { 399 | output_current_post(); 400 | blocktyp = POST_END; 401 | output_current_post(); 402 | } 403 | 404 | 405 | /* finish off the resource fork */ 406 | 407 | static uint32_t 408 | complete_rfork(void) 409 | { 410 | uint32_t reflist_offset, total_data_len; 411 | uint32_t typelist_len; 412 | int i, j, ntypes; 413 | 414 | /* analyze resources */ 415 | { 416 | int last_type = -1; 417 | ntypes = 0; 418 | for (i = 0; i < nrsrc; i++) 419 | if (rsrc[i].next_in_type == -2) { 420 | int last = -1; 421 | if (last_type >= 0) 422 | rsrc[last_type].next_type = i; 423 | for (j = i; j < nrsrc; j++) 424 | if (rsrc[j].type == rsrc[i].type) { 425 | if (last >= 0) 426 | rsrc[last].next_in_type = j; 427 | last = j; 428 | } 429 | rsrc[last].next_in_type = -1; 430 | last_type = i; 431 | ntypes++; 432 | } 433 | } 434 | 435 | /* have just finished writing data */ 436 | /* now write resource map */ 437 | for (i = 0; i < RFORK_MAP_RESERVEDLEN; i++) 438 | putc(0, rfork_f); /* reserved */ 439 | write_two(0, rfork_f); /* resource fork attributes */ 440 | typelist_len = ntypes * RFORK_RTYPE_LEN + 2; 441 | write_two(RFORK_MAP_HEADERLEN, rfork_f); /* offset from start of map to typelist */ 442 | write_two(RFORK_MAP_HEADERLEN + typelist_len + nrsrc * RFORK_RSRC_LEN, rfork_f); /* offset from start of map to namelist */ 443 | 444 | /* output type map */ 445 | write_two(ntypes - 1, rfork_f);/* number of types - 1 */ 446 | reflist_offset = typelist_len; 447 | for (i = 0; i >= 0; i = rsrc[i].next_type) { 448 | int n_in_type = 0; 449 | for (j = i; j >= 0; j = rsrc[j].next_in_type) 450 | n_in_type++; 451 | write_four(rsrc[i].type, rfork_f); /* resource type */ 452 | write_two(n_in_type - 1, rfork_f); /* number in type - 1 */ 453 | write_two(reflist_offset, rfork_f); /* offset to reflist from start of typelist */ 454 | reflist_offset += n_in_type * RFORK_RSRC_LEN; 455 | } 456 | 457 | /* output reference list */ 458 | for (i = 0; i >= 0; i = rsrc[i].next_type) 459 | for (j = i; j >= 0; j = rsrc[j].next_in_type) { 460 | write_two(rsrc[j].id, rfork_f); /* ID */ 461 | write_two(-1, rfork_f); /* offset to name */ 462 | write_one(rsrc[j].attrs, rfork_f); /* attributes */ 463 | write_three(rsrc[j].data_offset, rfork_f); /* offset to data from start of data */ 464 | write_four(0, rfork_f); /* reserved */ 465 | } 466 | 467 | /* finally, patch up resource fork header */ 468 | { 469 | total_data_len = rsrc[nrsrc-1].data_offset + rsrc[nrsrc-1].data_len + 4; 470 | reposition(rfork_f, 0); 471 | write_four(RFORK_HEADERLEN, rfork_f); /* offset from rfork to data */ 472 | write_four(RFORK_HEADERLEN + total_data_len, rfork_f); /* offset from rfork to map */ 473 | write_four(total_data_len, rfork_f); /* length of data */ 474 | write_four(RFORK_MAP_HEADERLEN + reflist_offset, rfork_f); /* length of map */ 475 | } 476 | 477 | return RFORK_HEADERLEN + total_data_len + RFORK_MAP_HEADERLEN + reflist_offset; 478 | } 479 | 480 | 481 | /* write a MacBinary II file */ 482 | 483 | static void 484 | output_raw(FILE *rf, int32_t len, FILE *f) 485 | { 486 | char buf[2048]; 487 | reposition(rf, 0); 488 | while (len > 0) { 489 | int n = (len < 2048 ? len : 2048); 490 | fread(buf, 1, n, rf); 491 | fwrite(buf, 1, n, f); 492 | len -= n; 493 | } 494 | } 495 | 496 | static void 497 | output_macbinary(FILE *rf, int32_t rf_len, const char *filename, FILE *f) 498 | { 499 | int i, len = strlen(filename); 500 | char buf[128]; 501 | if (len < 1 || len > 63) 502 | fatal_error("filename length must be between 1 and 63"); 503 | store_one(0, buf+0); /* old version number */ 504 | store_one(len, buf+1); /* filename length */ 505 | memset(buf+2, 0, 63); /* filename padding */ 506 | memcpy(buf+2, filename, len); /* filename */ 507 | store_four(T1_FILETYPE, buf+65); /* file type */ 508 | store_four(T1_FILECREATOR, buf+69); /* file creator */ 509 | store_one(T1_FINDERFLAGS, buf+73); /* finder flags */ 510 | store_one(0, buf+74); /* zero byte */ 511 | store_two(0, buf+75); /* vertical position in window */ 512 | store_two(0, buf+77); /* horizontal position in window */ 513 | store_two(0, buf+79); /* window or folder ID */ 514 | store_one(0, buf+81); /* protected flag */ 515 | store_one(0, buf+82); /* zero byte */ 516 | store_four(0, buf+83); /* data fork length */ 517 | store_four(rf_len, buf+87); /* resource fork length */ 518 | { 519 | time_t t = time(0) + MAC_TIME_DELTA; 520 | store_four(t, buf+91); /* creation date */ 521 | store_four(t, buf+95); /* modification date */ 522 | } 523 | store_two(0, buf+99); /* GetInfo comment length */ 524 | store_one(0, buf+101); /* finder flags part 2 */ 525 | memset(buf+102, 0, 116 - 102); /* padding */ 526 | store_four(0, buf+116); /* total length when unpacked */ 527 | store_two(0, buf+120); /* length of secondary header */ 528 | store_one(129, buf+122); /* version number */ 529 | store_one(129, buf+123); /* minimum acceptable version number */ 530 | store_two(crcbuf(0, 124, buf), buf+124); /* CRC */ 531 | store_two(0, buf+126); /* padding to 128 bytes */ 532 | 533 | /* write out the header */ 534 | fwrite(buf, 1, 128, f); 535 | 536 | /* now write resource fork */ 537 | output_raw(rf, rf_len, f); 538 | for (i = rf_len % 128; i && i < 128; i++) 539 | putc(0, f); 540 | } 541 | 542 | 543 | /* write an AppleSingle file */ 544 | 545 | #define APPLESINGLE_MAGIC 0x00051600 546 | #define APPLEDOUBLE_MAGIC 0x00051607 547 | #define APPLESINGLE_VERSION 0x00020000 548 | #define APPLESINGLE_TIME_DELTA 883612800 549 | #define APPLESINGLE_HEADERLEN 26 550 | #define APPLESINGLE_ENTRYLEN 12 551 | #define APPLESINGLE_DFORK_ENTRY 1 552 | #define APPLESINGLE_RFORK_ENTRY 2 553 | #define APPLESINGLE_DATES_ENTRY 8 554 | #define APPLESINGLE_DATES_LEN 16 555 | #define APPLESINGLE_FINDERINFO_ENTRY 9 556 | #define APPLESINGLE_FINDERINFO_LEN 32 557 | #define APPLESINGLE_REALNAME_ENTRY 3 558 | 559 | static void 560 | output_applesingle(FILE *rf, int32_t rf_len, const char *filename, FILE *f, 561 | int appledouble) 562 | { 563 | uint32_t offset; 564 | int i, nentries, len = strlen(filename); 565 | if (appledouble) /* magic number */ 566 | write_four(APPLEDOUBLE_MAGIC, f); 567 | else 568 | write_four(APPLESINGLE_MAGIC, f); 569 | write_four(APPLESINGLE_VERSION, f); /* version number */ 570 | for (i = 0; i < 4; i++) 571 | write_four(0, f); /* filler */ 572 | nentries = (appledouble ? 4 : 5); 573 | write_two(nentries, f); /* number of entries */ 574 | 575 | /* real name entry */ 576 | offset = APPLESINGLE_HEADERLEN + nentries * APPLESINGLE_ENTRYLEN; 577 | write_four(APPLESINGLE_REALNAME_ENTRY, f); 578 | write_four(offset, f); 579 | write_four(len, f); 580 | offset += len; 581 | 582 | /* time entry */ 583 | write_four(APPLESINGLE_DATES_ENTRY, f); 584 | write_four(offset, f); 585 | write_four(APPLESINGLE_DATES_LEN, f); 586 | offset += APPLESINGLE_DATES_LEN; 587 | 588 | /* finder info entry */ 589 | write_four(APPLESINGLE_FINDERINFO_ENTRY, f); 590 | write_four(offset, f); 591 | write_four(APPLESINGLE_FINDERINFO_LEN, f); 592 | offset += APPLESINGLE_FINDERINFO_LEN; 593 | 594 | /* resource fork entry */ 595 | write_four(APPLESINGLE_RFORK_ENTRY, f); 596 | write_four(offset, f); 597 | write_four(rf_len, f); 598 | offset += rf_len; 599 | 600 | /* data fork entry */ 601 | if (!appledouble) { 602 | write_four(APPLESINGLE_DFORK_ENTRY, f); 603 | write_four(offset, f); 604 | write_four(0, f); 605 | } 606 | 607 | /* real name data */ 608 | fwrite(filename, 1, len, f); 609 | 610 | /* time data */ 611 | i = time(0) - APPLESINGLE_TIME_DELTA; 612 | write_four(i, f); /* creation date */ 613 | write_four(i, f); /* modification date */ 614 | write_four(0x80000000, f); /* backup date */ 615 | write_four(0, f); /* access date */ 616 | 617 | /* finder info data */ 618 | write_four(T1_FILETYPE, f); /* file type */ 619 | write_four(T1_FILECREATOR, f); /* file creator */ 620 | write_one(T1_FINDERFLAGS, f); /* finder flags */ 621 | write_one(0, f); /* extended finder flags */ 622 | write_two(0, f); /* vertical position in window */ 623 | write_two(0, f); /* horizontal position in window */ 624 | write_two(0, f); /* window or folder ID */ 625 | write_four(0, f); /* icon ID and reserved */ 626 | write_four(0, f); /* reserved */ 627 | write_one(0, f); /* script flag */ 628 | write_one(0, f); /* reserved */ 629 | write_two(0, f); /* comment ID */ 630 | write_four(0, f); /* put away */ 631 | 632 | /* resource fork data */ 633 | output_raw(rf, rf_len, f); 634 | } 635 | 636 | 637 | /* write a BinHex file */ 638 | 639 | static void 640 | binhex_buffer(const byte *s, int len, FILE *f) 641 | { 642 | static int col = 1; 643 | static int bits = 0; 644 | static int bitspos = 2; 645 | static const char *table = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr"; 646 | byte buf[5]; 647 | int c, i, left; 648 | 649 | if (!s && bitspos > 2) { /* output the remaining bits */ 650 | s = (const byte *)"\0"; 651 | len = 1; 652 | } 653 | 654 | for (left = len; left > 0; left--, s++) { 655 | int pos; 656 | if (s[0] == 0x90) { 657 | buf[0] = 0x90; 658 | buf[1] = 0x00; 659 | pos = 2; 660 | } else { 661 | buf[0] = s[0]; 662 | pos = 1; 663 | } 664 | 665 | /* find a run */ 666 | if (left > 2 && s[0] == s[1] && s[0] == s[2]) { 667 | for (i = 3; i < left && i < 255; i++) 668 | if (s[i] != s[0]) 669 | break; 670 | buf[pos] = 0x90; 671 | buf[pos+1] = i; 672 | pos += 2; 673 | s += i - 1; 674 | left -= i - 1; 675 | } 676 | 677 | /* store those characters */ 678 | for (i = 0; i < pos; i++) { 679 | bits |= buf[i]; 680 | while (bitspos >= 0) { 681 | c = (bits >> bitspos) & 0x3F; 682 | putc(table[c], f); 683 | if (++col == 63) { 684 | putc('\n', f); 685 | col = 0; 686 | } 687 | bitspos -= 6; 688 | } 689 | bits <<= 8; 690 | bitspos += 8; 691 | } 692 | } 693 | } 694 | 695 | static void 696 | output_binhex(FILE *rf, int32_t rf_len, const char *filename, FILE *f) 697 | { 698 | int crc, len = strlen(filename); 699 | char buf[2048]; 700 | 701 | if (len < 1 || len > 63) 702 | fatal_error("filename length must be between 1 and 63"); 703 | store_one(len, buf+0); /* filename length */ 704 | memcpy(buf+1, filename, len); /* filename */ 705 | store_one(0, buf+1+len); /* version */ 706 | store_four(T1_FILETYPE, buf+2+len); /* file type */ 707 | store_four(T1_FILECREATOR, buf+6+len); /* file creator */ 708 | store_one(T1_FINDERFLAGS, buf+10+len); /* finder flags */ 709 | store_one(0, buf+11+len); /* extended finder flags */ 710 | store_four(0, buf+12+len); /* length of data fork */ 711 | store_four(rf_len, buf+16+len); /* length of resource fork */ 712 | store_two(crcbuf(0, 20+len, buf), buf+20+len); /* CRC */ 713 | store_two(0, buf+22+len); /* data fork CRC */ 714 | 715 | /* output BinHex comment */ 716 | fputs("(This file must be converted with BinHex 4.0)\n:", f); 717 | 718 | /* BinHex the header */ 719 | binhex_buffer((const byte *)buf, 24+len, f); 720 | 721 | /* resource fork data */ 722 | reposition(rf, 0); 723 | crc = 0; 724 | while (rf_len > 0) { 725 | int n = (rf_len < 2048 ? rf_len : 2048); 726 | fread(buf, 1, n, rf); 727 | crc = crcbuf(crc, n, buf); /* update CRC */ 728 | binhex_buffer((const byte *)buf, n, f); 729 | rf_len -= n; 730 | } 731 | store_two(crc, buf); /* resource fork CRC */ 732 | binhex_buffer((const byte *)buf, 2, f); 733 | binhex_buffer(0, 0, f); /* get rid of any remaining bits */ 734 | fputs(":\n", f); /* trailer */ 735 | } 736 | 737 | 738 | /***** 739 | * command line 740 | **/ 741 | 742 | #define OUTPUT_OPT 301 743 | #define VERSION_OPT 302 744 | #define HELP_OPT 303 745 | #define MACBINARY_OPT 304 746 | #define RAW_OPT 305 747 | #define APPLESINGLE_OPT 306 748 | #define APPLEDOUBLE_OPT 307 749 | #define BINHEX_OPT 308 750 | #define FILENAME_OPT 309 751 | 752 | static Clp_Option options[] = { 753 | { "appledouble", 0, APPLEDOUBLE_OPT, 0, 0 }, 754 | { "applesingle", 0, APPLESINGLE_OPT, 0, 0 }, 755 | { "binhex", 0, BINHEX_OPT, 0, 0 }, 756 | { "help", 0, HELP_OPT, 0, 0 }, 757 | { "macbinary", 0, MACBINARY_OPT, 0, 0 }, 758 | { "filename", 'n', FILENAME_OPT, Clp_ValString, 0 }, 759 | { "output", 'o', OUTPUT_OPT, Clp_ValString, 0 }, 760 | { "raw", 'r', RAW_OPT, 0, 0 }, 761 | { "version", 0, VERSION_OPT, 0, 0 }, 762 | }; 763 | static const char *program_name; 764 | 765 | 766 | void 767 | fatal_error(const char *message, ...) 768 | { 769 | va_list val; 770 | va_start(val, message); 771 | fprintf(stderr, "%s: ", program_name); 772 | vfprintf(stderr, message, val); 773 | putc('\n', stderr); 774 | va_end(val); 775 | exit(1); 776 | } 777 | 778 | void 779 | error(const char *message, ...) 780 | { 781 | va_list val; 782 | va_start(val, message); 783 | fprintf(stderr, "%s: ", program_name); 784 | vfprintf(stderr, message, val); 785 | putc('\n', stderr); 786 | va_end(val); 787 | } 788 | 789 | 790 | static void 791 | short_usage(void) 792 | { 793 | fprintf(stderr, "Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\ 794 | Try `%s --help' for more information.\n", 795 | program_name, program_name); 796 | } 797 | 798 | 799 | static void 800 | usage(void) 801 | { 802 | printf("\ 803 | `T1mac' translates a PostScript Type 1 font from PFA or PFB format into\n\ 804 | Macintosh Type 1 format. The result can be written in MacBinary II format (the\n\ 805 | default), AppleSingle format, AppleDouble format, or BinHex format, or as a\n\ 806 | raw resource fork. It is sent to the standard output unless an OUTPUT file is\n\ 807 | given.\n\ 808 | \n\ 809 | Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\ 810 | \n\ 811 | Options:\n\ 812 | -r, --raw Output is a raw Macintosh resource fork.\n\ 813 | --macbinary Output is in MacBinary format (default).\n\ 814 | --applesingle Output is in AppleSingle format.\n\ 815 | --appledouble Output is in AppleDouble format.\n\ 816 | --binhex Output is in BinHex format.\n\ 817 | -n, --filename NAME Macintosh font filename will be NAME.\n\ 818 | -o, --output FILE Write output to FILE.\n\ 819 | -h, --help Print this message and exit.\n\ 820 | --version Print version number and warranty and exit.\n\ 821 | \n\ 822 | Report bugs to .\n", program_name); 823 | } 824 | 825 | #ifdef __cplusplus 826 | } 827 | #endif 828 | 829 | 830 | int 831 | main(int argc, char *argv[]) 832 | { 833 | int i, c; 834 | FILE *ifp = 0, *ofp = 0; 835 | const char *ifp_filename = ""; 836 | const char *ofp_filename = ""; 837 | const char *set_font_name = 0; 838 | struct font_reader fr; 839 | uint32_t rfork_len; 840 | int raw = 0, macbinary = 1, applesingle = 0, appledouble = 0, binhex = 0; 841 | 842 | Clp_Parser *clp = 843 | Clp_NewParser(argc, (const char * const *)argv, sizeof(options) / sizeof(options[0]), options); 844 | program_name = Clp_ProgramName(clp); 845 | 846 | /* interpret command line arguments using CLP */ 847 | while (1) { 848 | int opt = Clp_Next(clp); 849 | switch (opt) { 850 | 851 | case RAW_OPT: 852 | raw = 1; 853 | macbinary = applesingle = appledouble = binhex = 0; 854 | break; 855 | 856 | case MACBINARY_OPT: 857 | macbinary = 1; 858 | raw = applesingle = appledouble = binhex = 0; 859 | break; 860 | 861 | case APPLESINGLE_OPT: 862 | applesingle = 1; 863 | raw = macbinary = appledouble = binhex = 0; 864 | break; 865 | 866 | case APPLEDOUBLE_OPT: 867 | appledouble = 1; 868 | raw = macbinary = applesingle = binhex = 0; 869 | break; 870 | 871 | case BINHEX_OPT: 872 | binhex = 1; 873 | raw = macbinary = applesingle = appledouble = 0; 874 | break; 875 | 876 | output_file: 877 | case OUTPUT_OPT: 878 | if (ofp) 879 | fatal_error("output file already specified"); 880 | if (strcmp(clp->vstr, "-") == 0) 881 | ofp = stdout; 882 | else { 883 | ofp_filename = clp->vstr; 884 | ofp = fopen(ofp_filename, "wb"); 885 | if (!ofp) fatal_error("%s: %s", ofp_filename, strerror(errno)); 886 | } 887 | break; 888 | 889 | case FILENAME_OPT: 890 | if (set_font_name) 891 | fatal_error("Macintosh font filename already specified"); 892 | set_font_name = clp->vstr; 893 | break; 894 | 895 | case HELP_OPT: 896 | usage(); 897 | exit(0); 898 | break; 899 | 900 | case VERSION_OPT: 901 | printf("t1mac (LCDF t1utils) %s\n", VERSION); 902 | printf("Copyright (C) 2000-2017 Eddie Kohler et al.\n\ 903 | This is free software; see the source for copying conditions.\n\ 904 | There is NO warranty, not even for merchantability or fitness for a\n\ 905 | particular purpose.\n"); 906 | exit(0); 907 | break; 908 | 909 | case Clp_NotOption: 910 | if (ifp && ofp) 911 | fatal_error("too many arguments"); 912 | else if (ifp) 913 | goto output_file; 914 | if (strcmp(clp->vstr, "-") == 0) 915 | ifp = stdin; 916 | else { 917 | ifp_filename = clp->vstr; 918 | ifp = fopen(clp->vstr, "r"); 919 | if (!ifp) fatal_error("%s: %s", clp->vstr, strerror(errno)); 920 | } 921 | break; 922 | 923 | case Clp_Done: 924 | goto done; 925 | 926 | case Clp_BadOption: 927 | short_usage(); 928 | exit(1); 929 | break; 930 | 931 | } 932 | } 933 | 934 | done: 935 | if (!ifp) ifp = stdin; 936 | if (!ofp) ofp = stdout; 937 | 938 | #if defined(_MSDOS) || defined(_WIN32) 939 | /* As we are processing a PFB (binary) output */ 940 | /* file, we must set its file mode to binary. */ 941 | _setmode(_fileno(ofp), _O_BINARY); 942 | #endif 943 | 944 | /* prepare font reader */ 945 | fr.output_ascii = t1mac_output_ascii; 946 | fr.output_binary = t1mac_output_binary; 947 | fr.output_end = t1mac_output_end; 948 | 949 | /* prepare resource fork file */ 950 | rfork_f = tmpfile(); 951 | if (!rfork_f) 952 | fatal_error("cannot open temporary file: %s", strerror(errno)); 953 | for (i = 0; i < RFORK_HEADERLEN; i++) 954 | putc(0, rfork_f); 955 | init_current_post(); 956 | 957 | /* peek at first byte to see if it is the PFB marker 0x80 */ 958 | c = getc(ifp); 959 | ungetc(c, ifp); 960 | 961 | /* do the file */ 962 | if (c == PFB_MARKER) 963 | process_pfb(ifp, ifp_filename, &fr); 964 | else if (c == '%') 965 | process_pfa(ifp, ifp_filename, &fr); 966 | else 967 | fatal_error("%s does not start with font marker (`%%' or 0x80)", ifp_filename); 968 | if (ifp != stdin) 969 | fclose(ifp); 970 | 971 | /* check if anything was read */ 972 | if (nrsrc == 0) 973 | error("no POST resources written -- are you sure this was a font?"); 974 | 975 | /* output large B/W icon */ 976 | output_new_rsrc("ICN#", 256, 32, (const char *)icon_bw_data, 256); 977 | /* output FREF */ 978 | output_new_rsrc("FREF", 256, 32, "LWFN\0\0\0", 7); 979 | /* output BNDL */ 980 | output_new_rsrc("BNDL", 256, 32, "T1UT\0\0\0\1FREF\0\0\0\0\1\0ICN#\0\0\0\0\1\0", 28); 981 | /* output other icons */ 982 | output_new_rsrc("icl8", 256, 32, (const char *)icon_8_data, 1024); 983 | output_new_rsrc("icl4", 256, 32, (const char *)icon_4_data, 512); 984 | output_new_rsrc("ics#", 256, 32, (const char *)small_icon_bw_data, 64); 985 | output_new_rsrc("ics8", 256, 32, (const char *)small_icon_8_data, 256); 986 | output_new_rsrc("ics4", 256, 32, (const char *)small_icon_4_data, 128); 987 | /* output T1UT (signature) */ 988 | output_new_rsrc("T1UT", 0, 0, "DConverted by t1mac (t1utils) \251Eddie Kohler http://www.lcdf.org/type/", 69); 989 | 990 | /* finish off resource file */ 991 | rfork_len = complete_rfork(); 992 | 993 | /* prepare font name */ 994 | if (!set_font_name && font_name) { 995 | int part = 0, len = 0; 996 | char *x, *s; 997 | for (x = s = font_name; *s; s++) 998 | if (isupper((unsigned char) *s) || isdigit((unsigned char) *s)) { 999 | *x++ = *s; 1000 | part++; 1001 | len = 1; 1002 | } else if (islower((unsigned char) *s)) { 1003 | if (len < (part <= 1 ? 5 : 3)) 1004 | *x++ = *s; 1005 | len++; 1006 | } 1007 | *x++ = 0; 1008 | set_font_name = font_name; 1009 | } else if (!set_font_name) 1010 | set_font_name = "Unknown Font"; 1011 | 1012 | /* now, output the file */ 1013 | if (macbinary) 1014 | output_macbinary(rfork_f, rfork_len, set_font_name, ofp); 1015 | else if (raw) 1016 | output_raw(rfork_f, rfork_len, ofp); 1017 | else if (applesingle || appledouble) 1018 | output_applesingle(rfork_f, rfork_len, set_font_name, ofp, appledouble); 1019 | else if (binhex) 1020 | output_binhex(rfork_f, rfork_len, set_font_name, ofp); 1021 | else 1022 | fatal_error("strange output format"); 1023 | fclose(rfork_f); 1024 | 1025 | if (ofp != stdout) 1026 | fclose(ofp); 1027 | return 0; 1028 | } 1029 | -------------------------------------------------------------------------------- /t1unmac.1: -------------------------------------------------------------------------------- 1 | .ds V 1.42 2 | .de M 3 | .BR "\\$1" "(\\$2)\\$3" 4 | .. 5 | .TH T1UNMAC 1 "" "Version \*V" 6 | .SH NAME 7 | t1unmac \- translate a Mac PostScript Type 1 font into PFA or PFB format 8 | .SH SYNOPSIS 9 | .B t1unmac 10 | \%[\fB\-a\fR|\fB\-b\fR] 11 | \%[\fB\-r\fR] 12 | \%[\fIinput\fR [\fIoutput\fR]] 13 | .SH DESCRIPTION 14 | .B t1unmac 15 | extracts POST resources from a Macintosh PostScript font file and creates a 16 | PFA (hexadecimal) or PFB (binary) font file. The file 17 | .I input 18 | should be in MacBinary I or II, AppleSingle, AppleDouble, or BinHex format, 19 | or it can be a raw resource fork. If the file is a raw resource fork, you 20 | need to give the `\-\-raw' option; otherwise 21 | .B t1unmac 22 | should automatically figure out what kind of file you have. If the file 23 | .I output 24 | is not specified output goes to the standard output. 25 | .SH OPTIONS 26 | .TP 5 27 | .BR \-\-pfa ", " \-a 28 | Output in PFA (ASCII) format. 29 | .TP 5 30 | .BR \-\-pfb ", " \-b 31 | Output in PFB (binary) format. This is the default. 32 | .TP 5 33 | .BR \-\-raw ", " \-r 34 | Indicates that the input is a raw resource fork. 35 | .TP 5 36 | .BR \-\-macbinary 37 | Indicates that the input is in MacBinary I or II format. 38 | .TP 5 39 | .BR \-\-applesingle 40 | Indicates that the input is in AppleSingle format. 41 | .TP 5 42 | .BR \-\-appledouble 43 | Indicates that the input is in AppleDouble format. 44 | .TP 5 45 | .BR \-\-binhex 46 | Indicates that the input is in BinHex 4.0 format. 47 | .TP 48 | .BI \-\-block\-length= "num\fR, " \-l " num" 49 | PFB only: Set the maximum output block length to 50 | .I num. 51 | The default length is as large as memory allows. 52 | .TP 53 | .BI \-\-line\-length= "num\fR, " \-l " num" 54 | PFA only: Set the maximum length of encrypted lines in the output to 55 | .I num. 56 | (These are the lines consisting wholly of hexadecimal digits.) The default 57 | is 64. 58 | .SH EXAMPLES 59 | .LP 60 | On Mac OS X, you can use 61 | .B t1unmac 62 | to translate a font into PFA or PFB format as follows: 63 | .nf 64 | % \fBt1unmac\fR \-\-raw FONTFILENAME/..namedfork/rsrc > OUTPUT 65 | .fi 66 | .SH "SEE ALSO" 67 | .LP 68 | .M t1mac 1 , 69 | .M t1ascii 1 , 70 | .M t1binary 1 , 71 | .M t1asm 1 , 72 | .M t1disasm 1 73 | .SH AUTHORS 74 | Lee Hetherington (ilh@lcs.mit.edu) 75 | .br 76 | Eddie Kohler (ekohler@gmail.com) 77 | .PP 78 | Ported to Microsoft C/C++ Compiler and MS-DOS operating system by 79 | Kai-Uwe Herbing (herbing@netmbx.netmbx.de). 80 | -------------------------------------------------------------------------------- /t1unmac.c: -------------------------------------------------------------------------------- 1 | /* t1unmac/unpost 2 | * 3 | * This program converts Macintosh Type 1 fonts stored in MacBinary (I or II), 4 | * AppleSingle, AppleDouble, BinHex, or raw resource fork format to PFA and 5 | * PFB formats. 6 | * 7 | * Copyright (c) 1992 by I. Lee Hetherington, all rights reserved. 8 | * Copyright (c) 1998-2017 Eddie Kohler 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a 11 | * copy of this software and associated documentation files (the 12 | * "Software"), to deal in the Software without restriction, subject to the 13 | * conditions listed in the Click LICENSE file, which is available in full at 14 | * http://github.com/kohler/click/blob/master/LICENSE. The conditions 15 | * include: you must preserve this copyright notice, and you cannot mention 16 | * the copyright holders in advertising related to the Software without 17 | * their permission. The Software is provided WITHOUT ANY WARRANTY, EXPRESS 18 | * OR IMPLIED. This notice is a summary of the Click LICENSE file; the 19 | * license in that file is binding. 20 | * 21 | * New change log in `NEWS'. Old change log: 22 | * 23 | * Revision 1.2 92/06/23 10:57:33 ilh 24 | * MSDOS porting by Kai-Uwe Herbing (herbing@netmbx.netmbx.de) 25 | * incoporated. 26 | * 27 | * Revision 1.1 92/05/22 12:07:49 ilh 28 | * initial version 29 | * 30 | * Ported to Microsoft C/C++ Compiler and MS-DOS operating system by 31 | * Kai-Uwe Herbing (herbing@netmbx.netmbx.de) on June 12, 1992. Code 32 | * specific to the MS-DOS version is encapsulated with #ifdef _MSDOS 33 | * ... #endif, where _MSDOS is an identifier, which is automatically 34 | * defined, if you compile with the Microsoft C/C++ Compiler. 35 | * */ 36 | 37 | /* Note: this is ANSI C. */ 38 | 39 | #ifdef HAVE_CONFIG_H 40 | # include 41 | #endif 42 | #if defined(_MSDOS) || defined(_WIN32) 43 | # include 44 | # include 45 | # include 46 | #endif 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include "t1lib.h" 56 | 57 | #ifdef __cplusplus 58 | extern "C" { 59 | #endif 60 | 61 | /* Some functions to read one, two, three, and four byte integers in 68000 62 | byte order (most significant byte first). */ 63 | 64 | static int 65 | read_one(FILE *fi) 66 | { 67 | return getc(fi); 68 | } 69 | 70 | static int 71 | read_two(FILE *fi) 72 | { 73 | int val; 74 | 75 | val = getc(fi); 76 | val = (val << 8) | getc(fi); 77 | 78 | return val; 79 | } 80 | 81 | static int32_t 82 | read_three(FILE *fi) 83 | { 84 | int32_t val; 85 | 86 | val = getc(fi); 87 | val = (val << 8) | getc(fi); 88 | val = (val << 8) | getc(fi); 89 | 90 | return val; 91 | } 92 | 93 | static int32_t 94 | read_four(FILE *fi) 95 | { 96 | int32_t val; 97 | 98 | val = getc(fi); 99 | val = (val << 8) | getc(fi); 100 | val = (val << 8) | getc(fi); 101 | val = (val << 8) | getc(fi); 102 | 103 | return val; 104 | } 105 | 106 | /* reposition a file with error messages */ 107 | 108 | static void 109 | reposition(FILE *fi, int32_t absolute) 110 | { 111 | if (fseek(fi, absolute, 0) == -1) 112 | fatal_error("can't seek to position %d\n\ 113 | (The Mac file may be corrupted, or you may need the `-r' option.)", 114 | absolute); 115 | } 116 | 117 | static int blocklen = -1; 118 | 119 | static int hex_column = 0; /* current column of hex ASCII output */ 120 | 121 | static void 122 | output_hex_byte(FILE *fo, int b) 123 | { 124 | static const char *hex = "0123456789abcdef"; 125 | 126 | if (hex_column >= blocklen) { 127 | putc('\n', fo); 128 | hex_column = 0; 129 | } 130 | putc(hex[b >> 4], fo); 131 | putc(hex[b & 0xf], fo); 132 | hex_column += 2; 133 | } 134 | 135 | /* Function to extract a particular POST resource. Offset points to the four 136 | byte length which is followed by the data. The first byte of the POST data 137 | specifies resource type: 1 for ASCII, 2 for binary, and 5 for end. The 138 | second byte is always zero. */ 139 | 140 | 141 | /* Function to write four byte length to PFB file: least significant byte 142 | first. */ 143 | 144 | static int 145 | extract_data(FILE *fi, FILE *fo, struct pfb_writer *w, int32_t offset, int pfb) 146 | { 147 | enum PS_type { PS_ascii = 1, PS_binary = 2, PS_end = 5 }; 148 | static int last_type = -1; 149 | static int skip_newline = 0; 150 | int32_t len; 151 | int more = 1; 152 | int i, c; 153 | 154 | reposition(fi, offset); 155 | len = read_four(fi) - 2; /* subtract type field */ 156 | 157 | switch ((enum PS_type)read_one(fi)) { 158 | 159 | case PS_ascii: { 160 | (void) read_one(fi); 161 | if (last_type != PFB_ASCII && pfb) { 162 | pfb_writer_output_block(w); 163 | w->blocktyp = PFB_ASCII; 164 | } 165 | for (i = 0; i < len; i++) { 166 | c = read_one(fi); 167 | if (c == '\n' && skip_newline) { 168 | skip_newline = 0; 169 | continue; 170 | } 171 | if (c == '\r') { 172 | c = '\n'; 173 | skip_newline = 1; 174 | } else 175 | skip_newline = 0; 176 | if (pfb) 177 | PFB_OUTPUT_BYTE(w, c); 178 | else 179 | putc(c, fo); 180 | } 181 | last_type = PFB_ASCII; 182 | break; 183 | } 184 | 185 | case PS_binary: { 186 | (void) read_one(fi); 187 | if (last_type != PFB_BINARY && pfb) { 188 | pfb_writer_output_block(w); 189 | w->blocktyp = PFB_BINARY; 190 | } else if (last_type != PFB_BINARY) 191 | hex_column = 0; 192 | if (pfb) { 193 | while (len--) 194 | PFB_OUTPUT_BYTE(w, read_one(fi)); 195 | } else { 196 | while (len--) 197 | output_hex_byte(fo, read_one(fi)); 198 | } 199 | last_type = PFB_BINARY; 200 | break; 201 | } 202 | 203 | case PS_end: 204 | more = 0; 205 | break; 206 | 207 | } 208 | 209 | return more; 210 | } 211 | 212 | 213 | /***** 214 | * Command line 215 | **/ 216 | 217 | #define OUTPUT_OPT 301 218 | #define VERSION_OPT 302 219 | #define HELP_OPT 303 220 | #define PFB_OPT 304 221 | #define PFA_OPT 305 222 | #define MACBINARY_OPT 306 223 | #define RAW_OPT 307 224 | #define LINE_LEN_OPT 308 225 | #define APPLEDOUBLE_OPT 309 226 | #define BINHEX_OPT 310 227 | 228 | static Clp_Option options[] = { 229 | { "applesingle", 0, APPLEDOUBLE_OPT, 0, 0 }, 230 | { "appledouble", 0, APPLEDOUBLE_OPT, 0, 0 }, 231 | { "binhex", 0, BINHEX_OPT, 0, 0 }, 232 | { "block-length", 0, LINE_LEN_OPT, Clp_ValUnsigned, 0 }, 233 | { "help", 0, HELP_OPT, 0, 0 }, 234 | { "line-length", 'l', LINE_LEN_OPT, Clp_ValUnsigned, 0 }, 235 | { "macbinary", 0, MACBINARY_OPT, 0, 0 }, 236 | { "output", 'o', OUTPUT_OPT, Clp_ValString, 0 }, 237 | { "pfa", 'a', PFA_OPT, 0, 0 }, 238 | { "pfb", 'b', PFB_OPT, 0, 0 }, 239 | { "raw", 'r', RAW_OPT, 0, 0 }, 240 | { "version", 0, VERSION_OPT, 0, 0 }, 241 | }; 242 | static const char *program_name; 243 | 244 | void 245 | fatal_error(const char *message, ...) 246 | { 247 | va_list val; 248 | va_start(val, message); 249 | fprintf(stderr, "%s: ", program_name); 250 | vfprintf(stderr, message, val); 251 | putc('\n', stderr); 252 | va_end(val); 253 | exit(1); 254 | } 255 | 256 | void 257 | error(const char *message, ...) 258 | { 259 | va_list val; 260 | va_start(val, message); 261 | fprintf(stderr, "%s: ", program_name); 262 | vfprintf(stderr, message, val); 263 | putc('\n', stderr); 264 | va_end(val); 265 | } 266 | 267 | static void 268 | short_usage(void) 269 | { 270 | fprintf(stderr, "Usage: %s [OPTION]... INPUT [OUTPUT]\n\ 271 | Try `%s --help' for more information.\n", 272 | program_name, program_name); 273 | } 274 | 275 | static void 276 | usage(void) 277 | { 278 | printf("\ 279 | `T1unmac' extracts a PostScript Type 1 font from a Macintosh font file. It can\n\ 280 | read MacBinary, AppleSingle, AppleDouble, or BinHex files, or raw Macintosh\n\ 281 | resource forks. The result is written to the standard output unless an OUTPUT\n\ 282 | file is given.\n\ 283 | \n\ 284 | Usage: %s [OPTION]... INPUT [OUTPUT]\n\ 285 | \n\ 286 | Options:\n\ 287 | -r, --raw Input is a raw Macintosh resource fork.\n\ 288 | --macbinary Input is in MacBinary format.\n\ 289 | --applesingle Input is in AppleSingle format.\n\ 290 | --appledouble Input is in AppleDouble format.\n\ 291 | --binhex Input is in BinHex format.\n\ 292 | -a, --pfa Output font in ASCII (PFA) format.\n\ 293 | -b, --pfb Output font in binary (PFB) format. This is\n\ 294 | the default.\n\ 295 | -l, --block-length NUM Set max block length for PFB output.\n\ 296 | -l, --line-length NUM Set max encrypted line length for PFA output.\n\ 297 | -o, --output FILE Write output to FILE.\n\ 298 | -h, --help Print this message and exit.\n\ 299 | --version Print version number and warranty and exit.\n\ 300 | \n\ 301 | Report bugs to .\n", program_name); 302 | } 303 | 304 | 305 | static const char * 306 | check_macbinary(FILE *ifp) 307 | { 308 | int i, j; 309 | char buf[124]; 310 | 311 | /* check "version" bytes at offsets 0 and 74 */ 312 | reposition(ifp, 0); 313 | if (read_one(ifp) != 0) 314 | return "bad version byte"; 315 | reposition(ifp, 74); 316 | if (read_one(ifp) != 0) 317 | return "bad version byte"; 318 | 319 | #if 0 320 | /* write out bullshit */ 321 | {int t; 322 | reposition(ifp, 65); 323 | t = read_four(ifp); 324 | fprintf(stderr, "Type %c%c%c%c\n", (t>>24)&255, (t>>16)&255, (t>>8)&255, t&255); 325 | t = read_four(ifp); 326 | fprintf(stderr, "Creator %c%c%c%c\n", (t>>24)&255, (t>>16)&255, (t>>8)&255, t&255); 327 | t = read_one(ifp); 328 | fprintf(stderr, "Finder flags 1 %02x\n", t); 329 | read_one(ifp); 330 | t = read_two(ifp); 331 | fprintf(stderr, "horizpos %04x\n", t); 332 | t = read_two(ifp); 333 | fprintf(stderr, "vertpos %04x\n", t); 334 | t = read_two(ifp); 335 | fprintf(stderr, "folder id %d\n", t); 336 | t = read_one(ifp); 337 | fprintf(stderr, "protected? %x\n", t); 338 | t = read_one(ifp); 339 | t = read_four(ifp); 340 | fprintf(stderr, "data len %d\n", t); 341 | t = read_four(ifp); 342 | fprintf(stderr, "rsrc len %d\n", t); 343 | t = read_four(ifp); 344 | { 345 | struct tm *crap; 346 | fprintf(stderr, "creation date %x\n", t); 347 | t -= 2082844800; 348 | fprintf(stderr, " %s\n", ctime(&t)); 349 | t = read_four(ifp); 350 | fprintf(stderr, "modification date %x\n", t); 351 | t -= 2082844800; 352 | fprintf(stderr, " %s\n", ctime(&t)); 353 | t = read_two(ifp); 354 | } 355 | fprintf(stderr, "getinfo len %d\n", t); 356 | t = read_one(ifp); 357 | fprintf(stderr, "finderflags 2 %02x\n", t); 358 | reposition(ifp, 116); 359 | t = read_four(ifp); 360 | fprintf(stderr, "total len %d\n", t); 361 | t = read_two(ifp); 362 | fprintf(stderr, "secondary header len %d\n", t); 363 | t = read_one(ifp); 364 | fprintf(stderr, "version %d\n", t); 365 | t = read_one(ifp); 366 | fprintf(stderr, "version %d\n", t); 367 | } 368 | #endif 369 | 370 | /* check file length */ 371 | reposition(ifp, 1); 372 | i = read_one(ifp); 373 | if (i > 63) 374 | return "bad length"; 375 | reposition(ifp, 83); 376 | i = read_four(ifp); 377 | j = read_four(ifp); 378 | if (i < 0 || j < 0 || i >= 0x800000 || j >= 0x800000) 379 | return "bad length"; 380 | 381 | /* check CRC */ 382 | reposition(ifp, 0); 383 | fread(buf, 1, 124, ifp); 384 | if (crcbuf(0, 124, buf) != read_two(ifp)) { 385 | reposition(ifp, 82); 386 | if (read_one(ifp) != 0) 387 | return "bad checksum"; 388 | } 389 | 390 | return 0; 391 | } 392 | 393 | #define APPLESINGLE_MAGIC 0x00051600 394 | #define APPLEDOUBLE_MAGIC 0x00051607 395 | 396 | static const char * 397 | check_appledouble(FILE *ifp) 398 | { 399 | int i; 400 | reposition(ifp, 0); 401 | i = read_four(ifp); 402 | if (i != APPLEDOUBLE_MAGIC && i != APPLESINGLE_MAGIC) 403 | return "bad magic number"; 404 | 405 | return 0; 406 | } 407 | 408 | static const char * 409 | translate_binhex(FILE *f, FILE *tmpf) 410 | { 411 | int i, c = 0, last_char, after_x90, bits, bitpos; 412 | unsigned char value_table[256]; 413 | 414 | /* prepare value table */ 415 | { 416 | const char *table = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr"; 417 | for (i = 0; i < 256; i++) 418 | value_table[i] = 255; 419 | for (i = 0; *table; i++, table++) 420 | value_table[(unsigned char)*table] = i; 421 | } 422 | 423 | /* skip to comment */ 424 | { 425 | const char *comment = "(This file must be converted with BinHex"; 426 | while (!feof(f)) { 427 | const char *s; 428 | for (s = comment; *s; s++) { 429 | c = getc(f); 430 | if (c != *s) 431 | break; 432 | } 433 | /* skip to end of line */ 434 | while (c >= 0 && c != '\n' && c != '\r') 435 | c = getc(f); 436 | /* stop if read comment */ 437 | if (!*s) 438 | goto found_comment; 439 | } 440 | /* failed */ 441 | return "no comment"; 442 | } 443 | 444 | found_comment: 445 | /* skip spaces, look for ':' */ 446 | for (c = ' '; isspace(c); c = getc(f)) ; 447 | if (c != ':') 448 | return "no file-start character"; 449 | 450 | /* found ':', process until you find another ':' */ 451 | last_char = -1; 452 | after_x90 = bits = 0; 453 | bitpos = 10; 454 | for (c = getc(f); c >= 0; c = getc(f)) 455 | if (!isspace(c)) { 456 | /* add 6 bits to bits */ 457 | if (value_table[c] == 255) 458 | break; 459 | bits |= (value_table[c] << bitpos); 460 | bitpos -= 6; 461 | 462 | /* output character(s) */ 463 | if (bitpos <= 2) { 464 | int d = bits >> 8; 465 | bits = (bits << 8) & 0xFF00; 466 | bitpos += 8; 467 | if (after_x90) { 468 | /* handle compression */ 469 | if (d == 0) { 470 | last_char = 0x90; 471 | putc(0x90, tmpf); 472 | } else 473 | for (i = 1; i < d; i++) 474 | putc(last_char, tmpf); 475 | after_x90 = 0; 476 | } else if (d == 0x90) 477 | after_x90 = 1; 478 | else { 479 | last_char = d; 480 | putc(d, tmpf); 481 | } 482 | } 483 | } 484 | 485 | if (c < 0) 486 | return "unexpected EOF"; 487 | else if (c != ':') 488 | return "bad character"; 489 | 490 | fflush(tmpf); 491 | return 0; 492 | } 493 | 494 | static int 495 | check_binhex_crc(FILE *f, int offset, int length) 496 | { 497 | int crc = 0; 498 | char buf[2048]; 499 | reposition(f, offset); 500 | while (length > 0) { 501 | int n = (length < 2048 ? length : 2048); 502 | fread(buf, 1, n, f); 503 | crc = crcbuf(crc, n, buf); 504 | length -= n; 505 | } 506 | return crc == 0; 507 | } 508 | 509 | static const char * 510 | check_binhex(FILE *f) 511 | { 512 | int fname_len, data_len, rsrc_len, off; 513 | 514 | /* check lengths */ 515 | reposition(f, 0); 516 | fname_len = read_one(f); 517 | if (fname_len < 1 || fname_len > 63) 518 | return "bad length"; 519 | reposition(f, 1 + fname_len + 11); 520 | data_len = read_four(f); 521 | rsrc_len = read_four(f); 522 | if (data_len < 0 || rsrc_len < 0 || data_len >= 0x800000 || rsrc_len >= 0x800000) 523 | return "bad length"; 524 | 525 | /* check version */ 526 | reposition(f, 1 + fname_len); 527 | if (read_one(f) != 0) 528 | return "bad version"; 529 | 530 | /* check CRC */ 531 | off = 1 + fname_len + 21; 532 | if (!check_binhex_crc(f, 0, off)) 533 | return "bad header CRC"; 534 | if (!check_binhex_crc(f, off, data_len + 2)) 535 | return "bad data CRC"; 536 | if (!check_binhex_crc(f, off + data_len + 2, rsrc_len + 2)) 537 | return "bad resource fork CRC"; 538 | 539 | return 0; 540 | } 541 | 542 | #ifdef __cplusplus 543 | } 544 | #endif 545 | 546 | 547 | int 548 | main(int argc, char *argv[]) 549 | { 550 | FILE *ifp = 0; 551 | FILE *ofp = 0; 552 | struct pfb_writer w; 553 | const char *ifp_name = ""; 554 | int32_t res_offset, res_data_offset, res_map_offset, type_list_offset; 555 | int32_t post_type; 556 | int num_types, num_extracted = 0, pfb = 1; 557 | int raw = 0, appledouble = 0, binhex = 0, macbinary = 0; 558 | 559 | Clp_Parser *clp = 560 | Clp_NewParser(argc, (const char * const *)argv, sizeof(options) / sizeof(options[0]), options); 561 | program_name = Clp_ProgramName(clp); 562 | 563 | /* interpret command line arguments using CLP */ 564 | while (1) { 565 | int opt = Clp_Next(clp); 566 | switch (opt) { 567 | 568 | case RAW_OPT: 569 | raw = 1; 570 | appledouble = binhex = macbinary = 0; 571 | break; 572 | 573 | case MACBINARY_OPT: 574 | macbinary = 1; 575 | raw = appledouble = binhex = 0; 576 | break; 577 | 578 | case APPLEDOUBLE_OPT: 579 | appledouble = 1; 580 | raw = binhex = macbinary = 0; 581 | break; 582 | 583 | case BINHEX_OPT: 584 | binhex = 1; 585 | raw = appledouble = macbinary = 0; 586 | break; 587 | 588 | output_file: 589 | case OUTPUT_OPT: 590 | if (ofp) 591 | fatal_error("output file already specified"); 592 | if (strcmp(clp->vstr, "-") == 0) 593 | ofp = stdout; 594 | else { 595 | ofp = fopen(clp->vstr, "w"); 596 | if (!ofp) fatal_error("%s: %s", clp->vstr, strerror(errno)); 597 | } 598 | break; 599 | 600 | case PFB_OPT: 601 | pfb = 1; 602 | break; 603 | 604 | case PFA_OPT: 605 | pfb = 0; 606 | break; 607 | 608 | case LINE_LEN_OPT: 609 | blocklen = clp->val.i; 610 | break; 611 | 612 | case HELP_OPT: 613 | usage(); 614 | exit(0); 615 | break; 616 | 617 | case VERSION_OPT: 618 | printf("t1unmac (LCDF t1utils) %s\n", VERSION); 619 | printf("Copyright (C) 1992-2017 I. Lee Hetherington, Eddie Kohler et al.\n\ 620 | This is free software; see the source for copying conditions.\n\ 621 | There is NO warranty, not even for merchantability or fitness for a\n\ 622 | particular purpose.\n"); 623 | exit(0); 624 | break; 625 | 626 | case Clp_NotOption: 627 | if (ifp && ofp) 628 | fatal_error("too many arguments"); 629 | else if (ifp) 630 | goto output_file; 631 | if (strcmp(clp->vstr, "-") == 0) 632 | ifp = stdin; 633 | else { 634 | ifp_name = clp->vstr; 635 | ifp = fopen(clp->vstr, "rb"); 636 | if (!ifp) fatal_error("%s: %s", clp->vstr, strerror(errno)); 637 | } 638 | break; 639 | 640 | case Clp_Done: 641 | goto done; 642 | 643 | case Clp_BadOption: 644 | short_usage(); 645 | exit(1); 646 | break; 647 | 648 | } 649 | } 650 | 651 | done: 652 | if (!ifp) ifp = stdin; 653 | if (!ofp) ofp = stdout; 654 | 655 | #if defined(_MSDOS) || defined(_WIN32) 656 | _setmode(_fileno(ifp), _O_BINARY); 657 | /* If we are processing a PFB (binary) output */ 658 | /* file, we must set its file mode to binary. */ 659 | if (pfb) 660 | _setmode(_fileno(ofp), _O_BINARY); 661 | #endif 662 | 663 | if (pfb) 664 | init_pfb_writer(&w, blocklen, ofp); 665 | else { 666 | if (blocklen == -1) 667 | blocklen = 64; 668 | else if (blocklen < 8) { 669 | blocklen = 8; 670 | error("warning: line length raised to %d", blocklen); 671 | } else if (blocklen > 1024) { 672 | blocklen = 1024; 673 | error("warning: line length lowered to %d", blocklen); 674 | } 675 | } 676 | 677 | /* check for non-seekable input */ 678 | if (fseek(ifp, 0, 0)) { 679 | char buf[2048]; 680 | FILE *tmp = tmpfile(); 681 | if (!tmp) 682 | fatal_error("cannot open temporary file: %s", strerror(errno)); 683 | while (!feof(ifp)) { 684 | int i = fread(buf, 1, 2048, ifp); 685 | if (i > 0) 686 | fwrite(buf, 1, i, tmp); 687 | } 688 | if (ferror(ifp)) 689 | fatal_error("%s: %s", ifp_name, strerror(errno)); 690 | reposition(tmp, 0); 691 | fflush(tmp); 692 | if (ifp != stdin) 693 | fclose(ifp); 694 | ifp = tmp; 695 | } 696 | 697 | /* check for empty file */ 698 | fseek(ifp, 0, 2); 699 | if (ftell(ifp) == 0) 700 | fatal_error("%s: empty file\n\ 701 | (Try re-transferring the files using MacBinary format.)", 702 | ifp_name); 703 | 704 | reposition(ifp, 0); 705 | if (!raw && !appledouble && !binhex && !macbinary) { 706 | /* check magic number, try to figure out what it is */ 707 | int i, magic; 708 | magic = read_four(ifp); 709 | reposition(ifp, 0); 710 | 711 | if (magic == APPLESINGLE_MAGIC || magic == APPLEDOUBLE_MAGIC) 712 | appledouble = 1; 713 | else if ((magic & 0xFF000000) == 0) 714 | macbinary = 1; 715 | else { 716 | binhex = 1; 717 | for (i = 0; i < 4; i++, magic >>= 8) 718 | if (!isprint(magic & 0xFF) && !isspace(magic & 0xFF)) 719 | /* not an ASCII character, assume not BinHex */ 720 | binhex = 0; 721 | } 722 | 723 | if (!appledouble && !macbinary && !binhex) 724 | fatal_error("%s: unknown file type", ifp_name); 725 | } 726 | 727 | if (raw) { 728 | /* raw resource file */ 729 | res_offset = 0; 730 | 731 | } else if (macbinary) { /* MacBinary (I or II) file */ 732 | const char *check; 733 | int32_t data_fork_size; 734 | 735 | /* check integrity of file */ 736 | check = check_macbinary(ifp); 737 | if (check) 738 | fatal_error("%s: not a MacBinary file (%s)", ifp_name, check); 739 | 740 | /* read data and resource fork sizes in MacBinary header */ 741 | reposition(ifp, 83); 742 | data_fork_size = read_four(ifp); 743 | (void) read_four(ifp); 744 | 745 | /* round data_fork_size up to multiple of 128 */ 746 | if (data_fork_size % 128) 747 | data_fork_size += 128 - data_fork_size % 128; 748 | 749 | res_offset = 128 + data_fork_size; 750 | 751 | } else if (appledouble) { /* AppleDouble file */ 752 | const char *check; 753 | const char *applewhat; 754 | int i, n; 755 | 756 | /* check integrity */ 757 | check = check_appledouble(ifp); 758 | if (check) 759 | fatal_error("%s: not an AppleDouble file (%s)", ifp_name, check); 760 | reposition(ifp, 0); 761 | if (read_four(ifp) == APPLESINGLE_MAGIC) 762 | applewhat = "AppleSingle"; 763 | else 764 | applewhat = "AppleDouble"; 765 | 766 | /* find offset to resource and/or data fork */ 767 | reposition(ifp, 24); 768 | n = read_two(ifp); 769 | res_offset = -1; 770 | for (i = 0; i < n; i++) { 771 | int type = read_four(ifp); 772 | if (type == 0) 773 | fatal_error("%s: bad %s file (bad entry descriptor)", ifp_name, applewhat); 774 | if (type == 2) /* resource fork entry */ 775 | res_offset = read_four(ifp); 776 | else 777 | (void) read_four(ifp); 778 | (void) read_four(ifp); 779 | } 780 | if (res_offset < 0) 781 | fatal_error("%s: bad %s file (no resource fork)", ifp_name, applewhat); 782 | 783 | } else if (binhex) { /* BinHex file */ 784 | const char *check; 785 | FILE *tmpf = tmpfile(); 786 | if (!tmpf) 787 | fatal_error("cannot open temporary file: %s", strerror(errno)); 788 | 789 | /* check integrity */ 790 | check = translate_binhex(ifp, tmpf); 791 | if (check) 792 | fatal_error("%s: not a BinHex file (%s)", ifp_name, check); 793 | check = check_binhex(tmpf); 794 | if (check) 795 | fatal_error("%s: bad BinHex file (%s)", ifp_name, check); 796 | 797 | /* find resource offset */ 798 | reposition(tmpf, 0); 799 | res_offset = read_one(tmpf); 800 | reposition(tmpf, 1 + res_offset + 11); 801 | res_offset += 22 + read_four(tmpf) + 2; 802 | if (ifp != stdin) 803 | fclose(ifp); 804 | ifp = tmpf; 805 | 806 | } else { 807 | fatal_error("%s: strange format", ifp_name); 808 | exit(1); 809 | } 810 | 811 | /* read offsets from resource fork header */ 812 | reposition(ifp, res_offset); 813 | res_data_offset = res_offset + read_four(ifp); 814 | res_map_offset = res_offset + read_four(ifp); 815 | 816 | /* read type list offset from resource map header */ 817 | reposition(ifp, res_map_offset + 24); 818 | type_list_offset = res_map_offset + read_two(ifp); 819 | 820 | /* read type list */ 821 | reposition(ifp, type_list_offset); 822 | num_types = read_two(ifp) + 1; 823 | 824 | /* find POST type */ 825 | post_type = (int32_t)('P' & 0xff) << 24; 826 | post_type |= (int32_t)('O' & 0xff) << 16; 827 | post_type |= (int32_t)('S' & 0xff) << 8; 828 | post_type |= (int32_t)('T' & 0xff); 829 | 830 | while (num_types--) { 831 | if (read_four(ifp) == post_type) { 832 | int nrsrc = 1 + read_two(ifp); 833 | int list_offset = type_list_offset + read_two(ifp); 834 | int rsrc_pos = 0; 835 | int want_id = 501; 836 | int second_time = 1; 837 | reposition(ifp, list_offset); 838 | /* read resources sequentially, starting with ID 501, until we encounter 839 | an "end" resource or we can't find the next resource */ 840 | while (rsrc_pos < nrsrc) { 841 | int offset = ftell(ifp); 842 | int id = read_two(ifp); 843 | if (id == want_id) { 844 | (void) read_two(ifp); 845 | (void) read_one(ifp); 846 | num_extracted++; 847 | if (!extract_data(ifp, ofp, &w, res_data_offset + read_three(ifp), pfb)) 848 | break; 849 | second_time = 0; 850 | want_id++; 851 | } 852 | reposition(ifp, offset + 12); 853 | rsrc_pos++; 854 | if (rsrc_pos >= nrsrc && !second_time) { 855 | reposition(ifp, list_offset); 856 | rsrc_pos = 0; 857 | } 858 | } 859 | break; 860 | } else { 861 | (void) read_two(ifp); 862 | (void) read_two(ifp); 863 | } 864 | } 865 | 866 | #if 0 867 | system("/bin/rm -f /tmp/x.*"); 868 | { 869 | FILE *f; 870 | int i; 871 | reposition(ifp, res_offset + 16); 872 | if ((f = fopen("/tmp/x.systemarea", "wb"))) { 873 | for (i = res_offset + 16; i < res_data_offset; i++) { 874 | putc(getc(ifp), f); 875 | } 876 | fclose(f); 877 | } 878 | } 879 | reposition(ifp, type_list_offset); 880 | num_types = read_two(ifp) + 1; 881 | while (num_types--) { 882 | int t = read_four(ifp); 883 | int num_of_type = 1 + read_two(ifp); 884 | int32_t save_offset = ftell(ifp) + 2; 885 | reposition(ifp, type_list_offset + read_two(ifp)); 886 | while (num_of_type--) { 887 | FILE *f; 888 | char buf[2048]; 889 | int x, i, attrs; 890 | x = ftell(ifp); 891 | i = read_two(ifp); /* ID */ 892 | read_two(ifp); 893 | attrs = read_one(ifp); 894 | sprintf(buf, "/tmp/x.%c%c%c%c.%d", (t>>24)&255, (t>>16)&255, (t>>8)&255, t&255, i); 895 | fprintf(stderr, "%c%c%c%c.%d %d", (t>>24)&255, (t>>16)&255, (t>>8)&255, t&255, i, attrs); 896 | if ((f = fopen(buf, "wb"))) { 897 | int l; 898 | reposition(ifp, res_data_offset + read_three(ifp)); 899 | l = read_four(ifp); 900 | fprintf(stderr, " %d\n", l); 901 | while (l > 0) { 902 | int n = (l < 2048 ? l : 2048); 903 | fread(buf, 1, n, ifp); 904 | fwrite(buf, 1, n, f); 905 | l -= n; 906 | } 907 | fclose(f); 908 | } 909 | reposition(ifp, x + 12); 910 | } 911 | reposition(ifp, save_offset); 912 | } 913 | #endif 914 | 915 | if (pfb) 916 | pfb_writer_end(&w); 917 | if (num_extracted == 0) 918 | error("%s: not a Type 1 font (no POST resources)", ifp_name); 919 | 920 | fclose(ifp); 921 | fclose(ofp); 922 | return 0; 923 | } 924 | --------------------------------------------------------------------------------