diff options
Diffstat (limited to 'fofi')
41 files changed, 10214 insertions, 0 deletions
diff --git a/fofi/CMakeFiles/CMakeDirectoryInformation.cmake b/fofi/CMakeFiles/CMakeDirectoryInformation.cmake new file mode 100644 index 0000000..aef4d6c --- /dev/null +++ b/fofi/CMakeFiles/CMakeDirectoryInformation.cmake @@ -0,0 +1,16 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.18 + +# Relative path conversion top directories. +set(CMAKE_RELATIVE_PATH_TOP_SOURCE "/home/calvin/src/xpdf-4.04") +set(CMAKE_RELATIVE_PATH_TOP_BINARY "/home/calvin/src/xpdf-4.04") + +# Force unix paths in dependencies. +set(CMAKE_FORCE_UNIX_PATHS 1) + + +# The C and CXX include file regular expressions for this directory. +set(CMAKE_C_INCLUDE_REGEX_SCAN "^.*$") +set(CMAKE_C_INCLUDE_REGEX_COMPLAIN "^$") +set(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN}) +set(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN}) diff --git a/fofi/CMakeFiles/fofi.dir/DependInfo.cmake b/fofi/CMakeFiles/fofi.dir/DependInfo.cmake new file mode 100644 index 0000000..19fab21 --- /dev/null +++ b/fofi/CMakeFiles/fofi.dir/DependInfo.cmake @@ -0,0 +1,11 @@ +# The set of languages for which implicit dependencies are needed: +set(CMAKE_DEPENDS_LANGUAGES + ) +# The set of files for implicit dependencies of each language: + +# Targets to which this target links. +set(CMAKE_TARGET_LINKED_INFO_FILES + ) + +# Fortran module output directory. +set(CMAKE_Fortran_TARGET_MODULE_DIR "") diff --git a/fofi/CMakeFiles/fofi.dir/build.make b/fofi/CMakeFiles/fofi.dir/build.make new file mode 100644 index 0000000..088891c --- /dev/null +++ b/fofi/CMakeFiles/fofi.dir/build.make @@ -0,0 +1,115 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.18 + +# Delete rule output on recipe failure. +.DELETE_ON_ERROR: + + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + + +# Disable VCS-based implicit rules. +% : %,v + + +# Disable VCS-based implicit rules. +% : RCS/% + + +# Disable VCS-based implicit rules. +% : RCS/%,v + + +# Disable VCS-based implicit rules. +% : SCCS/s.% + + +# Disable VCS-based implicit rules. +% : s.% + + +.SUFFIXES: .hpux_make_needs_suffix_list + + +# Command-line flag to silence nested $(MAKE). +$(VERBOSE)MAKESILENT = -s + +#Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: + +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E rm -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/calvin/src/xpdf-4.04 + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/calvin/src/xpdf-4.04 + +# Include any dependencies generated for this target. +include fofi/CMakeFiles/fofi.dir/depend.make + +# Include the progress variables for this target. +include fofi/CMakeFiles/fofi.dir/progress.make + +# Include the compile flags for this target's objects. +include fofi/CMakeFiles/fofi.dir/flags.make + +# Object files for target fofi +fofi_OBJECTS = + +# External object files for target fofi +fofi_EXTERNAL_OBJECTS = \ +"/home/calvin/src/xpdf-4.04/fofi/CMakeFiles/fofi_objs.dir/FoFiBase.cc.o" \ +"/home/calvin/src/xpdf-4.04/fofi/CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.o" \ +"/home/calvin/src/xpdf-4.04/fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o" \ +"/home/calvin/src/xpdf-4.04/fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o" \ +"/home/calvin/src/xpdf-4.04/fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.o" \ +"/home/calvin/src/xpdf-4.04/fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o" + +fofi/libfofi.a: fofi/CMakeFiles/fofi_objs.dir/FoFiBase.cc.o +fofi/libfofi.a: fofi/CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.o +fofi/libfofi.a: fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o +fofi/libfofi.a: fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o +fofi/libfofi.a: fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.o +fofi/libfofi.a: fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o +fofi/libfofi.a: fofi/CMakeFiles/fofi.dir/build.make +fofi/libfofi.a: fofi/CMakeFiles/fofi.dir/link.txt + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --bold --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_1) "Linking CXX static library libfofi.a" + cd /home/calvin/src/xpdf-4.04/fofi && $(CMAKE_COMMAND) -P CMakeFiles/fofi.dir/cmake_clean_target.cmake + cd /home/calvin/src/xpdf-4.04/fofi && $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/fofi.dir/link.txt --verbose=$(VERBOSE) + +# Rule to build all files generated by this target. +fofi/CMakeFiles/fofi.dir/build: fofi/libfofi.a + +.PHONY : fofi/CMakeFiles/fofi.dir/build + +fofi/CMakeFiles/fofi.dir/clean: + cd /home/calvin/src/xpdf-4.04/fofi && $(CMAKE_COMMAND) -P CMakeFiles/fofi.dir/cmake_clean.cmake +.PHONY : fofi/CMakeFiles/fofi.dir/clean + +fofi/CMakeFiles/fofi.dir/depend: + cd /home/calvin/src/xpdf-4.04 && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /home/calvin/src/xpdf-4.04 /home/calvin/src/xpdf-4.04/fofi /home/calvin/src/xpdf-4.04 /home/calvin/src/xpdf-4.04/fofi /home/calvin/src/xpdf-4.04/fofi/CMakeFiles/fofi.dir/DependInfo.cmake --color=$(COLOR) +.PHONY : fofi/CMakeFiles/fofi.dir/depend + diff --git a/fofi/CMakeFiles/fofi.dir/cmake_clean.cmake b/fofi/CMakeFiles/fofi.dir/cmake_clean.cmake new file mode 100644 index 0000000..fcbacc2 --- /dev/null +++ b/fofi/CMakeFiles/fofi.dir/cmake_clean.cmake @@ -0,0 +1,9 @@ +file(REMOVE_RECURSE + "libfofi.a" + "libfofi.pdb" +) + +# Per-language clean rules from dependency scanning. +foreach(lang CXX) + include(CMakeFiles/fofi.dir/cmake_clean_${lang}.cmake OPTIONAL) +endforeach() diff --git a/fofi/CMakeFiles/fofi.dir/cmake_clean_target.cmake b/fofi/CMakeFiles/fofi.dir/cmake_clean_target.cmake new file mode 100644 index 0000000..71175d3 --- /dev/null +++ b/fofi/CMakeFiles/fofi.dir/cmake_clean_target.cmake @@ -0,0 +1,3 @@ +file(REMOVE_RECURSE + "libfofi.a" +) diff --git a/fofi/CMakeFiles/fofi.dir/depend.internal b/fofi/CMakeFiles/fofi.dir/depend.internal new file mode 100644 index 0000000..756f521 --- /dev/null +++ b/fofi/CMakeFiles/fofi.dir/depend.internal @@ -0,0 +1,3 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.18 + diff --git a/fofi/CMakeFiles/fofi.dir/depend.make b/fofi/CMakeFiles/fofi.dir/depend.make new file mode 100644 index 0000000..756f521 --- /dev/null +++ b/fofi/CMakeFiles/fofi.dir/depend.make @@ -0,0 +1,3 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.18 + diff --git a/fofi/CMakeFiles/fofi.dir/flags.make b/fofi/CMakeFiles/fofi.dir/flags.make new file mode 100644 index 0000000..b3b8b67 --- /dev/null +++ b/fofi/CMakeFiles/fofi.dir/flags.make @@ -0,0 +1,10 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.18 + +# compile CXX with /usr/bin/c++ +CXX_DEFINES = + +CXX_INCLUDES = -I/home/calvin/src/xpdf-4.04 -I/home/calvin/src/xpdf-4.04/goo + +CXX_FLAGS = + diff --git a/fofi/CMakeFiles/fofi.dir/link.txt b/fofi/CMakeFiles/fofi.dir/link.txt new file mode 100644 index 0000000..98a9ca1 --- /dev/null +++ b/fofi/CMakeFiles/fofi.dir/link.txt @@ -0,0 +1,2 @@ +/usr/bin/ar qc libfofi.a CMakeFiles/fofi_objs.dir/FoFiBase.cc.o CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.o CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o CMakeFiles/fofi_objs.dir/FoFiType1.cc.o CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o +/usr/bin/ranlib libfofi.a diff --git a/fofi/CMakeFiles/fofi.dir/progress.make b/fofi/CMakeFiles/fofi.dir/progress.make new file mode 100644 index 0000000..225de34 --- /dev/null +++ b/fofi/CMakeFiles/fofi.dir/progress.make @@ -0,0 +1,2 @@ +CMAKE_PROGRESS_1 = + diff --git a/fofi/CMakeFiles/fofi_objs.dir/CXX.includecache b/fofi/CMakeFiles/fofi_objs.dir/CXX.includecache new file mode 100644 index 0000000..432133e --- /dev/null +++ b/fofi/CMakeFiles/fofi_objs.dir/CXX.includecache @@ -0,0 +1,198 @@ +#IncludeRegexLine: ^[ ]*[#%][ ]*(include|import)[ ]*[<"]([^">]+)([">]) + +#IncludeRegexScan: ^.*$ + +#IncludeRegexComplain: ^$ + +#IncludeRegexTransform: + +/home/calvin/src/xpdf-4.04/fofi/FoFiBase.cc +aconf.h +- +stdio.h +- +limits.h +- +gmem.h +/home/calvin/src/xpdf-4.04/fofi/gmem.h +gmempp.h +/home/calvin/src/xpdf-4.04/fofi/gmempp.h +FoFiBase.h +/home/calvin/src/xpdf-4.04/fofi/FoFiBase.h + +/home/calvin/src/xpdf-4.04/fofi/FoFiBase.h +aconf.h +- +gtypes.h +/home/calvin/src/xpdf-4.04/fofi/gtypes.h + +/home/calvin/src/xpdf-4.04/fofi/FoFiEncodings.cc +aconf.h +- +stdlib.h +- +gmempp.h +/home/calvin/src/xpdf-4.04/fofi/gmempp.h +FoFiEncodings.h +/home/calvin/src/xpdf-4.04/fofi/FoFiEncodings.h + +/home/calvin/src/xpdf-4.04/fofi/FoFiEncodings.h +aconf.h +- +gtypes.h +/home/calvin/src/xpdf-4.04/fofi/gtypes.h + +/home/calvin/src/xpdf-4.04/fofi/FoFiIdentifier.cc +aconf.h +- +stdio.h +- +string.h +- +limits.h +- +gtypes.h +/home/calvin/src/xpdf-4.04/fofi/gtypes.h +gmem.h +/home/calvin/src/xpdf-4.04/fofi/gmem.h +gmempp.h +/home/calvin/src/xpdf-4.04/fofi/gmempp.h +GString.h +/home/calvin/src/xpdf-4.04/fofi/GString.h +GList.h +/home/calvin/src/xpdf-4.04/fofi/GList.h +FoFiIdentifier.h +/home/calvin/src/xpdf-4.04/fofi/FoFiIdentifier.h + +/home/calvin/src/xpdf-4.04/fofi/FoFiIdentifier.h +aconf.h +- + +/home/calvin/src/xpdf-4.04/fofi/FoFiTrueType.cc +aconf.h +- +stdlib.h +- +string.h +- +algorithm +- +gtypes.h +/home/calvin/src/xpdf-4.04/fofi/gtypes.h +gmem.h +/home/calvin/src/xpdf-4.04/fofi/gmem.h +gmempp.h +/home/calvin/src/xpdf-4.04/fofi/gmempp.h +GString.h +/home/calvin/src/xpdf-4.04/fofi/GString.h +GHash.h +/home/calvin/src/xpdf-4.04/fofi/GHash.h +FoFiType1C.h +/home/calvin/src/xpdf-4.04/fofi/FoFiType1C.h +FoFiTrueType.h +/home/calvin/src/xpdf-4.04/fofi/FoFiTrueType.h + +/home/calvin/src/xpdf-4.04/fofi/FoFiTrueType.h +aconf.h +- +gtypes.h +/home/calvin/src/xpdf-4.04/fofi/gtypes.h +FoFiBase.h +/home/calvin/src/xpdf-4.04/fofi/FoFiBase.h + +/home/calvin/src/xpdf-4.04/fofi/FoFiType1.cc +aconf.h +- +stdlib.h +- +string.h +- +gmem.h +/home/calvin/src/xpdf-4.04/fofi/gmem.h +gmempp.h +/home/calvin/src/xpdf-4.04/fofi/gmempp.h +FoFiEncodings.h +/home/calvin/src/xpdf-4.04/fofi/FoFiEncodings.h +FoFiType1.h +/home/calvin/src/xpdf-4.04/fofi/FoFiType1.h + +/home/calvin/src/xpdf-4.04/fofi/FoFiType1.h +aconf.h +- +gtypes.h +/home/calvin/src/xpdf-4.04/fofi/gtypes.h +FoFiBase.h +/home/calvin/src/xpdf-4.04/fofi/FoFiBase.h + +/home/calvin/src/xpdf-4.04/fofi/FoFiType1C.cc +aconf.h +- +stdlib.h +- +string.h +- +math.h +- +gmem.h +/home/calvin/src/xpdf-4.04/fofi/gmem.h +gmempp.h +/home/calvin/src/xpdf-4.04/fofi/gmempp.h +GString.h +/home/calvin/src/xpdf-4.04/fofi/GString.h +GHash.h +/home/calvin/src/xpdf-4.04/fofi/GHash.h +FoFiEncodings.h +/home/calvin/src/xpdf-4.04/fofi/FoFiEncodings.h +FoFiType1C.h +/home/calvin/src/xpdf-4.04/fofi/FoFiType1C.h + +/home/calvin/src/xpdf-4.04/fofi/FoFiType1C.h +aconf.h +- +gtypes.h +/home/calvin/src/xpdf-4.04/fofi/gtypes.h +FoFiBase.h +/home/calvin/src/xpdf-4.04/fofi/FoFiBase.h + +aconf.h +aconf2.h +- + +aconf2.h +AvailabilityMacros.h +- + +goo/GHash.h +aconf.h +- +gtypes.h +goo/gtypes.h + +goo/GList.h +aconf.h +- +gtypes.h +goo/gtypes.h + +goo/GString.h +aconf.h +- +limits.h +- +stdarg.h +- +gtypes.h +goo/gtypes.h + +goo/gmem.h +stdio.h +- +aconf.h +- + +goo/gmempp.h +stdlib.h +- + +goo/gtypes.h + diff --git a/fofi/CMakeFiles/fofi_objs.dir/DependInfo.cmake b/fofi/CMakeFiles/fofi_objs.dir/DependInfo.cmake new file mode 100644 index 0000000..fe7f765 --- /dev/null +++ b/fofi/CMakeFiles/fofi_objs.dir/DependInfo.cmake @@ -0,0 +1,27 @@ +# The set of languages for which implicit dependencies are needed: +set(CMAKE_DEPENDS_LANGUAGES + "CXX" + ) +# The set of files for implicit dependencies of each language: +set(CMAKE_DEPENDS_CHECK_CXX + "/home/calvin/src/xpdf-4.04/fofi/FoFiBase.cc" "/home/calvin/src/xpdf-4.04/fofi/CMakeFiles/fofi_objs.dir/FoFiBase.cc.o" + "/home/calvin/src/xpdf-4.04/fofi/FoFiEncodings.cc" "/home/calvin/src/xpdf-4.04/fofi/CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.o" + "/home/calvin/src/xpdf-4.04/fofi/FoFiIdentifier.cc" "/home/calvin/src/xpdf-4.04/fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o" + "/home/calvin/src/xpdf-4.04/fofi/FoFiTrueType.cc" "/home/calvin/src/xpdf-4.04/fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o" + "/home/calvin/src/xpdf-4.04/fofi/FoFiType1.cc" "/home/calvin/src/xpdf-4.04/fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.o" + "/home/calvin/src/xpdf-4.04/fofi/FoFiType1C.cc" "/home/calvin/src/xpdf-4.04/fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o" + ) +set(CMAKE_CXX_COMPILER_ID "GNU") + +# The include file search paths: +set(CMAKE_CXX_TARGET_INCLUDE_PATH + "." + "goo" + ) + +# Targets to which this target links. +set(CMAKE_TARGET_LINKED_INFO_FILES + ) + +# Fortran module output directory. +set(CMAKE_Fortran_TARGET_MODULE_DIR "") diff --git a/fofi/CMakeFiles/fofi_objs.dir/FoFiBase.cc.o b/fofi/CMakeFiles/fofi_objs.dir/FoFiBase.cc.o Binary files differnew file mode 100644 index 0000000..c5393e6 --- /dev/null +++ b/fofi/CMakeFiles/fofi_objs.dir/FoFiBase.cc.o diff --git a/fofi/CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.o b/fofi/CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.o Binary files differnew file mode 100644 index 0000000..e7ce97f --- /dev/null +++ b/fofi/CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.o diff --git a/fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o b/fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o Binary files differnew file mode 100644 index 0000000..89e1f3e --- /dev/null +++ b/fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o diff --git a/fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o b/fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o Binary files differnew file mode 100644 index 0000000..2dca8ab --- /dev/null +++ b/fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o diff --git a/fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.o b/fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.o Binary files differnew file mode 100644 index 0000000..d9d0fc3 --- /dev/null +++ b/fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.o diff --git a/fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o b/fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o Binary files differnew file mode 100644 index 0000000..3943e20 --- /dev/null +++ b/fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o diff --git a/fofi/CMakeFiles/fofi_objs.dir/build.make b/fofi/CMakeFiles/fofi_objs.dir/build.make new file mode 100644 index 0000000..f830d62 --- /dev/null +++ b/fofi/CMakeFiles/fofi_objs.dir/build.make @@ -0,0 +1,179 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.18 + +# Delete rule output on recipe failure. +.DELETE_ON_ERROR: + + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + + +# Disable VCS-based implicit rules. +% : %,v + + +# Disable VCS-based implicit rules. +% : RCS/% + + +# Disable VCS-based implicit rules. +% : RCS/%,v + + +# Disable VCS-based implicit rules. +% : SCCS/s.% + + +# Disable VCS-based implicit rules. +% : s.% + + +.SUFFIXES: .hpux_make_needs_suffix_list + + +# Command-line flag to silence nested $(MAKE). +$(VERBOSE)MAKESILENT = -s + +#Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: + +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E rm -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/calvin/src/xpdf-4.04 + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/calvin/src/xpdf-4.04 + +# Include any dependencies generated for this target. +include fofi/CMakeFiles/fofi_objs.dir/depend.make + +# Include the progress variables for this target. +include fofi/CMakeFiles/fofi_objs.dir/progress.make + +# Include the compile flags for this target's objects. +include fofi/CMakeFiles/fofi_objs.dir/flags.make + +fofi/CMakeFiles/fofi_objs.dir/FoFiBase.cc.o: fofi/CMakeFiles/fofi_objs.dir/flags.make +fofi/CMakeFiles/fofi_objs.dir/FoFiBase.cc.o: fofi/FoFiBase.cc + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_1) "Building CXX object fofi/CMakeFiles/fofi_objs.dir/FoFiBase.cc.o" + cd /home/calvin/src/xpdf-4.04/fofi && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/fofi_objs.dir/FoFiBase.cc.o -c /home/calvin/src/xpdf-4.04/fofi/FoFiBase.cc + +fofi/CMakeFiles/fofi_objs.dir/FoFiBase.cc.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/fofi_objs.dir/FoFiBase.cc.i" + cd /home/calvin/src/xpdf-4.04/fofi && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/calvin/src/xpdf-4.04/fofi/FoFiBase.cc > CMakeFiles/fofi_objs.dir/FoFiBase.cc.i + +fofi/CMakeFiles/fofi_objs.dir/FoFiBase.cc.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/fofi_objs.dir/FoFiBase.cc.s" + cd /home/calvin/src/xpdf-4.04/fofi && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/calvin/src/xpdf-4.04/fofi/FoFiBase.cc -o CMakeFiles/fofi_objs.dir/FoFiBase.cc.s + +fofi/CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.o: fofi/CMakeFiles/fofi_objs.dir/flags.make +fofi/CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.o: fofi/FoFiEncodings.cc + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_2) "Building CXX object fofi/CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.o" + cd /home/calvin/src/xpdf-4.04/fofi && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.o -c /home/calvin/src/xpdf-4.04/fofi/FoFiEncodings.cc + +fofi/CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.i" + cd /home/calvin/src/xpdf-4.04/fofi && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/calvin/src/xpdf-4.04/fofi/FoFiEncodings.cc > CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.i + +fofi/CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.s" + cd /home/calvin/src/xpdf-4.04/fofi && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/calvin/src/xpdf-4.04/fofi/FoFiEncodings.cc -o CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.s + +fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o: fofi/CMakeFiles/fofi_objs.dir/flags.make +fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o: fofi/FoFiIdentifier.cc + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_3) "Building CXX object fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o" + cd /home/calvin/src/xpdf-4.04/fofi && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o -c /home/calvin/src/xpdf-4.04/fofi/FoFiIdentifier.cc + +fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.i" + cd /home/calvin/src/xpdf-4.04/fofi && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/calvin/src/xpdf-4.04/fofi/FoFiIdentifier.cc > CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.i + +fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.s" + cd /home/calvin/src/xpdf-4.04/fofi && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/calvin/src/xpdf-4.04/fofi/FoFiIdentifier.cc -o CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.s + +fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o: fofi/CMakeFiles/fofi_objs.dir/flags.make +fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o: fofi/FoFiTrueType.cc + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_4) "Building CXX object fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o" + cd /home/calvin/src/xpdf-4.04/fofi && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o -c /home/calvin/src/xpdf-4.04/fofi/FoFiTrueType.cc + +fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.i" + cd /home/calvin/src/xpdf-4.04/fofi && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/calvin/src/xpdf-4.04/fofi/FoFiTrueType.cc > CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.i + +fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.s" + cd /home/calvin/src/xpdf-4.04/fofi && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/calvin/src/xpdf-4.04/fofi/FoFiTrueType.cc -o CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.s + +fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.o: fofi/CMakeFiles/fofi_objs.dir/flags.make +fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.o: fofi/FoFiType1.cc + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_5) "Building CXX object fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.o" + cd /home/calvin/src/xpdf-4.04/fofi && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/fofi_objs.dir/FoFiType1.cc.o -c /home/calvin/src/xpdf-4.04/fofi/FoFiType1.cc + +fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/fofi_objs.dir/FoFiType1.cc.i" + cd /home/calvin/src/xpdf-4.04/fofi && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/calvin/src/xpdf-4.04/fofi/FoFiType1.cc > CMakeFiles/fofi_objs.dir/FoFiType1.cc.i + +fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/fofi_objs.dir/FoFiType1.cc.s" + cd /home/calvin/src/xpdf-4.04/fofi && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/calvin/src/xpdf-4.04/fofi/FoFiType1.cc -o CMakeFiles/fofi_objs.dir/FoFiType1.cc.s + +fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o: fofi/CMakeFiles/fofi_objs.dir/flags.make +fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o: fofi/FoFiType1C.cc + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_6) "Building CXX object fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o" + cd /home/calvin/src/xpdf-4.04/fofi && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o -c /home/calvin/src/xpdf-4.04/fofi/FoFiType1C.cc + +fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/fofi_objs.dir/FoFiType1C.cc.i" + cd /home/calvin/src/xpdf-4.04/fofi && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/calvin/src/xpdf-4.04/fofi/FoFiType1C.cc > CMakeFiles/fofi_objs.dir/FoFiType1C.cc.i + +fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/fofi_objs.dir/FoFiType1C.cc.s" + cd /home/calvin/src/xpdf-4.04/fofi && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/calvin/src/xpdf-4.04/fofi/FoFiType1C.cc -o CMakeFiles/fofi_objs.dir/FoFiType1C.cc.s + +fofi_objs: fofi/CMakeFiles/fofi_objs.dir/FoFiBase.cc.o +fofi_objs: fofi/CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.o +fofi_objs: fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o +fofi_objs: fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o +fofi_objs: fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.o +fofi_objs: fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o +fofi_objs: fofi/CMakeFiles/fofi_objs.dir/build.make + +.PHONY : fofi_objs + +# Rule to build all files generated by this target. +fofi/CMakeFiles/fofi_objs.dir/build: fofi_objs + +.PHONY : fofi/CMakeFiles/fofi_objs.dir/build + +fofi/CMakeFiles/fofi_objs.dir/clean: + cd /home/calvin/src/xpdf-4.04/fofi && $(CMAKE_COMMAND) -P CMakeFiles/fofi_objs.dir/cmake_clean.cmake +.PHONY : fofi/CMakeFiles/fofi_objs.dir/clean + +fofi/CMakeFiles/fofi_objs.dir/depend: + cd /home/calvin/src/xpdf-4.04 && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /home/calvin/src/xpdf-4.04 /home/calvin/src/xpdf-4.04/fofi /home/calvin/src/xpdf-4.04 /home/calvin/src/xpdf-4.04/fofi /home/calvin/src/xpdf-4.04/fofi/CMakeFiles/fofi_objs.dir/DependInfo.cmake --color=$(COLOR) +.PHONY : fofi/CMakeFiles/fofi_objs.dir/depend + diff --git a/fofi/CMakeFiles/fofi_objs.dir/cmake_clean.cmake b/fofi/CMakeFiles/fofi_objs.dir/cmake_clean.cmake new file mode 100644 index 0000000..a41cbd8 --- /dev/null +++ b/fofi/CMakeFiles/fofi_objs.dir/cmake_clean.cmake @@ -0,0 +1,13 @@ +file(REMOVE_RECURSE + "CMakeFiles/fofi_objs.dir/FoFiBase.cc.o" + "CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.o" + "CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o" + "CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o" + "CMakeFiles/fofi_objs.dir/FoFiType1.cc.o" + "CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o" +) + +# Per-language clean rules from dependency scanning. +foreach(lang CXX) + include(CMakeFiles/fofi_objs.dir/cmake_clean_${lang}.cmake OPTIONAL) +endforeach() diff --git a/fofi/CMakeFiles/fofi_objs.dir/depend.internal b/fofi/CMakeFiles/fofi_objs.dir/depend.internal new file mode 100644 index 0000000..2c61253 --- /dev/null +++ b/fofi/CMakeFiles/fofi_objs.dir/depend.internal @@ -0,0 +1,62 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.18 + +fofi/CMakeFiles/fofi_objs.dir/FoFiBase.cc.o + /home/calvin/src/xpdf-4.04/fofi/FoFiBase.cc + /home/calvin/src/xpdf-4.04/fofi/FoFiBase.h + aconf.h + aconf2.h + goo/gmem.h + goo/gmempp.h + goo/gtypes.h +fofi/CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.o + /home/calvin/src/xpdf-4.04/fofi/FoFiEncodings.cc + /home/calvin/src/xpdf-4.04/fofi/FoFiEncodings.h + aconf.h + aconf2.h + goo/gmempp.h + goo/gtypes.h +fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o + /home/calvin/src/xpdf-4.04/fofi/FoFiIdentifier.cc + /home/calvin/src/xpdf-4.04/fofi/FoFiIdentifier.h + aconf.h + aconf2.h + goo/GList.h + goo/GString.h + goo/gmem.h + goo/gmempp.h + goo/gtypes.h +fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o + /home/calvin/src/xpdf-4.04/fofi/FoFiBase.h + /home/calvin/src/xpdf-4.04/fofi/FoFiTrueType.cc + /home/calvin/src/xpdf-4.04/fofi/FoFiTrueType.h + /home/calvin/src/xpdf-4.04/fofi/FoFiType1C.h + aconf.h + aconf2.h + goo/GHash.h + goo/GString.h + goo/gmem.h + goo/gmempp.h + goo/gtypes.h +fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.o + /home/calvin/src/xpdf-4.04/fofi/FoFiBase.h + /home/calvin/src/xpdf-4.04/fofi/FoFiEncodings.h + /home/calvin/src/xpdf-4.04/fofi/FoFiType1.cc + /home/calvin/src/xpdf-4.04/fofi/FoFiType1.h + aconf.h + aconf2.h + goo/gmem.h + goo/gmempp.h + goo/gtypes.h +fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o + /home/calvin/src/xpdf-4.04/fofi/FoFiBase.h + /home/calvin/src/xpdf-4.04/fofi/FoFiEncodings.h + /home/calvin/src/xpdf-4.04/fofi/FoFiType1C.cc + /home/calvin/src/xpdf-4.04/fofi/FoFiType1C.h + aconf.h + aconf2.h + goo/GHash.h + goo/GString.h + goo/gmem.h + goo/gmempp.h + goo/gtypes.h diff --git a/fofi/CMakeFiles/fofi_objs.dir/depend.make b/fofi/CMakeFiles/fofi_objs.dir/depend.make new file mode 100644 index 0000000..cc496ef --- /dev/null +++ b/fofi/CMakeFiles/fofi_objs.dir/depend.make @@ -0,0 +1,62 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.18 + +fofi/CMakeFiles/fofi_objs.dir/FoFiBase.cc.o: fofi/FoFiBase.cc +fofi/CMakeFiles/fofi_objs.dir/FoFiBase.cc.o: fofi/FoFiBase.h +fofi/CMakeFiles/fofi_objs.dir/FoFiBase.cc.o: aconf.h +fofi/CMakeFiles/fofi_objs.dir/FoFiBase.cc.o: aconf2.h +fofi/CMakeFiles/fofi_objs.dir/FoFiBase.cc.o: goo/gmem.h +fofi/CMakeFiles/fofi_objs.dir/FoFiBase.cc.o: goo/gmempp.h +fofi/CMakeFiles/fofi_objs.dir/FoFiBase.cc.o: goo/gtypes.h + +fofi/CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.o: fofi/FoFiEncodings.cc +fofi/CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.o: fofi/FoFiEncodings.h +fofi/CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.o: aconf.h +fofi/CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.o: aconf2.h +fofi/CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.o: goo/gmempp.h +fofi/CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.o: goo/gtypes.h + +fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o: fofi/FoFiIdentifier.cc +fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o: fofi/FoFiIdentifier.h +fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o: aconf.h +fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o: aconf2.h +fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o: goo/GList.h +fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o: goo/GString.h +fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o: goo/gmem.h +fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o: goo/gmempp.h +fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o: goo/gtypes.h + +fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o: fofi/FoFiBase.h +fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o: fofi/FoFiTrueType.cc +fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o: fofi/FoFiTrueType.h +fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o: fofi/FoFiType1C.h +fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o: aconf.h +fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o: aconf2.h +fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o: goo/GHash.h +fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o: goo/GString.h +fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o: goo/gmem.h +fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o: goo/gmempp.h +fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o: goo/gtypes.h + +fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.o: fofi/FoFiBase.h +fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.o: fofi/FoFiEncodings.h +fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.o: fofi/FoFiType1.cc +fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.o: fofi/FoFiType1.h +fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.o: aconf.h +fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.o: aconf2.h +fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.o: goo/gmem.h +fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.o: goo/gmempp.h +fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.o: goo/gtypes.h + +fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o: fofi/FoFiBase.h +fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o: fofi/FoFiEncodings.h +fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o: fofi/FoFiType1C.cc +fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o: fofi/FoFiType1C.h +fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o: aconf.h +fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o: aconf2.h +fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o: goo/GHash.h +fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o: goo/GString.h +fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o: goo/gmem.h +fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o: goo/gmempp.h +fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o: goo/gtypes.h + diff --git a/fofi/CMakeFiles/fofi_objs.dir/flags.make b/fofi/CMakeFiles/fofi_objs.dir/flags.make new file mode 100644 index 0000000..8695794 --- /dev/null +++ b/fofi/CMakeFiles/fofi_objs.dir/flags.make @@ -0,0 +1,10 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.18 + +# compile CXX with /usr/bin/c++ +CXX_DEFINES = + +CXX_INCLUDES = -I/home/calvin/src/xpdf-4.04 -I/home/calvin/src/xpdf-4.04/goo + +CXX_FLAGS = -fPIC + diff --git a/fofi/CMakeFiles/fofi_objs.dir/progress.make b/fofi/CMakeFiles/fofi_objs.dir/progress.make new file mode 100644 index 0000000..392d5e4 --- /dev/null +++ b/fofi/CMakeFiles/fofi_objs.dir/progress.make @@ -0,0 +1,7 @@ +CMAKE_PROGRESS_1 = 1 +CMAKE_PROGRESS_2 = 2 +CMAKE_PROGRESS_3 = +CMAKE_PROGRESS_4 = 3 +CMAKE_PROGRESS_5 = 4 +CMAKE_PROGRESS_6 = 5 + diff --git a/fofi/CMakeFiles/progress.marks b/fofi/CMakeFiles/progress.marks new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/fofi/CMakeFiles/progress.marks @@ -0,0 +1 @@ +5 diff --git a/fofi/CMakeLists.txt b/fofi/CMakeLists.txt new file mode 100644 index 0000000..fd61b25 --- /dev/null +++ b/fofi/CMakeLists.txt @@ -0,0 +1,28 @@ +#======================================================================== +# +# fofi/CMakeLists.txt +# +# CMake script for the fofi library. +# +# Copyright 2015 Glyph & Cog, LLC +# +#======================================================================== + +include_directories("${PROJECT_SOURCE_DIR}") +include_directories("${PROJECT_BINARY_DIR}") +include_directories("${PROJECT_SOURCE_DIR}/goo") + +add_library(fofi_objs OBJECT + FoFiBase.cc + FoFiEncodings.cc + FoFiIdentifier.cc + FoFiTrueType.cc + FoFiType1.cc + FoFiType1C.cc +) +set_property(TARGET fofi_objs + PROPERTY POSITION_INDEPENDENT_CODE True) + +add_library(fofi + $<TARGET_OBJECTS:fofi_objs> +) diff --git a/fofi/FoFiBase.cc b/fofi/FoFiBase.cc new file mode 100644 index 0000000..e1951b0 --- /dev/null +++ b/fofi/FoFiBase.cc @@ -0,0 +1,177 @@ +//======================================================================== +// +// FoFiBase.cc +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdio.h> +#include <limits.h> +#include "gmem.h" +#include "gmempp.h" +#include "FoFiBase.h" + +//------------------------------------------------------------------------ +// FoFiBase +//------------------------------------------------------------------------ + +FoFiBase::FoFiBase(char *fileA, int lenA, GBool freeFileDataA) { + fileData = file = (Guchar *)fileA; + len = lenA; + freeFileData = freeFileDataA; +} + +FoFiBase::~FoFiBase() { + if (freeFileData) { + gfree(fileData); + } +} + +char *FoFiBase::readFile(char *fileName, int *fileLen) { + FILE *f; + char *buf; + int n; + + if (!(f = fopen(fileName, "rb"))) { + return NULL; + } + fseek(f, 0, SEEK_END); + n = (int)ftell(f); + if (n < 0) { + fclose(f); + return NULL; + } + fseek(f, 0, SEEK_SET); + buf = (char *)gmalloc(n); + if ((int)fread(buf, 1, n, f) != n) { + gfree(buf); + fclose(f); + return NULL; + } + fclose(f); + *fileLen = n; + return buf; +} + +int FoFiBase::getS8(int pos, GBool *ok) { + int x; + + if (pos < 0 || pos >= len) { + *ok = gFalse; + return 0; + } + x = file[pos]; + if (x & 0x80) { + x |= ~0xff; + } + return x; +} + +int FoFiBase::getU8(int pos, GBool *ok) { + if (pos < 0 || pos >= len) { + *ok = gFalse; + return 0; + } + return file[pos]; +} + +int FoFiBase::getS16BE(int pos, GBool *ok) { + int x; + + if (pos < 0 || pos > INT_MAX - 1 || pos+1 >= len) { + *ok = gFalse; + return 0; + } + x = file[pos]; + x = (x << 8) + file[pos+1]; + if (x & 0x8000) { + x |= ~0xffff; + } + return x; +} + +int FoFiBase::getU16BE(int pos, GBool *ok) { + int x; + + if (pos < 0 || pos > INT_MAX - 1 || pos+1 >= len) { + *ok = gFalse; + return 0; + } + x = file[pos]; + x = (x << 8) + file[pos+1]; + return x; +} + +int FoFiBase::getS32BE(int pos, GBool *ok) { + int x; + + if (pos < 0 || pos > INT_MAX - 3 || pos+3 >= len) { + *ok = gFalse; + return 0; + } + x = file[pos]; + x = (x << 8) + file[pos+1]; + x = (x << 8) + file[pos+2]; + x = (x << 8) + file[pos+3]; + if (x & 0x80000000) { + x |= ~0xffffffff; + } + return x; +} + +Guint FoFiBase::getU32BE(int pos, GBool *ok) { + Guint x; + + if (pos < 0 || pos > INT_MAX - 3 || pos+3 >= len) { + *ok = gFalse; + return 0; + } + x = file[pos]; + x = (x << 8) + file[pos+1]; + x = (x << 8) + file[pos+2]; + x = (x << 8) + file[pos+3]; + return x; +} + +Guint FoFiBase::getU32LE(int pos, GBool *ok) { + Guint x; + + if (pos < 0 || pos > INT_MAX - 3 || pos+3 >= len) { + *ok = gFalse; + return 0; + } + x = file[pos+3]; + x = (x << 8) + file[pos+2]; + x = (x << 8) + file[pos+1]; + x = (x << 8) + file[pos]; + return x; +} + +Guint FoFiBase::getUVarBE(int pos, int size, GBool *ok) { + Guint x; + int i; + + if (pos < 0 || pos > INT_MAX - size || pos + size > len) { + *ok = gFalse; + return 0; + } + x = 0; + for (i = 0; i < size; ++i) { + x = (x << 8) + file[pos + i]; + } + return x; +} + +GBool FoFiBase::checkRegion(int pos, int size) { + return pos >= 0 && + size >= 0 && + size <= INT_MAX - pos && + pos + size <= len; +} diff --git a/fofi/FoFiBase.h b/fofi/FoFiBase.h new file mode 100644 index 0000000..c9f93eb --- /dev/null +++ b/fofi/FoFiBase.h @@ -0,0 +1,58 @@ +//======================================================================== +// +// FoFiBase.h +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FOFIBASE_H +#define FOFIBASE_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +//------------------------------------------------------------------------ + +typedef void (*FoFiOutputFunc)(void *stream, const char *data, int len); + +//------------------------------------------------------------------------ +// FoFiBase +//------------------------------------------------------------------------ + +class FoFiBase { +public: + + virtual ~FoFiBase(); + +protected: + + FoFiBase(char *fileA, int lenA, GBool freeFileDataA); + static char *readFile(char *fileName, int *fileLen); + + // S = signed / U = unsigned + // 8/16/32/Var = word length, in bytes + // BE = big endian + int getS8(int pos, GBool *ok); + int getU8(int pos, GBool *ok); + int getS16BE(int pos, GBool *ok); + int getU16BE(int pos, GBool *ok); + int getS32BE(int pos, GBool *ok); + Guint getU32BE(int pos, GBool *ok); + Guint getU32LE(int pos, GBool *ok); + Guint getUVarBE(int pos, int size, GBool *ok); + + GBool checkRegion(int pos, int size); + + Guchar *fileData; + Guchar *file; + int len; + GBool freeFileData; +}; + +#endif diff --git a/fofi/FoFiEncodings.cc b/fofi/FoFiEncodings.cc new file mode 100644 index 0000000..6b3debb --- /dev/null +++ b/fofi/FoFiEncodings.cc @@ -0,0 +1,995 @@ +//======================================================================== +// +// FoFiEncodings.cc +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdlib.h> +#include "gmempp.h" +#include "FoFiEncodings.h" + +//------------------------------------------------------------------------ +// Type 1 and 1C font data +//------------------------------------------------------------------------ + +const char *fofiType1StandardEncoding[256] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "space", + "exclam", + "quotedbl", + "numbersign", + "dollar", + "percent", + "ampersand", + "quoteright", + "parenleft", + "parenright", + "asterisk", + "plus", + "comma", + "hyphen", + "period", + "slash", + "zero", + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "colon", + "semicolon", + "less", + "equal", + "greater", + "question", + "at", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "bracketleft", + "backslash", + "bracketright", + "asciicircum", + "underscore", + "quoteleft", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "braceleft", + "bar", + "braceright", + "asciitilde", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "exclamdown", + "cent", + "sterling", + "fraction", + "yen", + "florin", + "section", + "currency", + "quotesingle", + "quotedblleft", + "guillemotleft", + "guilsinglleft", + "guilsinglright", + "fi", + "fl", + NULL, + "endash", + "dagger", + "daggerdbl", + "periodcentered", + NULL, + "paragraph", + "bullet", + "quotesinglbase", + "quotedblbase", + "quotedblright", + "guillemotright", + "ellipsis", + "perthousand", + NULL, + "questiondown", + NULL, + "grave", + "acute", + "circumflex", + "tilde", + "macron", + "breve", + "dotaccent", + "dieresis", + NULL, + "ring", + "cedilla", + NULL, + "hungarumlaut", + "ogonek", + "caron", + "emdash", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "AE", + NULL, + "ordfeminine", + NULL, + NULL, + NULL, + NULL, + "Lslash", + "Oslash", + "OE", + "ordmasculine", + NULL, + NULL, + NULL, + NULL, + NULL, + "ae", + NULL, + NULL, + NULL, + "dotlessi", + NULL, + NULL, + "lslash", + "oslash", + "oe", + "germandbls", + NULL, + NULL, + NULL, + NULL +}; + +const char *fofiType1ExpertEncoding[256] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "space", + "exclamsmall", + "Hungarumlautsmall", + NULL, + "dollaroldstyle", + "dollarsuperior", + "ampersandsmall", + "Acutesmall", + "parenleftsuperior", + "parenrightsuperior", + "twodotenleader", + "onedotenleader", + "comma", + "hyphen", + "period", + "fraction", + "zerooldstyle", + "oneoldstyle", + "twooldstyle", + "threeoldstyle", + "fouroldstyle", + "fiveoldstyle", + "sixoldstyle", + "sevenoldstyle", + "eightoldstyle", + "nineoldstyle", + "colon", + "semicolon", + "commasuperior", + "threequartersemdash", + "periodsuperior", + "questionsmall", + NULL, + "asuperior", + "bsuperior", + "centsuperior", + "dsuperior", + "esuperior", + NULL, + NULL, + NULL, + "isuperior", + NULL, + NULL, + "lsuperior", + "msuperior", + "nsuperior", + "osuperior", + NULL, + NULL, + "rsuperior", + "ssuperior", + "tsuperior", + NULL, + "ff", + "fi", + "fl", + "ffi", + "ffl", + "parenleftinferior", + NULL, + "parenrightinferior", + "Circumflexsmall", + "hyphensuperior", + "Gravesmall", + "Asmall", + "Bsmall", + "Csmall", + "Dsmall", + "Esmall", + "Fsmall", + "Gsmall", + "Hsmall", + "Ismall", + "Jsmall", + "Ksmall", + "Lsmall", + "Msmall", + "Nsmall", + "Osmall", + "Psmall", + "Qsmall", + "Rsmall", + "Ssmall", + "Tsmall", + "Usmall", + "Vsmall", + "Wsmall", + "Xsmall", + "Ysmall", + "Zsmall", + "colonmonetary", + "onefitted", + "rupiah", + "Tildesmall", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "exclamdownsmall", + "centoldstyle", + "Lslashsmall", + NULL, + NULL, + "Scaronsmall", + "Zcaronsmall", + "Dieresissmall", + "Brevesmall", + "Caronsmall", + NULL, + "Dotaccentsmall", + NULL, + NULL, + "Macronsmall", + NULL, + NULL, + "figuredash", + "hypheninferior", + NULL, + NULL, + "Ogoneksmall", + "Ringsmall", + "Cedillasmall", + NULL, + NULL, + NULL, + "onequarter", + "onehalf", + "threequarters", + "questiondownsmall", + "oneeighth", + "threeeighths", + "fiveeighths", + "seveneighths", + "onethird", + "twothirds", + NULL, + NULL, + "zerosuperior", + "onesuperior", + "twosuperior", + "threesuperior", + "foursuperior", + "fivesuperior", + "sixsuperior", + "sevensuperior", + "eightsuperior", + "ninesuperior", + "zeroinferior", + "oneinferior", + "twoinferior", + "threeinferior", + "fourinferior", + "fiveinferior", + "sixinferior", + "seveninferior", + "eightinferior", + "nineinferior", + "centinferior", + "dollarinferior", + "periodinferior", + "commainferior", + "Agravesmall", + "Aacutesmall", + "Acircumflexsmall", + "Atildesmall", + "Adieresissmall", + "Aringsmall", + "AEsmall", + "Ccedillasmall", + "Egravesmall", + "Eacutesmall", + "Ecircumflexsmall", + "Edieresissmall", + "Igravesmall", + "Iacutesmall", + "Icircumflexsmall", + "Idieresissmall", + "Ethsmall", + "Ntildesmall", + "Ogravesmall", + "Oacutesmall", + "Ocircumflexsmall", + "Otildesmall", + "Odieresissmall", + "OEsmall", + "Oslashsmall", + "Ugravesmall", + "Uacutesmall", + "Ucircumflexsmall", + "Udieresissmall", + "Yacutesmall", + "Thornsmall", + "Ydieresissmall" +}; + +//------------------------------------------------------------------------ +// Type 1C font data +//------------------------------------------------------------------------ + +const char *fofiType1CStdStrings[391] = { + ".notdef", + "space", + "exclam", + "quotedbl", + "numbersign", + "dollar", + "percent", + "ampersand", + "quoteright", + "parenleft", + "parenright", + "asterisk", + "plus", + "comma", + "hyphen", + "period", + "slash", + "zero", + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "colon", + "semicolon", + "less", + "equal", + "greater", + "question", + "at", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "bracketleft", + "backslash", + "bracketright", + "asciicircum", + "underscore", + "quoteleft", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "braceleft", + "bar", + "braceright", + "asciitilde", + "exclamdown", + "cent", + "sterling", + "fraction", + "yen", + "florin", + "section", + "currency", + "quotesingle", + "quotedblleft", + "guillemotleft", + "guilsinglleft", + "guilsinglright", + "fi", + "fl", + "endash", + "dagger", + "daggerdbl", + "periodcentered", + "paragraph", + "bullet", + "quotesinglbase", + "quotedblbase", + "quotedblright", + "guillemotright", + "ellipsis", + "perthousand", + "questiondown", + "grave", + "acute", + "circumflex", + "tilde", + "macron", + "breve", + "dotaccent", + "dieresis", + "ring", + "cedilla", + "hungarumlaut", + "ogonek", + "caron", + "emdash", + "AE", + "ordfeminine", + "Lslash", + "Oslash", + "OE", + "ordmasculine", + "ae", + "dotlessi", + "lslash", + "oslash", + "oe", + "germandbls", + "onesuperior", + "logicalnot", + "mu", + "trademark", + "Eth", + "onehalf", + "plusminus", + "Thorn", + "onequarter", + "divide", + "brokenbar", + "degree", + "thorn", + "threequarters", + "twosuperior", + "registered", + "minus", + "eth", + "multiply", + "threesuperior", + "copyright", + "Aacute", + "Acircumflex", + "Adieresis", + "Agrave", + "Aring", + "Atilde", + "Ccedilla", + "Eacute", + "Ecircumflex", + "Edieresis", + "Egrave", + "Iacute", + "Icircumflex", + "Idieresis", + "Igrave", + "Ntilde", + "Oacute", + "Ocircumflex", + "Odieresis", + "Ograve", + "Otilde", + "Scaron", + "Uacute", + "Ucircumflex", + "Udieresis", + "Ugrave", + "Yacute", + "Ydieresis", + "Zcaron", + "aacute", + "acircumflex", + "adieresis", + "agrave", + "aring", + "atilde", + "ccedilla", + "eacute", + "ecircumflex", + "edieresis", + "egrave", + "iacute", + "icircumflex", + "idieresis", + "igrave", + "ntilde", + "oacute", + "ocircumflex", + "odieresis", + "ograve", + "otilde", + "scaron", + "uacute", + "ucircumflex", + "udieresis", + "ugrave", + "yacute", + "ydieresis", + "zcaron", + "exclamsmall", + "Hungarumlautsmall", + "dollaroldstyle", + "dollarsuperior", + "ampersandsmall", + "Acutesmall", + "parenleftsuperior", + "parenrightsuperior", + "twodotenleader", + "onedotenleader", + "zerooldstyle", + "oneoldstyle", + "twooldstyle", + "threeoldstyle", + "fouroldstyle", + "fiveoldstyle", + "sixoldstyle", + "sevenoldstyle", + "eightoldstyle", + "nineoldstyle", + "commasuperior", + "threequartersemdash", + "periodsuperior", + "questionsmall", + "asuperior", + "bsuperior", + "centsuperior", + "dsuperior", + "esuperior", + "isuperior", + "lsuperior", + "msuperior", + "nsuperior", + "osuperior", + "rsuperior", + "ssuperior", + "tsuperior", + "ff", + "ffi", + "ffl", + "parenleftinferior", + "parenrightinferior", + "Circumflexsmall", + "hyphensuperior", + "Gravesmall", + "Asmall", + "Bsmall", + "Csmall", + "Dsmall", + "Esmall", + "Fsmall", + "Gsmall", + "Hsmall", + "Ismall", + "Jsmall", + "Ksmall", + "Lsmall", + "Msmall", + "Nsmall", + "Osmall", + "Psmall", + "Qsmall", + "Rsmall", + "Ssmall", + "Tsmall", + "Usmall", + "Vsmall", + "Wsmall", + "Xsmall", + "Ysmall", + "Zsmall", + "colonmonetary", + "onefitted", + "rupiah", + "Tildesmall", + "exclamdownsmall", + "centoldstyle", + "Lslashsmall", + "Scaronsmall", + "Zcaronsmall", + "Dieresissmall", + "Brevesmall", + "Caronsmall", + "Dotaccentsmall", + "Macronsmall", + "figuredash", + "hypheninferior", + "Ogoneksmall", + "Ringsmall", + "Cedillasmall", + "questiondownsmall", + "oneeighth", + "threeeighths", + "fiveeighths", + "seveneighths", + "onethird", + "twothirds", + "zerosuperior", + "foursuperior", + "fivesuperior", + "sixsuperior", + "sevensuperior", + "eightsuperior", + "ninesuperior", + "zeroinferior", + "oneinferior", + "twoinferior", + "threeinferior", + "fourinferior", + "fiveinferior", + "sixinferior", + "seveninferior", + "eightinferior", + "nineinferior", + "centinferior", + "dollarinferior", + "periodinferior", + "commainferior", + "Agravesmall", + "Aacutesmall", + "Acircumflexsmall", + "Atildesmall", + "Adieresissmall", + "Aringsmall", + "AEsmall", + "Ccedillasmall", + "Egravesmall", + "Eacutesmall", + "Ecircumflexsmall", + "Edieresissmall", + "Igravesmall", + "Iacutesmall", + "Icircumflexsmall", + "Idieresissmall", + "Ethsmall", + "Ntildesmall", + "Ogravesmall", + "Oacutesmall", + "Ocircumflexsmall", + "Otildesmall", + "Odieresissmall", + "OEsmall", + "Oslashsmall", + "Ugravesmall", + "Uacutesmall", + "Ucircumflexsmall", + "Udieresissmall", + "Yacutesmall", + "Thornsmall", + "Ydieresissmall", + "001.000", + "001.001", + "001.002", + "001.003", + "Black", + "Bold", + "Book", + "Light", + "Medium", + "Regular", + "Roman", + "Semibold" +}; + +Gushort fofiType1CISOAdobeCharset[229] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228 +}; + +Gushort fofiType1CExpertCharset[166] = { + 0, 1, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 13, 14, 15, 99, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 109, 110, 267, 268, + 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, + 158, 155, 163, 319, 320, 321, 322, 323, 324, 325, + 326, 150, 164, 169, 327, 328, 329, 330, 331, 332, + 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, + 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, + 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, + 373, 374, 375, 376, 377, 378 +}; + +Gushort fofiType1CExpertSubsetCharset[87] = { + 0, 1, 231, 232, 235, 236, 237, 238, 13, 14, + 15, 99, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 27, 28, 249, 250, 251, 253, 254, 255, + 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, + 266, 109, 110, 267, 268, 269, 270, 272, 300, 301, + 302, 305, 314, 315, 158, 155, 163, 320, 321, 322, + 323, 324, 325, 326, 150, 164, 169, 327, 328, 329, + 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346 +}; diff --git a/fofi/FoFiEncodings.h b/fofi/FoFiEncodings.h new file mode 100644 index 0000000..dd85458 --- /dev/null +++ b/fofi/FoFiEncodings.h @@ -0,0 +1,36 @@ +//======================================================================== +// +// FoFiEncodings.h +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FOFIENCODINGS_H +#define FOFIENCODINGS_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +//------------------------------------------------------------------------ +// Type 1 and 1C font data +//------------------------------------------------------------------------ + +extern const char *fofiType1StandardEncoding[256]; +extern const char *fofiType1ExpertEncoding[256]; + +//------------------------------------------------------------------------ +// Type 1C font data +//------------------------------------------------------------------------ + +extern const char *fofiType1CStdStrings[391]; +extern Gushort fofiType1CISOAdobeCharset[229]; +extern Gushort fofiType1CExpertCharset[166]; +extern Gushort fofiType1CExpertSubsetCharset[87]; + +#endif diff --git a/fofi/FoFiIdentifier.cc b/fofi/FoFiIdentifier.cc new file mode 100644 index 0000000..4c6797b --- /dev/null +++ b/fofi/FoFiIdentifier.cc @@ -0,0 +1,887 @@ +//======================================================================== +// +// FoFiIdentifier.cc +// +// Copyright 2009 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include "gtypes.h" +#include "gmem.h" +#include "gmempp.h" +#include "GString.h" +#include "GList.h" +#include "FoFiIdentifier.h" + +//------------------------------------------------------------------------ + +class Reader { +public: + + virtual ~Reader() {} + + // Read one byte. Returns -1 if past EOF. + virtual int getByte(int pos) = 0; + + // Read a big-endian unsigned 16-bit integer. Fills in *val and + // returns true if successful. + virtual GBool getU16BE(int pos, int *val) = 0; + + // Read a big-endian unsigned 32-bit integer. Fills in *val and + // returns true if successful. + virtual GBool getU32BE(int pos, Guint *val) = 0; + + // Read a little-endian unsigned 32-bit integer. Fills in *val and + // returns true if successful. + virtual GBool getU32LE(int pos, Guint *val) = 0; + + // Read a big-endian unsigned <size>-byte integer, where 1 <= size + // <= 4. Fills in *val and returns true if successful. + virtual GBool getUVarBE(int pos, int size, Guint *val) = 0; + + // Compare against a string. Returns true if equal. + virtual GBool cmp(int pos, const char *s) = 0; + +}; + +//------------------------------------------------------------------------ + +class MemReader: public Reader { +public: + + static MemReader *make(char *bufA, int lenA); + virtual ~MemReader(); + virtual int getByte(int pos); + virtual GBool getU16BE(int pos, int *val); + virtual GBool getU32BE(int pos, Guint *val); + virtual GBool getU32LE(int pos, Guint *val); + virtual GBool getUVarBE(int pos, int size, Guint *val); + virtual GBool cmp(int pos, const char *s); + +private: + + MemReader(char *bufA, int lenA); + + char *buf; + int len; +}; + +MemReader *MemReader::make(char *bufA, int lenA) { + return new MemReader(bufA, lenA); +} + +MemReader::MemReader(char *bufA, int lenA) { + buf = bufA; + len = lenA; +} + +MemReader::~MemReader() { +} + +int MemReader::getByte(int pos) { + if (pos < 0 || pos >= len) { + return -1; + } + return buf[pos] & 0xff; +} + +GBool MemReader::getU16BE(int pos, int *val) { + if (pos < 0 || pos > len - 2) { + return gFalse; + } + *val = ((buf[pos] & 0xff) << 8) + + (buf[pos+1] & 0xff); + return gTrue; +} + +GBool MemReader::getU32BE(int pos, Guint *val) { + if (pos < 0 || pos > len - 4) { + return gFalse; + } + *val = ((buf[pos] & 0xff) << 24) + + ((buf[pos+1] & 0xff) << 16) + + ((buf[pos+2] & 0xff) << 8) + + (buf[pos+3] & 0xff); + return gTrue; +} + +GBool MemReader::getU32LE(int pos, Guint *val) { + if (pos < 0 || pos > len - 4) { + return gFalse; + } + *val = (buf[pos] & 0xff) + + ((buf[pos+1] & 0xff) << 8) + + ((buf[pos+2] & 0xff) << 16) + + ((buf[pos+3] & 0xff) << 24); + return gTrue; +} + +GBool MemReader::getUVarBE(int pos, int size, Guint *val) { + int i; + + if (size < 1 || size > 4 || pos < 0 || pos > len - size) { + return gFalse; + } + *val = 0; + for (i = 0; i < size; ++i) { + *val = (*val << 8) + (buf[pos + i] & 0xff); + } + return gTrue; +} + +GBool MemReader::cmp(int pos, const char *s) { + int n; + + n = (int)strlen(s); + if (pos < 0 || len < n || pos > len - n) { + return gFalse; + } + return !memcmp(buf + pos, s, n); +} + +//------------------------------------------------------------------------ + +class FileReader: public Reader { +public: + + static FileReader *make(char *fileName); + virtual ~FileReader(); + virtual int getByte(int pos); + virtual GBool getU16BE(int pos, int *val); + virtual GBool getU32BE(int pos, Guint *val); + virtual GBool getU32LE(int pos, Guint *val); + virtual GBool getUVarBE(int pos, int size, Guint *val); + virtual GBool cmp(int pos, const char *s); + +private: + + FileReader(FILE *fA); + GBool fillBuf(int pos, int len); + + FILE *f; + char buf[1024]; + int bufPos, bufLen; +}; + +FileReader *FileReader::make(char *fileName) { + FILE *fA; + + if (!(fA = fopen(fileName, "rb"))) { + return NULL; + } + return new FileReader(fA); +} + +FileReader::FileReader(FILE *fA) { + f = fA; + bufPos = 0; + bufLen = 0; +} + +FileReader::~FileReader() { + fclose(f); +} + +int FileReader::getByte(int pos) { + if (!fillBuf(pos, 1)) { + return -1; + } + return buf[pos - bufPos] & 0xff; +} + +GBool FileReader::getU16BE(int pos, int *val) { + if (!fillBuf(pos, 2)) { + return gFalse; + } + *val = ((buf[pos - bufPos] & 0xff) << 8) + + (buf[pos - bufPos + 1] & 0xff); + return gTrue; +} + +GBool FileReader::getU32BE(int pos, Guint *val) { + if (!fillBuf(pos, 4)) { + return gFalse; + } + *val = ((buf[pos - bufPos] & 0xff) << 24) + + ((buf[pos - bufPos + 1] & 0xff) << 16) + + ((buf[pos - bufPos + 2] & 0xff) << 8) + + (buf[pos - bufPos + 3] & 0xff); + return gTrue; +} + +GBool FileReader::getU32LE(int pos, Guint *val) { + if (!fillBuf(pos, 4)) { + return gFalse; + } + *val = (buf[pos - bufPos] & 0xff) + + ((buf[pos - bufPos + 1] & 0xff) << 8) + + ((buf[pos - bufPos + 2] & 0xff) << 16) + + ((buf[pos - bufPos + 3] & 0xff) << 24); + return gTrue; +} + +GBool FileReader::getUVarBE(int pos, int size, Guint *val) { + int i; + + if (size < 1 || size > 4 || !fillBuf(pos, size)) { + return gFalse; + } + *val = 0; + for (i = 0; i < size; ++i) { + *val = (*val << 8) + (buf[pos - bufPos + i] & 0xff); + } + return gTrue; +} + +GBool FileReader::cmp(int pos, const char *s) { + int n; + + n = (int)strlen(s); + if (!fillBuf(pos, n)) { + return gFalse; + } + return !memcmp(buf - bufPos + pos, s, n); +} + +GBool FileReader::fillBuf(int pos, int len) { + if (pos < 0 || len < 0 || len > (int)sizeof(buf) || + pos > INT_MAX - (int)sizeof(buf)) { + return gFalse; + } + if (pos >= bufPos && pos + len <= bufPos + bufLen) { + return gTrue; + } + if (fseek(f, pos, SEEK_SET)) { + return gFalse; + } + bufPos = pos; + bufLen = (int)fread(buf, 1, sizeof(buf), f); + if (bufLen < len) { + return gFalse; + } + return gTrue; +} + +//------------------------------------------------------------------------ + +class StreamReader: public Reader { +public: + + static StreamReader *make(int (*getCharA)(void *data), void *dataA); + virtual ~StreamReader(); + virtual int getByte(int pos); + virtual GBool getU16BE(int pos, int *val); + virtual GBool getU32BE(int pos, Guint *val); + virtual GBool getU32LE(int pos, Guint *val); + virtual GBool getUVarBE(int pos, int size, Guint *val); + virtual GBool cmp(int pos, const char *s); + +private: + + StreamReader(int (*getCharA)(void *data), void *dataA); + GBool fillBuf(int pos, int len); + + int (*getChar)(void *data); + void *data; + int streamPos; + char buf[1024]; + int bufPos, bufLen; +}; + +StreamReader *StreamReader::make(int (*getCharA)(void *data), void *dataA) { + return new StreamReader(getCharA, dataA); +} + +StreamReader::StreamReader(int (*getCharA)(void *data), void *dataA) { + getChar = getCharA; + data = dataA; + streamPos = 0; + bufPos = 0; + bufLen = 0; +} + +StreamReader::~StreamReader() { +} + +int StreamReader::getByte(int pos) { + if (!fillBuf(pos, 1)) { + return -1; + } + return buf[pos - bufPos] & 0xff; +} + +GBool StreamReader::getU16BE(int pos, int *val) { + if (!fillBuf(pos, 2)) { + return gFalse; + } + *val = ((buf[pos - bufPos] & 0xff) << 8) + + (buf[pos - bufPos + 1] & 0xff); + return gTrue; +} + +GBool StreamReader::getU32BE(int pos, Guint *val) { + if (!fillBuf(pos, 4)) { + return gFalse; + } + *val = ((buf[pos - bufPos] & 0xff) << 24) + + ((buf[pos - bufPos + 1] & 0xff) << 16) + + ((buf[pos - bufPos + 2] & 0xff) << 8) + + (buf[pos - bufPos + 3] & 0xff); + return gTrue; +} + +GBool StreamReader::getU32LE(int pos, Guint *val) { + if (!fillBuf(pos, 4)) { + return gFalse; + } + *val = (buf[pos - bufPos] & 0xff) + + ((buf[pos - bufPos + 1] & 0xff) << 8) + + ((buf[pos - bufPos + 2] & 0xff) << 16) + + ((buf[pos - bufPos + 3] & 0xff) << 24); + return gTrue; +} + +GBool StreamReader::getUVarBE(int pos, int size, Guint *val) { + int i; + + if (size < 1 || size > 4 || !fillBuf(pos, size)) { + return gFalse; + } + *val = 0; + for (i = 0; i < size; ++i) { + *val = (*val << 8) + (buf[pos - bufPos + i] & 0xff); + } + return gTrue; +} + +GBool StreamReader::cmp(int pos, const char *s) { + int n; + + n = (int)strlen(s); + if (!fillBuf(pos, n)) { + return gFalse; + } + return !memcmp(buf - bufPos + pos, s, n); +} + +GBool StreamReader::fillBuf(int pos, int len) { + int c; + + if (pos < 0 || len < 0 || len > (int)sizeof(buf) || + pos > INT_MAX - (int)sizeof(buf)) { + return gFalse; + } + if (pos < bufPos) { + return gFalse; + } + + // if requested region will not fit in the current buffer... + if (pos + len > bufPos + (int)sizeof(buf)) { + + // if the start of the requested data is already in the buffer, move + // it to the start of the buffer + if (pos < bufPos + bufLen) { + bufLen -= pos - bufPos; + memmove(buf, buf + (pos - bufPos), bufLen); + bufPos = pos; + + // otherwise discard data from the + // stream until we get to the requested position + } else { + bufPos += bufLen; + bufLen = 0; + while (bufPos < pos) { + if ((c = (*getChar)(data)) < 0) { + return gFalse; + } + ++bufPos; + } + } + } + + // read the rest of the requested data + while (bufPos + bufLen < pos + len) { + if ((c = (*getChar)(data)) < 0) { + return gFalse; + } + buf[bufLen++] = (char)c; + } + + return gTrue; +} + +//------------------------------------------------------------------------ + +static FoFiIdentifierType identify(Reader *reader); +static FoFiIdentifierType identifyOpenType(Reader *reader); +static FoFiIdentifierType identifyCFF(Reader *reader, int start); + +FoFiIdentifierType FoFiIdentifier::identifyMem(char *file, int len) { + MemReader *reader; + FoFiIdentifierType type; + + if (!(reader = MemReader::make(file, len))) { + return fofiIdError; + } + type = identify(reader); + delete reader; + return type; +} + +FoFiIdentifierType FoFiIdentifier::identifyFile(char *fileName) { + FileReader *reader; + FoFiIdentifierType type; + int n; + + if (!(reader = FileReader::make(fileName))) { + return fofiIdError; + } + type = identify(reader); + delete reader; + + // Mac OS X dfont files don't have any sort of header or magic number, + // so look at the file name extension + if (type == fofiIdUnknown) { + n = (int)strlen(fileName); + if (n >= 6 && !strcmp(fileName + n - 6, ".dfont")) { + type = fofiIdDfont; + } + } + + return type; +} + +FoFiIdentifierType FoFiIdentifier::identifyStream(int (*getChar)(void *data), + void *data) { + StreamReader *reader; + FoFiIdentifierType type; + + if (!(reader = StreamReader::make(getChar, data))) { + return fofiIdError; + } + type = identify(reader); + delete reader; + return type; +} + +static FoFiIdentifierType identify(Reader *reader) { + Guint n; + + //----- PFA + if (reader->cmp(0, "%!PS-AdobeFont-1") || + reader->cmp(0, "%!FontType1")) { + return fofiIdType1PFA; + } + + //----- PFB + if (reader->getByte(0) == 0x80 && + reader->getByte(1) == 0x01 && + reader->getU32LE(2, &n)) { + if ((n >= 16 && reader->cmp(6, "%!PS-AdobeFont-1")) || + (n >= 11 && reader->cmp(6, "%!FontType1"))) { + return fofiIdType1PFB; + } + } + + //----- TrueType + if ((reader->getByte(0) == 0x00 && + reader->getByte(1) == 0x01 && + reader->getByte(2) == 0x00 && + reader->getByte(3) == 0x00) || + (reader->getByte(0) == 0x74 && // 'true' + reader->getByte(1) == 0x72 && + reader->getByte(2) == 0x75 && + reader->getByte(3) == 0x65)) { + return fofiIdTrueType; + } + if (reader->getByte(0) == 0x74 && // 'ttcf' + reader->getByte(1) == 0x74 && + reader->getByte(2) == 0x63 && + reader->getByte(3) == 0x66) { + return fofiIdTrueTypeCollection; + } + + //----- OpenType + if (reader->getByte(0) == 0x4f && // 'OTTO + reader->getByte(1) == 0x54 && + reader->getByte(2) == 0x54 && + reader->getByte(3) == 0x4f) { + return identifyOpenType(reader); + } + + //----- CFF + if (reader->getByte(0) == 0x01 && + reader->getByte(1) == 0x00) { + return identifyCFF(reader, 0); + } + // some tools embed CFF fonts with an extra whitespace char at the + // beginning + if (reader->getByte(1) == 0x01 && + reader->getByte(2) == 0x00) { + return identifyCFF(reader, 1); + } + + return fofiIdUnknown; +} + +static FoFiIdentifierType identifyOpenType(Reader *reader) { + FoFiIdentifierType type; + Guint offset; + int nTables, i; + + if (!reader->getU16BE(4, &nTables)) { + return fofiIdUnknown; + } + for (i = 0; i < nTables; ++i) { + if (reader->cmp(12 + i*16, "CFF ")) { + if (reader->getU32BE(12 + i*16 + 8, &offset) && + offset < (Guint)INT_MAX) { + type = identifyCFF(reader, (int)offset); + if (type == fofiIdCFF8Bit) { + type = fofiIdOpenTypeCFF8Bit; + } else if (type == fofiIdCFFCID) { + type = fofiIdOpenTypeCFFCID; + } + return type; + } + return fofiIdUnknown; + } + } + return fofiIdUnknown; +} + +static FoFiIdentifierType identifyCFF(Reader *reader, int start) { + Guint offset0, offset1; + int hdrSize, offSize0, offSize1, pos, endPos, b0, n; + + //----- read the header + if (reader->getByte(start) != 0x01 || + reader->getByte(start + 1) != 0x00) { + return fofiIdUnknown; + } + if ((hdrSize = reader->getByte(start + 2)) < 0) { + return fofiIdUnknown; + } + if ((offSize0 = reader->getByte(start + 3)) < 1 || offSize0 > 4) { + return fofiIdUnknown; + } + pos = start + hdrSize; + if (pos < 0) { + return fofiIdUnknown; + } + + //----- skip the name index + if (!reader->getU16BE(pos, &n)) { + return fofiIdUnknown; + } + if (n == 0) { + pos += 2; + } else { + if ((offSize1 = reader->getByte(pos + 2)) < 1 || offSize1 > 4) { + return fofiIdUnknown; + } + if (!reader->getUVarBE(pos + 3 + n * offSize1, offSize1, &offset1) || + offset1 > (Guint)INT_MAX) { + return fofiIdUnknown; + } + pos += 3 + (n + 1) * offSize1 + (int)offset1 - 1; + } + if (pos < 0) { + return fofiIdUnknown; + } + + //----- parse the top dict index + if (!reader->getU16BE(pos, &n) || n < 1) { + return fofiIdUnknown; + } + if ((offSize1 = reader->getByte(pos + 2)) < 1 || offSize1 > 4) { + return fofiIdUnknown; + } + if (!reader->getUVarBE(pos + 3, offSize1, &offset0) || + offset0 > (Guint)INT_MAX || + !reader->getUVarBE(pos + 3 + offSize1, offSize1, &offset1) || + offset1 > (Guint)INT_MAX || + offset0 > offset1) { + return fofiIdUnknown; + } + pos = pos + 3 + (n + 1) * offSize1 + (int)offset0 - 1; + endPos = pos + 3 + (n + 1) * offSize1 + (int)offset1 - 1; + if (pos < 0 || endPos < 0 || pos > endPos) { + return fofiIdUnknown; + } + + //----- parse the top dict, look for ROS as first entry + // for a CID font, the top dict starts with: + // <int> <int> <int> ROS + while (pos >= 0 && pos < endPos) { + b0 = reader->getByte(pos); + if (b0 == 0x1c) { + pos += 3; + } else if (b0 == 0x1d) { + pos += 5; + } else if (b0 >= 0xf7 && b0 <= 0xfe) { + pos += 2; + } else if (b0 >= 0x20 && b0 <= 0xf6) { + pos += 1; + } else { + break; + } + } + if (pos + 1 < endPos && + reader->getByte(pos) == 12 && + reader->getByte(pos + 1) == 30) { + return fofiIdCFFCID; + } else { + return fofiIdCFF8Bit; + } +} + +//------------------------------------------------------------------------ + +static GList *getTTCFontList(FILE *f); +static GList *getDfontFontList(FILE *f); + +GList *FoFiIdentifier::getFontList(char *fileName) { + FILE *f; + char buf[4]; + GList *ret; + + if (!(f = fopen(fileName, "rb"))) { + return NULL; + } + if (fread(buf, 1, 4, f) == 4 && + buf[0] == 0x74 && // 'ttcf' + buf[1] == 0x74 && + buf[2] == 0x63 && + buf[3] == 0x66) { + ret = getTTCFontList(f); + } else { + ret = getDfontFontList(f); + } + fclose(f); + return ret; +} + +static GList *getTTCFontList(FILE *f) { + Guchar buf[12]; + Guchar *buf2; + int fileLength, nFonts; + int tabDirOffset, nTables, nameTabOffset, nNames, stringsOffset; + int stringPlatform, stringLength, stringOffset; + GBool stringUnicode; + int i, j; + GList *ret; + + fseek(f, 0, SEEK_END); + fileLength = (int)ftell(f); + if (fileLength < 0) { + goto err1; + } + fseek(f, 8, SEEK_SET); + if (fread(buf, 1, 4, f) != 4) { + goto err1; + } + nFonts = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + if (nFonts < 0 || + 12 + 4 * nFonts > fileLength) { + goto err1; + } + ret = new GList(); + for (i = 0; i < nFonts; ++i) { + fseek(f, 12 + 4 * i, SEEK_SET); + if (fread(buf, 1, 4, f) != 4) { + goto err2; + } + tabDirOffset = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + if (tabDirOffset < 0 || + tabDirOffset + 12 < 0 || + tabDirOffset + 12 > fileLength) { + goto err2; + } + fseek(f, tabDirOffset, SEEK_SET); + if (fread(buf, 1, 12, f) != 12) { + goto err2; + } + nTables = (buf[4] << 8) | buf[5]; + if (tabDirOffset + 12 + 16 * nTables < 0 || + tabDirOffset + 12 + 16 * nTables > fileLength) { + goto err2; + } + buf2 = (Guchar *)gmallocn(nTables, 16); + if ((int)fread(buf2, 1, 16 * nTables, f) != 16 * nTables) { + goto err3; + } + nameTabOffset = 0; // make gcc happy + for (j = 0; j < nTables; ++j) { + if (buf2[16*j + 0] == 'n' && + buf2[16*j + 1] == 'a' && + buf2[16*j + 2] == 'm' && + buf2[16*j + 3] == 'e') { + nameTabOffset = (buf2[16*j + 8] << 24) | (buf2[16*j + 9] << 16) | + (buf2[16*j + 10] << 8) | buf2[16*j + 11]; + break; + } + } + gfree(buf2); + if (j >= nTables) { + goto err2; + } + if (nameTabOffset < 0 || + nameTabOffset + 6 < 0 || + nameTabOffset + 6 > fileLength) { + goto err2; + } + fseek(f, nameTabOffset, SEEK_SET); + if (fread(buf, 1, 6, f) != 6) { + goto err2; + } + nNames = (buf[2] << 8) | buf[3]; + stringsOffset = (buf[4] << 8) | buf[5]; + if (nameTabOffset + 6 + 12 * nNames < 0 || + nameTabOffset + 6 + 12 * nNames > fileLength || + nameTabOffset + stringsOffset < 0) { + goto err2; + } + buf2 = (Guchar *)gmallocn(nNames, 12); + if ((int)fread(buf2, 1, 12 * nNames, f) != 12 * nNames) { + goto err3; + } + for (j = 0; j < nNames; ++j) { + if (buf2[12*j + 6] == 0 && // 0x0004 = full name + buf2[12*j + 7] == 4) { + break; + } + } + if (j >= nNames) { + goto err3; + } + stringPlatform = (buf2[12*j] << 8) | buf2[12*j + 1]; + // stringEncoding = (buf2[12*j + 2] << 8) | buf2[12*j + 3]; + stringUnicode = stringPlatform == 0 || stringPlatform == 3; + stringLength = (buf2[12*j + 8] << 8) | buf2[12*j + 9]; + stringOffset = nameTabOffset + stringsOffset + + ((buf2[12*j + 10] << 8) | buf2[12*j + 11]); + gfree(buf2); + if (stringOffset < 0 || + stringOffset + stringLength < 0 || + stringOffset + stringLength > fileLength) { + goto err2; + } + buf2 = (Guchar *)gmalloc(stringLength); + fseek(f, stringOffset, SEEK_SET); + if ((int)fread(buf2, 1, stringLength, f) != stringLength) { + goto err3; + } + if (stringUnicode) { + stringLength /= 2; + for (j = 0; j < stringLength; ++j) { + buf2[j] = buf2[2*j + 1]; + } + } + ret->append(new GString((char *)buf2, stringLength)); + gfree(buf2); + } + return ret; + + err3: + gfree(buf2); + err2: + deleteGList(ret, GString); + err1: + return NULL; +} + +static GList *getDfontFontList(FILE *f) { + Guchar buf[16]; + Guchar *resMap; + int fileLength, resMapOffset, resMapLength; + int resTypeListOffset, resNameListOffset, nTypes; + int refListOffset, nFonts, nameOffset, nameLen; + int offset, i; + GList *ret; + + fseek(f, 0, SEEK_END); + fileLength = (int)ftell(f); + if (fileLength < 0) { + goto err1; + } + fseek(f, 0, SEEK_SET); + if (fread((char *)buf, 1, 16, f) != 16) { + goto err1; + } + resMapOffset = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]; + resMapLength = (buf[12] << 24) | (buf[13] << 16) | (buf[14] << 8) | buf[15]; + if (resMapOffset < 0 || + resMapOffset >= fileLength || + resMapLength < 0 || + resMapOffset + resMapLength > fileLength || + resMapOffset + resMapLength < 0) { + goto err1; + } + if (resMapLength > 32768) { + // sanity check - this probably isn't a dfont file + goto err1; + } + resMap = (Guchar *)gmalloc(resMapLength); + fseek(f, resMapOffset, SEEK_SET); + if ((int)fread((char *)resMap, 1, resMapLength, f) != resMapLength) { + goto err2; + } + resTypeListOffset = (resMap[24] << 8) | resMap[25]; + resNameListOffset = (resMap[26] << 8) | resMap[27]; + nTypes = ((resMap[28] << 8) | resMap[29]) + 1; + if (resTypeListOffset + 2 + nTypes * 8 > resMapLength || + resNameListOffset >= resMapLength) { + goto err2; + } + for (i = 0; i < nTypes; ++i) { + offset = resTypeListOffset + 2 + 8 * i; + if (resMap[offset] == 0x73 && // 'sfnt' + resMap[offset+1] == 0x66 && + resMap[offset+2] == 0x6e && + resMap[offset+3] == 0x74) { + nFonts = ((resMap[offset+4] << 8) | resMap[offset+5]) + 1; + refListOffset = (resMap[offset+6] << 8) | resMap[offset+7]; + break; + } + } + if (i >= nTypes) { + goto err2; + } + if (resTypeListOffset + refListOffset >= resMapLength || + resTypeListOffset + refListOffset + nFonts * 12 > resMapLength) { + goto err2; + } + ret = new GList(); + for (i = 0; i < nFonts; ++i) { + offset = resTypeListOffset + refListOffset + 12 * i; + nameOffset = (resMap[offset+2] << 8) | resMap[offset+3]; + offset = resNameListOffset + nameOffset; + if (offset >= resMapLength) { + goto err3; + } + nameLen = resMap[offset]; + if (offset + 1 + nameLen > resMapLength) { + goto err3; + } + ret->append(new GString((char *)resMap + offset + 1, nameLen)); + } + gfree(resMap); + return ret; + + err3: + deleteGList(ret, GString); + err2: + gfree(resMap); + err1: + return NULL; +} diff --git a/fofi/FoFiIdentifier.h b/fofi/FoFiIdentifier.h new file mode 100644 index 0000000..b0307a0 --- /dev/null +++ b/fofi/FoFiIdentifier.h @@ -0,0 +1,55 @@ +//======================================================================== +// +// FoFiIdentifier.h +// +// Copyright 2009 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FOFIIDENTIFIER_H +#define FOFIIDENTIFIER_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +class GList; + +//------------------------------------------------------------------------ +// FoFiIdentifier +//------------------------------------------------------------------------ + +enum FoFiIdentifierType { + fofiIdType1PFA, // Type 1 font in PFA format + fofiIdType1PFB, // Type 1 font in PFB format + fofiIdCFF8Bit, // 8-bit CFF font + fofiIdCFFCID, // CID CFF font + fofiIdTrueType, // TrueType font + fofiIdTrueTypeCollection, // TrueType collection + fofiIdOpenTypeCFF8Bit, // OpenType wrapper with 8-bit CFF font + fofiIdOpenTypeCFFCID, // OpenType wrapper with CID CFF font + fofiIdDfont, // Mac OS X dfont + fofiIdUnknown, // unknown type + fofiIdError // error in reading the file +}; + +class FoFiIdentifier { +public: + + // Identify a font file. + static FoFiIdentifierType identifyMem(char *file, int len); + static FoFiIdentifierType identifyFile(char *fileName); + static FoFiIdentifierType identifyStream(int (*getChar)(void *data), + void *data); + + // Return a list of font names (GString *) in a font collection + // file. Indexes into the returned list are indexes into the + // collection. This function is only useful with TrueType + // collections and Mac dfont files. Returns NULL on error + // (including invalid font type). + static GList *getFontList(char *fileName); +}; + +#endif diff --git a/fofi/FoFiTrueType.cc b/fofi/FoFiTrueType.cc new file mode 100644 index 0000000..57b12b1 --- /dev/null +++ b/fofi/FoFiTrueType.cc @@ -0,0 +1,2461 @@ +//======================================================================== +// +// FoFiTrueType.cc +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdlib.h> +#include <string.h> +#if HAVE_STD_SORT +#include <algorithm> +#endif +#include "gtypes.h" +#include "gmem.h" +#include "gmempp.h" +#include "GString.h" +#include "GHash.h" +#include "FoFiType1C.h" +#include "FoFiTrueType.h" + +// +// Terminology +// ----------- +// +// character code = number used as an element of a text string +// +// character name = glyph name = name for a particular glyph within a +// font +// +// glyph index = GID = position (within some internal table in the font) +// where the instructions to draw a particular glyph are +// stored +// +// Type 1 fonts +// ------------ +// +// Type 1 fonts contain: +// +// Encoding: array of glyph names, maps char codes to glyph names +// +// Encoding[charCode] = charName +// +// CharStrings: dictionary of instructions, keyed by character names, +// maps character name to glyph data +// +// CharStrings[charName] = glyphData +// +// TrueType fonts +// -------------- +// +// TrueType fonts contain: +// +// 'cmap' table: mapping from character code to glyph index; there may +// be multiple cmaps in a TrueType font +// +// cmap[charCode] = gid +// +// 'post' table: mapping from glyph index to glyph name +// +// post[gid] = glyphName +// +// Type 42 fonts +// ------------- +// +// Type 42 fonts contain: +// +// Encoding: array of glyph names, maps char codes to glyph names +// +// Encoding[charCode] = charName +// +// CharStrings: dictionary of glyph indexes, keyed by character names, +// maps character name to glyph index +// +// CharStrings[charName] = gid +// + +//------------------------------------------------------------------------ + +#define ttcfTag 0x74746366 + +//------------------------------------------------------------------------ + +struct TrueTypeTable { + Guint tag; + Guint checksum; + int offset; + int origOffset; + int len; +}; + +struct TrueTypeCmap { + int platform; + int encoding; + int offset; + int len; + int fmt; +}; + +struct TrueTypeLoca { + int idx; + int origOffset; + int newOffset; + int len; +}; + +#define cmapTag 0x636d6170 +#define glyfTag 0x676c7966 +#define headTag 0x68656164 +#define hheaTag 0x68686561 +#define hmtxTag 0x686d7478 +#define locaTag 0x6c6f6361 +#define nameTag 0x6e616d65 +#define os2Tag 0x4f532f32 +#define postTag 0x706f7374 + +#if HAVE_STD_SORT + +struct cmpTrueTypeLocaOffsetFunctor { + bool operator()(const TrueTypeLoca &loca1, const TrueTypeLoca &loca2) { + if (loca1.origOffset == loca2.origOffset) { + return loca1.idx < loca2.idx; + } + return loca1.origOffset < loca2.origOffset; + } +}; + +struct cmpTrueTypeLocaIdxFunctor { + bool operator()(const TrueTypeLoca &loca1, const TrueTypeLoca &loca2) { + return loca1.idx < loca2.idx; + } +}; + +struct cmpTrueTypeTableTagFunctor { + bool operator()(const TrueTypeTable &tab1, const TrueTypeTable &tab2) { + return tab1.tag < tab2.tag; + } +}; + +#else // HAVE_STD_SORT + +static int cmpTrueTypeLocaOffset(const void *p1, const void *p2) { + TrueTypeLoca *loca1 = (TrueTypeLoca *)p1; + TrueTypeLoca *loca2 = (TrueTypeLoca *)p2; + + if (loca1->origOffset == loca2->origOffset) { + return loca1->idx - loca2->idx; + } + return loca1->origOffset - loca2->origOffset; +} + +static int cmpTrueTypeLocaIdx(const void *p1, const void *p2) { + TrueTypeLoca *loca1 = (TrueTypeLoca *)p1; + TrueTypeLoca *loca2 = (TrueTypeLoca *)p2; + + return loca1->idx - loca2->idx; +} + +static int cmpTrueTypeTableTag(const void *p1, const void *p2) { + TrueTypeTable *tab1 = (TrueTypeTable *)p1; + TrueTypeTable *tab2 = (TrueTypeTable *)p2; + + return (int)tab1->tag - (int)tab2->tag; +} + +#endif // HAVE_STD_SORT + +//------------------------------------------------------------------------ + +struct T42Table { + const char *tag; // 4-byte tag + GBool required; // required by the TrueType spec? +}; + +// TrueType tables to be embedded in Type 42 fonts. +// NB: the table names must be in alphabetical order here. +#define nT42Tables 11 +static T42Table t42Tables[nT42Tables] = { + { "cvt ", gTrue }, + { "fpgm", gTrue }, + { "glyf", gTrue }, + { "head", gTrue }, + { "hhea", gTrue }, + { "hmtx", gTrue }, + { "loca", gTrue }, + { "maxp", gTrue }, + { "prep", gTrue }, + { "vhea", gFalse }, + { "vmtx", gFalse } +}; +#define t42HeadTable 3 +#define t42LocaTable 6 +#define t42GlyfTable 2 +#define t42VheaTable 9 +#define t42VmtxTable 10 + +//------------------------------------------------------------------------ + +// Glyph names in some arbitrary standard order that Apple uses for +// their TrueType fonts. +static const char *macGlyphNames[258] = { + ".notdef", "null", "CR", "space", + "exclam", "quotedbl", "numbersign", "dollar", + "percent", "ampersand", "quotesingle", "parenleft", + "parenright", "asterisk", "plus", "comma", + "hyphen", "period", "slash", "zero", + "one", "two", "three", "four", + "five", "six", "seven", "eight", + "nine", "colon", "semicolon", "less", + "equal", "greater", "question", "at", + "A", "B", "C", "D", + "E", "F", "G", "H", + "I", "J", "K", "L", + "M", "N", "O", "P", + "Q", "R", "S", "T", + "U", "V", "W", "X", + "Y", "Z", "bracketleft", "backslash", + "bracketright", "asciicircum", "underscore", "grave", + "a", "b", "c", "d", + "e", "f", "g", "h", + "i", "j", "k", "l", + "m", "n", "o", "p", + "q", "r", "s", "t", + "u", "v", "w", "x", + "y", "z", "braceleft", "bar", + "braceright", "asciitilde", "Adieresis", "Aring", + "Ccedilla", "Eacute", "Ntilde", "Odieresis", + "Udieresis", "aacute", "agrave", "acircumflex", + "adieresis", "atilde", "aring", "ccedilla", + "eacute", "egrave", "ecircumflex", "edieresis", + "iacute", "igrave", "icircumflex", "idieresis", + "ntilde", "oacute", "ograve", "ocircumflex", + "odieresis", "otilde", "uacute", "ugrave", + "ucircumflex", "udieresis", "dagger", "degree", + "cent", "sterling", "section", "bullet", + "paragraph", "germandbls", "registered", "copyright", + "trademark", "acute", "dieresis", "notequal", + "AE", "Oslash", "infinity", "plusminus", + "lessequal", "greaterequal", "yen", "mu1", + "partialdiff", "summation", "product", "pi", + "integral", "ordfeminine", "ordmasculine", "Ohm", + "ae", "oslash", "questiondown", "exclamdown", + "logicalnot", "radical", "florin", "approxequal", + "increment", "guillemotleft", "guillemotright", "ellipsis", + "nbspace", "Agrave", "Atilde", "Otilde", + "OE", "oe", "endash", "emdash", + "quotedblleft", "quotedblright", "quoteleft", "quoteright", + "divide", "lozenge", "ydieresis", "Ydieresis", + "fraction", "currency", "guilsinglleft", "guilsinglright", + "fi", "fl", "daggerdbl", "periodcentered", + "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", + "Ecircumflex", "Aacute", "Edieresis", "Egrave", + "Iacute", "Icircumflex", "Idieresis", "Igrave", + "Oacute", "Ocircumflex", "applelogo", "Ograve", + "Uacute", "Ucircumflex", "Ugrave", "dotlessi", + "circumflex", "tilde", "overscore", "breve", + "dotaccent", "ring", "cedilla", "hungarumlaut", + "ogonek", "caron", "Lslash", "lslash", + "Scaron", "scaron", "Zcaron", "zcaron", + "brokenbar", "Eth", "eth", "Yacute", + "yacute", "Thorn", "thorn", "minus", + "multiply", "onesuperior", "twosuperior", "threesuperior", + "onehalf", "onequarter", "threequarters", "franc", + "Gbreve", "gbreve", "Idot", "Scedilla", + "scedilla", "Cacute", "cacute", "Ccaron", + "ccaron", "dmacron" +}; + +//------------------------------------------------------------------------ +// FoFiTrueType +//------------------------------------------------------------------------ + +FoFiTrueType *FoFiTrueType::make(char *fileA, int lenA, int fontNum, + GBool allowHeadlessCFF) { + FoFiTrueType *ff; + + ff = new FoFiTrueType(fileA, lenA, gFalse, fontNum, gFalse, allowHeadlessCFF); + if (!ff->parsedOk) { + delete ff; + return NULL; + } + return ff; +} + +FoFiTrueType *FoFiTrueType::load(char *fileName, int fontNum, + GBool allowHeadlessCFF) { + FoFiTrueType *ff; + char *fileA; + int lenA, n; + GBool isDfontA; + + if (!(fileA = FoFiBase::readFile(fileName, &lenA))) { + return NULL; + } + n = (int)strlen(fileName); + isDfontA = n >= 6 && !strcmp(fileName + n - 6, ".dfont"); + ff = new FoFiTrueType(fileA, lenA, gTrue, fontNum, isDfontA, + allowHeadlessCFF); + if (!ff->parsedOk) { + delete ff; + return NULL; + } + return ff; +} + +FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, + int fontNum, GBool isDfontA, + GBool allowHeadlessCFF): + FoFiBase(fileA, lenA, freeFileDataA) +{ + tables = NULL; + nTables = 0; + cmaps = NULL; + nCmaps = 0; + nameToGID = NULL; + isDfont = isDfontA; + isTTC = gFalse; + parsedOk = gFalse; + + parse(fontNum, allowHeadlessCFF); +} + +FoFiTrueType::~FoFiTrueType() { + gfree(tables); + gfree(cmaps); + if (nameToGID) { + delete nameToGID; + } +} + +int FoFiTrueType::getNumCmaps() { + return nCmaps; +} + +int FoFiTrueType::getCmapPlatform(int i) { + return cmaps[i].platform; +} + +int FoFiTrueType::getCmapEncoding(int i) { + return cmaps[i].encoding; +} + +int FoFiTrueType::findCmap(int platform, int encoding) { + int i; + + for (i = 0; i < nCmaps; ++i) { + if (cmaps[i].platform == platform && cmaps[i].encoding == encoding) { + return i; + } + } + return -1; +} + +int FoFiTrueType::mapCodeToGID(int i, int c) { + int gid; + int segCnt, segEnd, segStart, segDelta, segOffset; + int cmapFirst, cmapLen; + int pos, a, b, m; + GBool ok; + + if (i < 0 || i >= nCmaps) { + return 0; + } + ok = gTrue; + pos = cmaps[i].offset; + switch (cmaps[i].fmt) { + case 0: + if (c < 0 || c >= cmaps[i].len - 6) { + return 0; + } + gid = getU8(pos + 6 + c, &ok); + break; + case 2: + // this only handles single-byte codes + if (c < 0 || c > 0xff) { + return 0; + } + // check that: subHeaderKeys[0] = 0 + // subHeaders[0].firstCode = 0 + // subHeaders[0].entryCount = 256 + // subHeaders[0].idDelta = 0 + if (getU16BE(pos + 6, &ok) != 0 || + getU16BE(pos + 518 + 0, &ok) != 0 || + getU16BE(pos + 518 + 2, &ok) != 256 || + getU16BE(pos + 518 + 4, &ok) != 0) { + return 0; + } + // subHeaders[0].idRangeOffset is a byte offset from itself + pos = pos + 518 + 6 + getU16BE(pos + 518 + 6, &ok); + gid = getU16BE(pos + 2 * c, &ok); + break; + case 4: + segCnt = getU16BE(pos + 6, &ok) / 2; + a = -1; + b = segCnt - 1; + segEnd = getU16BE(pos + 14 + 2*b, &ok); + if (c > segEnd) { + // malformed font -- the TrueType spec requires the last segEnd + // to be 0xffff + return 0; + } + // invariant: seg[a].end < code <= seg[b].end + while (b - a > 1 && ok) { + m = (a + b) / 2; + segEnd = getU16BE(pos + 14 + 2*m, &ok); + if (segEnd < c) { + a = m; + } else { + b = m; + } + } + segStart = getU16BE(pos + 16 + 2*segCnt + 2*b, &ok); + segDelta = getU16BE(pos + 16 + 4*segCnt + 2*b, &ok); + segOffset = getU16BE(pos + 16 + 6*segCnt + 2*b, &ok); + if (c < segStart) { + return 0; + } + if (segOffset == 0) { + gid = (c + segDelta) & 0xffff; + } else { + gid = getU16BE(pos + 16 + 6*segCnt + 2*b + + segOffset + 2 * (c - segStart), &ok); + if (gid != 0) { + gid = (gid + segDelta) & 0xffff; + } + } + break; + case 6: + cmapFirst = getU16BE(pos + 6, &ok); + cmapLen = getU16BE(pos + 8, &ok); + if (c < cmapFirst || c >= cmapFirst + cmapLen) { + return 0; + } + gid = getU16BE(pos + 10 + 2 * (c - cmapFirst), &ok); + break; + default: + return 0; + } + if (!ok) { + return 0; + } + return gid; +} + +int FoFiTrueType::mapNameToGID(char *name) { + if (!nameToGID) { + return 0; + } + return nameToGID->lookupInt(name); +} + +GBool FoFiTrueType::getCFFBlock(char **start, int *length) { + int i; + + if (!openTypeCFF) { + return gFalse; + } + i = seekTable("CFF "); + if (!checkRegion(tables[i].offset, tables[i].len)) { + return gFalse; + } + *start = (char *)file + tables[i].offset; + *length = tables[i].len; + return gTrue; +} + +int *FoFiTrueType::getCIDToGIDMap(int *nCIDs) { + char *start; + int length; + FoFiType1C *ff; + int *map; + + *nCIDs = 0; + if (!getCFFBlock(&start, &length)) { + return NULL; + } + if (!(ff = FoFiType1C::make(start, length))) { + return NULL; + } + map = ff->getCIDToGIDMap(nCIDs); + delete ff; + return map; +} + +int FoFiTrueType::getEmbeddingRights() { + int i, fsType; + GBool ok; + + if ((i = seekTable("OS/2")) < 0) { + return 4; + } + ok = gTrue; + fsType = getU16BE(tables[i].offset + 8, &ok); + if (!ok) { + return 4; + } + if (fsType & 0x0008) { + return 2; + } + if (fsType & 0x0004) { + return 1; + } + if (fsType & 0x0002) { + return 0; + } + return 3; +} + +void FoFiTrueType::getFontMatrix(double *mat) { + char *start; + int length; + FoFiType1C *ff; + + if (!getCFFBlock(&start, &length)) { + return; + } + if (!(ff = FoFiType1C::make(start, length))) { + return; + } + ff->getFontMatrix(mat); + delete ff; +} + +struct FoFiTrueTypeTrickyFont { + int cvtLen; + Guint cvtChecksum; + int fpgmLen; + Guint fpgmChecksum; + int prepLen; + Guint prepChecksum; +}; + +// This data was taken from the FreeType project. +static FoFiTrueTypeTrickyFont trickyFonts[] = { + { 0x000002e4, 0x05bcf058, // MingLiU 1995 + 0x000087c4, 0x28233bf1, + 0x000001e1, 0xa344a1ea }, + { 0x000002e4, 0x05bcf058, // MingLiU 1996- + 0x000087c4, 0x28233bf1, + 0x000001e1, 0xa344a1eb }, + { 0x00000350, 0x12c3ebb2, // DFGothic-EB + 0x000087a7, 0xb680ee64, + 0x00000758, 0xce939563 }, + { 0x00000350, 0x11e5ead4, // DFGyoSho-Lt + 0x0000bc85, 0xce5956e9, + 0x00000045, 0x8272f416 }, + { 0x00000350, 0x1262eb4e, // DFHSGothic-W5 + 0x00007940, 0xe86a5d64, + 0x000005ff, 0x7850f729 }, + { 0x00000350, 0x122deb0a, // DFHSMincho-W3 + 0x0000859b, 0x3d16328a, + 0x000002cb, 0xa93fc33b }, + { 0x00000350, 0x125feb26, // DFHSMincho-W7 + 0x00007ee1, 0xa5acc982, + 0x0000041f, 0x90999196 }, + { 0x00000350, 0x11e5ead4, // DFKaiShu + 0x00009063, 0x5a30ca3b, + 0x0000007e, 0x13a42602 }, + { 0x00000350, 0x11e5ead4, // DFKaiShu2 + 0x00008998, 0xa6e78c01, + 0x0000007e, 0x13a42602 }, + { 0x00000008, 0xfffbfffc, // HuaTianKaiTi + 0x0000bea2, 0x9c9e48b8, + 0x00000008, 0x70020112 }, + { 0x00000008, 0xfffbfffc, // HuaTianSongTi + 0x00017c39, 0x0a5a0483, + 0x00000008, 0x70020112 }, + { 0x00000000, 0x00000000, // NEC fadpop7.ttf + 0x000000e5, 0x40c92555, + 0x0000117c, 0xa39b58e3 }, + { 0x00000000, 0x00000000, // NEC fadrei5.ttf + 0x000000e5, 0x33c41652, + 0x00000f6a, 0x26d6c52a }, + { 0x00000000, 0x00000000, // NEC fangot7.ttf + 0x0000019d, 0x6db1651d, + 0x00002492, 0x6c6e4b03 }, + { 0x00000000, 0x00000000, // NEC fangyo5.ttf + 0x000000e5, 0x40c92555, + 0x0000117c, 0xde51fad0 }, + { 0x00000000, 0x00000000, // NEC fankyo5.ttf + 0x000000e5, 0x85e47664, + 0x00001caa, 0xa6c62831 }, + { 0x00000000, 0x00000000, // NEC fanrgo5.ttf + 0x0000019d, 0x2d891cfd, + 0x00001de8, 0xa0604633 }, + { 0x00000000, 0x00000000, // NEC fangot5.ttc + 0x000001cb, 0x40aa774c, + 0x00001f9a, 0x9b5caa96 }, + { 0x00000000, 0x00000000, // NEC fanmin3.ttc + 0x00000141, 0x0d3de9cb, + 0x00002280, 0xd4127766 }, + { 0x00000000, 0x00000000, // NEC FA-Gothic, 1996 + 0x000001f0, 0x4a692698, + 0x00001fca, 0x340d4346 }, + { 0x00000000, 0x00000000, // NEC FA-Minchou, 1996 + 0x00000166, 0xcd34c604, + 0x000022b0, 0x6cf31046 }, + { 0x00000000, 0x00000000, // NEC FA-RoundGothicB, 1996 + 0x0000019d, 0x5da75315, + 0x000022e0, 0x40745a5f }, + { 0x00000000, 0x00000000, // NEC FA-RoundGothicM, 1996 + 0x000001c2, 0xf055fc48, + 0x00001e18, 0x3900ded3 }, + { 0x00000060, 0x00170003, // MINGLI, 1992 + 0x000058aa, 0xdbb4306e, + 0x00000035, 0xd643482a } +}; + +#define nTrickyFonts ((int)(sizeof(trickyFonts) / sizeof(FoFiTrueTypeTrickyFont))) + +// This looks at the length and checksum values for the cvt, fpgm, and +// prep tables. The theory is that those tables will be the same, +// even if the font is renamed and/or subsetted. +GBool FoFiTrueType::checkForTrickyCJK() { + int cvtIdx, fpgmIdx, prepIdx; + int cvtLen, fpgmLen, prepLen; + Guint cvtChecksum, fpgmChecksum, prepChecksum; + int i; + + if ((cvtIdx = seekTable("cvt ")) >= 0) { + cvtLen = tables[cvtIdx].len; + cvtChecksum = tables[cvtIdx].checksum; + } else { + cvtLen = 0; + cvtChecksum = 0; + } + if ((fpgmIdx = seekTable("fpgm")) >= 0) { + fpgmLen = tables[fpgmIdx].len; + fpgmChecksum = tables[fpgmIdx].checksum; + } else { + fpgmLen = 0; + fpgmChecksum = 0; + } + if ((prepIdx = seekTable("prep")) >= 0) { + prepLen = tables[prepIdx].len; + prepChecksum = tables[prepIdx].checksum; + } else { + prepLen = 0; + prepChecksum = 0; + } + + for (i = 0; i < nTrickyFonts; ++i) { + if (cvtLen == trickyFonts[i].cvtLen && + cvtChecksum == trickyFonts[i].cvtChecksum && + fpgmLen == trickyFonts[i].fpgmLen && + fpgmChecksum == trickyFonts[i].fpgmChecksum && + prepLen == trickyFonts[i].prepLen && + prepChecksum == trickyFonts[i].prepChecksum) { + return gTrue; + } + } + return gFalse; +} + +void FoFiTrueType::convertToType42(char *psName, char **encoding, + int *codeToGID, + FoFiOutputFunc outputFunc, + void *outputStream) { + GString *buf; + int maxUsedGlyph; + GBool ok; + + if (openTypeCFF) { + return; + } + + // write the header + ok = gTrue; + buf = GString::format("%!PS-TrueTypeFont-{0:2g}\n", + (double)getS32BE(0, &ok) / 65536.0); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + + // begin the font dictionary + (*outputFunc)(outputStream, "10 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, (int)strlen(psName)); + (*outputFunc)(outputStream, " def\n", 5); + (*outputFunc)(outputStream, "/FontType 42 def\n", 17); + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + buf = GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n", + bbox[0], bbox[1], bbox[2], bbox[3]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); + + // write the guts of the dictionary + cvtEncoding(encoding, outputFunc, outputStream); + cvtCharStrings(encoding, codeToGID, outputFunc, outputStream); + cvtSfnts(outputFunc, outputStream, NULL, gFalse, &maxUsedGlyph); + + // end the dictionary and define the font + (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); +} + +void FoFiTrueType::convertToType1(char *psName, const char **newEncoding, + GBool ascii, FoFiOutputFunc outputFunc, + void *outputStream) { + char *start; + int length; + FoFiType1C *ff; + + if (!getCFFBlock(&start, &length)) { + return; + } + if (!(ff = FoFiType1C::make(start, length))) { + return; + } + ff->convertToType1(psName, newEncoding, ascii, outputFunc, outputStream); + delete ff; +} + +void FoFiTrueType::convertToCIDType2(char *psName, + int *cidMap, int nCIDs, + GBool needVerticalMetrics, + FoFiOutputFunc outputFunc, + void *outputStream) { + GString *buf; + int cid, maxUsedGlyph; + GBool ok; + int i, j, k; + + if (openTypeCFF) { + return; + } + + // write the header + ok = gTrue; + buf = GString::format("%!PS-TrueTypeFont-{0:2g}\n", + (double)getS32BE(0, &ok) / 65536.0); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + + // begin the font dictionary + (*outputFunc)(outputStream, "20 dict begin\n", 14); + (*outputFunc)(outputStream, "/CIDFontName /", 14); + (*outputFunc)(outputStream, psName, (int)strlen(psName)); + (*outputFunc)(outputStream, " def\n", 5); + (*outputFunc)(outputStream, "/CIDFontType 2 def\n", 19); + (*outputFunc)(outputStream, "/FontType 42 def\n", 17); + (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32); + (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24); + (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27); + (*outputFunc)(outputStream, " /Supplement 0 def\n", 20); + (*outputFunc)(outputStream, " end def\n", 10); + (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15); + if (cidMap) { + buf = GString::format("/CIDCount {0:d} def\n", nCIDs); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + if (nCIDs > 32767) { + (*outputFunc)(outputStream, "/CIDMap [", 9); + for (i = 0; i < nCIDs; i += 32768 - 16) { + (*outputFunc)(outputStream, "<\n", 2); + for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) { + (*outputFunc)(outputStream, " ", 2); + for (k = 0; k < 16 && i+j+k < nCIDs; ++k) { + cid = cidMap[i+j+k]; + buf = GString::format("{0:02x}{1:02x}", + (cid >> 8) & 0xff, cid & 0xff); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "\n", 1); + } + (*outputFunc)(outputStream, " >", 3); + } + (*outputFunc)(outputStream, "\n", 1); + (*outputFunc)(outputStream, "] def\n", 6); + } else { + (*outputFunc)(outputStream, "/CIDMap <\n", 10); + for (i = 0; i < nCIDs; i += 16) { + (*outputFunc)(outputStream, " ", 2); + for (j = 0; j < 16 && i+j < nCIDs; ++j) { + cid = cidMap[i+j]; + buf = GString::format("{0:02x}{1:02x}", + (cid >> 8) & 0xff, cid & 0xff); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "\n", 1); + } + (*outputFunc)(outputStream, "> def\n", 6); + } + } else { + // direct mapping - just fill the string(s) with s[i]=i + buf = GString::format("/CIDCount {0:d} def\n", nGlyphs); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + if (nGlyphs > 32767) { + (*outputFunc)(outputStream, "/CIDMap [\n", 10); + for (i = 0; i < nGlyphs; i += 32767) { + j = nGlyphs - i < 32767 ? nGlyphs - i : 32767; + buf = GString::format(" {0:d} string 0 1 {1:d} {{\n", 2 * j, j - 1); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format(" 2 copy dup 2 mul exch {0:d} add -8 bitshift put\n", + i); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format(" 1 index exch dup 2 mul 1 add exch {0:d} add" + " 255 and put\n", i); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, " } for\n", 8); + } + (*outputFunc)(outputStream, "] def\n", 6); + } else { + buf = GString::format("/CIDMap {0:d} string\n", 2 * nGlyphs); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format(" 0 1 {0:d} {{\n", nGlyphs - 1); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, + " 2 copy dup 2 mul exch -8 bitshift put\n", 42); + (*outputFunc)(outputStream, + " 1 index exch dup 2 mul 1 add exch 255 and put\n", 50); + (*outputFunc)(outputStream, " } for\n", 8); + (*outputFunc)(outputStream, "def\n", 4); + } + } + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + buf = GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n", + bbox[0], bbox[1], bbox[2], bbox[3]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); + (*outputFunc)(outputStream, "/Encoding [] readonly def\n", 26); + (*outputFunc)(outputStream, "/CharStrings 1 dict dup begin\n", 30); + (*outputFunc)(outputStream, " /.notdef 0 def\n", 17); + (*outputFunc)(outputStream, " end readonly def\n", 19); + + // write the guts of the dictionary + cvtSfnts(outputFunc, outputStream, NULL, needVerticalMetrics, &maxUsedGlyph); + + // end the dictionary and define the font + (*outputFunc)(outputStream, + "CIDFontName currentdict end /CIDFont defineresource pop\n", + 56); +} + +void FoFiTrueType::convertToCIDType0(char *psName, int *cidMap, int nCIDs, + FoFiOutputFunc outputFunc, + void *outputStream) { + char *start; + int length; + FoFiType1C *ff; + + if (!getCFFBlock(&start, &length)) { + return; + } + if (!(ff = FoFiType1C::make(start, length))) { + return; + } + ff->convertToCIDType0(psName, cidMap, nCIDs, outputFunc, outputStream); + delete ff; +} + +void FoFiTrueType::convertToType0(char *psName, int *cidMap, int nCIDs, + GBool needVerticalMetrics, + FoFiOutputFunc outputFunc, + void *outputStream) { + GString *buf; + GString *sfntsName; + int maxUsedGlyph, n, i, j; + + if (openTypeCFF) { + return; + } + + // write the Type 42 sfnts array + sfntsName = (new GString(psName))->append("_sfnts"); + cvtSfnts(outputFunc, outputStream, sfntsName, needVerticalMetrics, + &maxUsedGlyph); + delete sfntsName; + + // write the descendant Type 42 fonts + // (The following is a kludge: nGlyphs is the glyph count from the + // maxp table; maxUsedGlyph is the max glyph number that has a + // non-zero-length description, from the loca table. The problem is + // that some TrueType font subsets fail to change the glyph count, + // i.e., nGlyphs is much larger than maxUsedGlyph+1, which results + // in an unnecessarily huge Type 0 font. But some other PDF files + // have fonts with only zero or one used glyph, and a content stream + // that refers to one of the unused glyphs -- this results in PS + // errors if we simply use maxUsedGlyph+1 for the Type 0 font. So + // we compromise by always defining at least 256 glyphs.) + if (cidMap) { + n = nCIDs; + } else if (nGlyphs > maxUsedGlyph + 256) { + if (maxUsedGlyph <= 255) { + n = 256; + } else { + n = maxUsedGlyph + 1; + } + } else { + n = nGlyphs; + } + for (i = 0; i < n; i += 256) { + (*outputFunc)(outputStream, "10 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, (int)strlen(psName)); + buf = GString::format("_{0:02x} def\n", i >> 8); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/FontType 42 def\n", 17); + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + buf = GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n", + bbox[0], bbox[1], bbox[2], bbox[3]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); + (*outputFunc)(outputStream, "/sfnts ", 7); + (*outputFunc)(outputStream, psName, (int)strlen(psName)); + (*outputFunc)(outputStream, "_sfnts def\n", 11); + (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); + for (j = 0; j < 256 && i+j < n; ++j) { + buf = GString::format("dup {0:d} /c{1:02x} put\n", j, j); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "readonly def\n", 13); + (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32); + (*outputFunc)(outputStream, "/.notdef 0 def\n", 15); + for (j = 0; j < 256 && i+j < n; ++j) { + buf = GString::format("/c{0:02x} {1:d} def\n", + j, cidMap ? cidMap[i+j] : i+j); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "end readonly def\n", 17); + (*outputFunc)(outputStream, + "FontName currentdict end definefont pop\n", 40); + } + + // write the Type 0 parent font + (*outputFunc)(outputStream, "16 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, (int)strlen(psName)); + (*outputFunc)(outputStream, " def\n", 5); + (*outputFunc)(outputStream, "/FontType 0 def\n", 16); + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + (*outputFunc)(outputStream, "/FMapType 2 def\n", 16); + (*outputFunc)(outputStream, "/Encoding [\n", 12); + for (i = 0; i < n; i += 256) { + buf = GString::format("{0:d}\n", i >> 8); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + (*outputFunc)(outputStream, "/FDepVector [\n", 14); + for (i = 0; i < n; i += 256) { + (*outputFunc)(outputStream, "/", 1); + (*outputFunc)(outputStream, psName, (int)strlen(psName)); + buf = GString::format("_{0:02x} findfont\n", i >> 8); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); +} + +void FoFiTrueType::convertToType0(char *psName, int *cidMap, int nCIDs, + FoFiOutputFunc outputFunc, + void *outputStream) { + char *start; + int length; + FoFiType1C *ff; + + if (!getCFFBlock(&start, &length)) { + return; + } + if (!(ff = FoFiType1C::make(start, length))) { + return; + } + ff->convertToType0(psName, cidMap, nCIDs, outputFunc, outputStream); + delete ff; +} + +GBool FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, + void *outputStream, char *name, + int *codeToGID, Guchar *replacementCmapTable, + int replacementCmapTableLen) { + // this substitute cmap table maps char code ffff to glyph 0, + // with tables for MacRoman and MS Unicode + static char cmapTab[44] = { + 0, 0, // table version number + 0, 2, // number of encoding tables + 0, 1, // platform ID + 0, 0, // encoding ID + 0, 0, 0, 20, // offset of subtable + 0, 3, // platform ID + 0, 1, // encoding ID + 0, 0, 0, 20, // offset of subtable + 0, 4, // subtable format + 0, 24, // subtable length + 0, 0, // subtable version + 0, 2, // segment count * 2 + 0, 2, // 2 * 2 ^ floor(log2(segCount)) + 0, 0, // floor(log2(segCount)) + 0, 0, // 2*segCount - 2*2^floor(log2(segCount)) + (char)0xff, (char)0xff, // endCount[0] + 0, 0, // reserved + (char)0xff, (char)0xff, // startCount[0] + 0, 1, // idDelta[0] + 0, 0 // idRangeOffset[0] + }; + static char nameTab[8] = { + 0, 0, // format + 0, 0, // number of name records + 0, 6, // offset to start of string storage + 0, 0 // pad to multiple of four bytes + }; + static char postTab[32] = { + 0, 1, 0, 0, // format + 0, 0, 0, 0, // italic angle + 0, 0, // underline position + 0, 0, // underline thickness + 0, 0, 0, 0, // fixed pitch + 0, 0, 0, 0, // min Type 42 memory + 0, 0, 0, 0, // max Type 42 memory + 0, 0, 0, 0, // min Type 1 memory + 0, 0, 0, 0 // max Type 1 memory + }; + static char os2Tab[86] = { + 0, 1, // version + 0, 1, // xAvgCharWidth + 0x01, (char)0x90, // usWeightClass + 0, 5, // usWidthClass + 0, 0, // fsType + 0, 0, // ySubscriptXSize + 0, 0, // ySubscriptYSize + 0, 0, // ySubscriptXOffset + 0, 0, // ySubscriptYOffset + 0, 0, // ySuperscriptXSize + 0, 0, // ySuperscriptYSize + 0, 0, // ySuperscriptXOffset + 0, 0, // ySuperscriptYOffset + 0, 0, // yStrikeoutSize + 0, 0, // yStrikeoutPosition + 0, 0, // sFamilyClass + 0, 0, 0, 0, 0, // panose + 0, 0, 0, 0, 0, + 0, 0, 0, 0, // ulUnicodeRange1 + 0, 0, 0, 0, // ulUnicodeRange2 + 0, 0, 0, 0, // ulUnicodeRange3 + 0, 0, 0, 0, // ulUnicodeRange4 + 0, 0, 0, 0, // achVendID + 0, 0, // fsSelection + 0, 0, // usFirstCharIndex + 0, 0, // usLastCharIndex + 0, 0, // sTypoAscender + 0, 0, // sTypoDescender + 0, 0, // sTypoLineGap + 0x20, 0x00, // usWinAscent + 0x20, 0x00, // usWinDescent + 0, 0, 0, 1, // ulCodePageRange1 + 0, 0, 0, 0 // ulCodePageRange2 + }; + GBool missingCmap, missingName, missingPost, missingOS2; + GBool unsortedLoca, emptyCmap, badCmapLen, abbrevHMTX; + int nZeroLengthTables, nBogusTables; + int nHMetrics, advWidth, lsb; + TrueTypeLoca *locaTable; + TrueTypeTable *newTables; + char *newNameTab, *newCmapTab, *newHHEATab, *newHMTXTab; + int nNewTables, cmapIdx, cmapLen, glyfLen, newNameLen, newCmapLen, next; + int newHHEALen, newHMTXLen; + Guint locaChecksum, glyfChecksum, fileChecksum; + char *tableDir; + char locaBuf[4], checksumBuf[4]; + GBool ok; + Guint t; + int pos, i, j, k, n; + + if (openTypeCFF) { + return gFalse; + } + + // check for missing tables + // (Note: if the OS/2 table is missing, the Microsoft PCL5 driver + // will embed a PCL TrueType font with the pitch field set to zero, + // which apparently causes divide-by-zero errors. As far as I can + // tell, the only important field in the OS/2 table is + // xAvgCharWidth.) + missingCmap = (cmapIdx = seekTable("cmap")) < 0; + missingName = seekTable("name") < 0; + missingPost = seekTable("post") < 0; + missingOS2 = seekTable("OS/2") < 0; + + // read the loca table, check to see if it's sorted + locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca)); + unsortedLoca = gFalse; + i = seekTable("loca"); + pos = tables[i].offset; + glyfLen = tables[seekTable("glyf")].len; + ok = gTrue; + for (i = 0; i <= nGlyphs; ++i) { + if (locaFmt) { + locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok); + } else { + locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok); + } + if (locaTable[i].origOffset < 0 || + locaTable[i].origOffset > glyfLen) { + locaTable[i].origOffset = glyfLen; + unsortedLoca = gTrue; + } + if (i > 0 && locaTable[i].origOffset < locaTable[i-1].origOffset) { + unsortedLoca = gTrue; + } + // glyph descriptions must be at least 12 bytes long (nContours, + // xMin, yMin, xMax, yMax, instructionLength - two bytes each); + // invalid glyph descriptions (even if they're never used) make + // Windows choke, so we work around that problem here (ideally, + // this would parse the glyph descriptions in the glyf table and + // remove any that were invalid, but this quick test is a decent + // start) + if (i > 0 && + locaTable[i].origOffset - locaTable[i-1].origOffset > 0 && + locaTable[i].origOffset - locaTable[i-1].origOffset < 12) { + locaTable[i-1].origOffset = locaTable[i].origOffset; + unsortedLoca = gTrue; + } + locaTable[i].idx = i; + } + + // check for zero-length tables and bogus tags + nZeroLengthTables = nBogusTables = 0; + for (i = 0; i < nTables; ++i) { + if (tables[i].len == 0) { + ++nZeroLengthTables; + if (tables[i].tag == cmapTag) { + missingCmap = gTrue; + } else if (tables[i].tag == nameTag) { + missingName = gTrue; + } else if (tables[i].tag == postTag) { + missingPost = gTrue; + } else if (tables[i].tag == os2Tag) { + missingOS2 = gTrue; + } + } else if (!(tables[i].tag & 0xe0000000) || + !(tables[i].tag & 0x00e00000) || + !(tables[i].tag & 0x0000e000) || + !(tables[i].tag & 0x000000e0)) { + // tags where any of the bytes are < 0x20 are probably bogus + // (the TrueType spec uses ASCII sequences for tags) -- this + // catches problems where the number of tables given in the + // header is too large, and so gibberish data is read at the end + // of the table directory + ++nBogusTables; + } + } + + // check for an empty cmap table or an incorrect cmap table length + emptyCmap = badCmapLen = gFalse; + cmapLen = 0; // make gcc happy + if (!missingCmap) { + if (nCmaps == 0) { + emptyCmap = gTrue; + } else { + cmapLen = cmaps[0].offset + cmaps[0].len; + for (i = 1; i < nCmaps; ++i) { + if (cmaps[i].offset + cmaps[i].len > cmapLen) { + cmapLen = cmaps[i].offset + cmaps[i].len; + } + } + cmapLen -= tables[cmapIdx].offset; + if (cmapLen > tables[cmapIdx].len) { + badCmapLen = gTrue; + } + } + } + + // check for an abbreviated hmtx table (this is completely legal, + // but confuses the Microsoft PCL5 printer driver, which generates + // embedded fonts with the pitch field set to zero) + i = seekTable("hhea"); + nHMetrics = getU16BE(tables[i].offset + 34, &ok); + abbrevHMTX = nHMetrics < nGlyphs; + + // if nothing is broken, just write the TTF file as is + if (!missingCmap && !missingName && !missingPost && !missingOS2 && + !unsortedLoca && !emptyCmap && !badCmapLen && !abbrevHMTX && + nZeroLengthTables == 0 && nBogusTables == 0 && + !name && !codeToGID && !replacementCmapTable && !isDfont && !isTTC) { + (*outputFunc)(outputStream, (char *)file, len); + gfree(locaTable); + return gFalse; + } + + // sort the 'loca' table: some (non-compliant) fonts have + // out-of-order loca tables; in order to correctly handle the case + // where (compliant) fonts have empty entries in the middle of the + // table, cmpTrueTypeLocaOffset uses offset as its primary sort key, + // and idx as its secondary key (ensuring that adjacent entries with + // the same pos value remain in the same order) + glyfLen = 0; // make gcc happy + if (unsortedLoca) { +#if HAVE_STD_SORT + std::sort(locaTable, locaTable + nGlyphs + 1, + cmpTrueTypeLocaOffsetFunctor()); +#else + qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), + &cmpTrueTypeLocaOffset); +#endif + for (i = 0; i < nGlyphs; ++i) { + locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset; + } + locaTable[nGlyphs].len = 0; +#if HAVE_STD_SORT + std::sort(locaTable, locaTable + nGlyphs + 1, cmpTrueTypeLocaIdxFunctor()); +#else + qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), + &cmpTrueTypeLocaIdx); +#endif + // if the last entry in the loca is not the max offset (size of + // the glyf table), something is wrong -- work around the problem + // by forcing the last sorted entry to have a zero length + locaTable[nGlyphs].len = 0; + pos = 0; + for (i = 0; i <= nGlyphs; ++i) { + locaTable[i].newOffset = pos; + pos += locaTable[i].len; + if (pos & 3) { + pos += 4 - (pos & 3); + } + } + glyfLen = pos; + } + + // compute checksums for the loca and glyf tables + locaChecksum = glyfChecksum = 0; + if (unsortedLoca) { + if (locaFmt) { + for (j = 0; j <= nGlyphs; ++j) { + locaChecksum += locaTable[j].newOffset; + } + } else { + for (j = 0; j <= nGlyphs; j += 2) { + locaChecksum += locaTable[j].newOffset << 16; + if (j + 1 <= nGlyphs) { + locaChecksum += locaTable[j+1].newOffset; + } + } + } + pos = tables[seekTable("glyf")].offset; + for (j = 0; j < nGlyphs; ++j) { + n = locaTable[j].len; + if (n > 0) { + k = locaTable[j].origOffset; + if (checkRegion(pos + k, n)) { + glyfChecksum += computeTableChecksum(file + pos + k, n); + } + } + } + } + + // construct the new name table + if (name) { + n = (int)strlen(name); + newNameLen = (6 + 4*12 + 2 * (3*n + 7) + 3) & ~3; + newNameTab = (char *)gmalloc(newNameLen); + memset(newNameTab, 0, newNameLen); + newNameTab[0] = 0; // format selector + newNameTab[1] = 0; + newNameTab[2] = 0; // number of name records + newNameTab[3] = 4; + newNameTab[4] = 0; // offset to start of string storage + newNameTab[5] = 6 + 4*12; + next = 0; + for (i = 0; i < 4; ++i) { + newNameTab[6 + i*12 + 0] = 0; // platform ID = Microsoft + newNameTab[6 + i*12 + 1] = 3; + newNameTab[6 + i*12 + 2] = 0; // encoding ID = Unicode + newNameTab[6 + i*12 + 3] = 1; + newNameTab[6 + i*12 + 4] = 0x04; // language ID = American English + newNameTab[6 + i*12 + 5] = 0x09; + newNameTab[6 + i*12 + 6] = 0; // name ID + newNameTab[6 + i*12 + 7] = (char)(i + 1); + // string length + newNameTab[6 + i*12 + 8] = (char)(i+1 == 2 ? 0 : ((2*n) >> 8)); + newNameTab[6 + i*12 + 9] = (char)(i+1 == 2 ? 14 : ((2*n) & 0xff)); + // string offset + newNameTab[6 + i*12 + 10] = (char)(next >> 8); + newNameTab[6 + i*12 + 11] = (char)(next & 0xff); + if (i+1 == 2) { + memcpy(newNameTab + 6 + 4*12 + next, "\0R\0e\0g\0u\0l\0a\0r", 14); + next += 14; + } else { + for (j = 0; j < n; ++j) { + newNameTab[6 + 4*12 + next + 2*j] = 0; + newNameTab[6 + 4*12 + next + 2*j + 1] = name[j]; + } + next += 2*n; + } + } + } else { + newNameLen = 0; + newNameTab = NULL; + } + + // construct the new cmap table + if (codeToGID && !replacementCmapTable) { + newCmapLen = 44 + 256 * 2; + newCmapTab = (char *)gmalloc(newCmapLen); + newCmapTab[0] = 0; // table version number = 0 + newCmapTab[1] = 0; + newCmapTab[2] = 0; // number of encoding tables = 1 + newCmapTab[3] = 1; + newCmapTab[4] = 0; // platform ID = Microsoft + newCmapTab[5] = 3; + newCmapTab[6] = 0; // encoding ID = Unicode + newCmapTab[7] = 1; + newCmapTab[8] = 0; // offset of subtable + newCmapTab[9] = 0; + newCmapTab[10] = 0; + newCmapTab[11] = 12; + newCmapTab[12] = 0; // subtable format = 4 + newCmapTab[13] = 4; + newCmapTab[14] = 0x02; // subtable length + newCmapTab[15] = 0x20; + newCmapTab[16] = 0; // subtable version = 0 + newCmapTab[17] = 0; + newCmapTab[18] = 0; // segment count * 2 + newCmapTab[19] = 4; + newCmapTab[20] = 0; // 2 * 2 ^ floor(log2(segCount)) + newCmapTab[21] = 4; + newCmapTab[22] = 0; // floor(log2(segCount)) + newCmapTab[23] = 1; + newCmapTab[24] = 0; // 2*segCount - 2*2^floor(log2(segCount)) + newCmapTab[25] = 0; + newCmapTab[26] = 0x00; // endCount[0] + newCmapTab[27] = (char)0xff; + newCmapTab[28] = (char)0xff; // endCount[1] + newCmapTab[29] = (char)0xff; + newCmapTab[30] = 0; // reserved + newCmapTab[31] = 0; + newCmapTab[32] = 0x00; // startCount[0] + newCmapTab[33] = 0x00; + newCmapTab[34] = (char)0xff; // startCount[1] + newCmapTab[35] = (char)0xff; + newCmapTab[36] = 0; // idDelta[0] + newCmapTab[37] = 0; + newCmapTab[38] = 0; // idDelta[1] + newCmapTab[39] = 1; + newCmapTab[40] = 0; // idRangeOffset[0] + newCmapTab[41] = 4; + newCmapTab[42] = 0; // idRangeOffset[1] + newCmapTab[43] = 0; + for (i = 0; i < 256; ++i) { + if (codeToGID[i] < 0) { + //~ this may not be correct - we want this character to never be + //~ displayed, but mapping it to the notdef glyph may result in + //~ little boxes being displayed + newCmapTab[44 + 2*i] = 0; + newCmapTab[44 + 2*i + 1] = 0; + } else { + newCmapTab[44 + 2*i] = (char)(codeToGID[i] >> 8); + newCmapTab[44 + 2*i + 1] = (char)(codeToGID[i] & 0xff); + } + } + } else { + newCmapLen = 0; + newCmapTab = NULL; + } + + // generate the new hmtx table and the updated hhea table + if (abbrevHMTX) { + i = seekTable("hhea"); + pos = tables[i].offset; + newHHEALen = 36; + newHHEATab = (char *)gmalloc(newHHEALen); + for (i = 0; i < newHHEALen; ++i) { + newHHEATab[i] = (char)getU8(pos++, &ok); + } + newHHEATab[34] = (char)(nGlyphs >> 8); + newHHEATab[35] = (char)(nGlyphs & 0xff); + i = seekTable("hmtx"); + pos = tables[i].offset; + newHMTXLen = 4 * nGlyphs; + newHMTXTab = (char *)gmalloc(newHMTXLen); + advWidth = 0; + for (i = 0; i < nHMetrics; ++i) { + advWidth = getU16BE(pos, &ok); + lsb = getU16BE(pos + 2, &ok); + pos += 4; + newHMTXTab[4*i ] = (char)(advWidth >> 8); + newHMTXTab[4*i + 1] = (char)(advWidth & 0xff); + newHMTXTab[4*i + 2] = (char)(lsb >> 8); + newHMTXTab[4*i + 3] = (char)(lsb & 0xff); + } + for (; i < nGlyphs; ++i) { + lsb = getU16BE(pos, &ok); + pos += 2; + newHMTXTab[4*i ] = (char)(advWidth >> 8); + newHMTXTab[4*i + 1] = (char)(advWidth & 0xff); + newHMTXTab[4*i + 2] = (char)(lsb >> 8); + newHMTXTab[4*i + 3] = (char)(lsb & 0xff); + } + } else { + newHHEATab = newHMTXTab = NULL; + newHHEALen = newHMTXLen = 0; // make gcc happy + } + + // construct the new table directory: + // - keep all original tables with non-zero length + // - fix the cmap table's length, if necessary + // - add missing tables + // - sort the table by tag + // - compute new table positions, including 4-byte alignment + // - (re)compute table checksums + nNewTables = nTables - nZeroLengthTables - nBogusTables + + (missingCmap ? 1 : 0) + (missingName ? 1 : 0) + + (missingPost ? 1 : 0) + (missingOS2 ? 1 : 0); + newTables = (TrueTypeTable *)gmallocn(nNewTables, sizeof(TrueTypeTable)); + j = 0; + for (i = 0; i < nTables; ++i) { + if (tables[i].len > 0 && + (tables[i].tag & 0xe0000000) && + (tables[i].tag & 0x00e00000) && + (tables[i].tag & 0x0000e000) && + (tables[i].tag & 0x000000e0)) { + newTables[j] = tables[i]; + newTables[j].origOffset = tables[i].offset; + if (checkRegion(tables[i].offset, tables[i].len)) { + newTables[j].checksum = + computeTableChecksum(file + tables[i].offset, tables[i].len); + if (tables[i].tag == headTag) { + // don't include the file checksum + newTables[j].checksum -= getU32BE(tables[i].offset + 8, &ok); + } + } else { + // we'll write four zero bytes for this table + newTables[j].len = 4; + } + if (newTables[j].tag == cmapTag && replacementCmapTable) { + newTables[j].len = replacementCmapTableLen; + newTables[j].checksum = computeTableChecksum(replacementCmapTable, + replacementCmapTableLen); + } else if (newTables[j].tag == cmapTag && codeToGID) { + newTables[j].len = newCmapLen; + newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab, + newCmapLen); + } else if (newTables[j].tag == cmapTag && emptyCmap) { + newTables[j].checksum = computeTableChecksum((Guchar *)cmapTab, + sizeof(cmapTab)); + newTables[j].len = sizeof(cmapTab); + } else if (newTables[j].tag == cmapTag && badCmapLen) { + newTables[j].len = cmapLen; + } else if (newTables[j].tag == locaTag && unsortedLoca) { + newTables[j].len = (nGlyphs + 1) * (locaFmt ? 4 : 2); + newTables[j].checksum = locaChecksum; + } else if (newTables[j].tag == glyfTag && unsortedLoca) { + newTables[j].len = glyfLen; + newTables[j].checksum = glyfChecksum; + } else if (newTables[j].tag == nameTag && name) { + newTables[j].len = newNameLen; + newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab, + newNameLen); + } else if (newTables[j].tag == hheaTag && abbrevHMTX) { + newTables[j].len = newHHEALen; + newTables[j].checksum = computeTableChecksum((Guchar *)newHHEATab, + newHHEALen); + } else if (newTables[j].tag == hmtxTag && abbrevHMTX) { + newTables[j].len = newHMTXLen; + newTables[j].checksum = computeTableChecksum((Guchar *)newHMTXTab, + newHMTXLen); + } + ++j; + } + } + if (missingCmap) { + newTables[j].tag = cmapTag; + if (replacementCmapTable) { + newTables[j].checksum = computeTableChecksum(replacementCmapTable, + replacementCmapTableLen); + newTables[j].len = replacementCmapTableLen; + } else if (codeToGID) { + newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab, + newCmapLen); + newTables[j].len = newCmapLen; + } else { + newTables[j].checksum = computeTableChecksum((Guchar *)cmapTab, + sizeof(cmapTab)); + newTables[j].len = sizeof(cmapTab); + } + ++j; + } + if (missingName) { + newTables[j].tag = nameTag; + if (name) { + newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab, + newNameLen); + newTables[j].len = newNameLen; + } else { + newTables[j].checksum = computeTableChecksum((Guchar *)nameTab, + sizeof(nameTab)); + newTables[j].len = sizeof(nameTab); + } + ++j; + } + if (missingPost) { + newTables[j].tag = postTag; + newTables[j].checksum = computeTableChecksum((Guchar *)postTab, + sizeof(postTab)); + newTables[j].len = sizeof(postTab); + ++j; + } + if (missingOS2) { + newTables[j].tag = os2Tag; + newTables[j].checksum = computeTableChecksum((Guchar *)os2Tab, + sizeof(os2Tab)); + newTables[j].len = sizeof(os2Tab); + ++j; + } +#if HAVE_STD_SORT + std::sort(newTables, newTables + nNewTables, cmpTrueTypeTableTagFunctor()); +#else + qsort(newTables, nNewTables, sizeof(TrueTypeTable), + &cmpTrueTypeTableTag); +#endif + pos = 12 + nNewTables * 16; + for (i = 0; i < nNewTables; ++i) { + newTables[i].offset = pos; + pos += newTables[i].len; + if (pos & 3) { + pos += 4 - (pos & 3); + } + } + + // write the table directory + tableDir = (char *)gmalloc(12 + nNewTables * 16); + tableDir[0] = 0x00; // sfnt version + tableDir[1] = 0x01; + tableDir[2] = 0x00; + tableDir[3] = 0x00; + tableDir[4] = (char)((nNewTables >> 8) & 0xff); // numTables + tableDir[5] = (char)(nNewTables & 0xff); + for (i = -1, t = (Guint)nNewTables; t; ++i, t >>= 1) ; + t = 1 << (4 + i); + tableDir[6] = (char)((t >> 8) & 0xff); // searchRange + tableDir[7] = (char)(t & 0xff); + tableDir[8] = (char)((i >> 8) & 0xff); // entrySelector + tableDir[9] = (char)(i & 0xff); + t = nNewTables * 16 - t; + tableDir[10] = (char)((t >> 8) & 0xff); // rangeShift + tableDir[11] = (char)(t & 0xff); + pos = 12; + for (i = 0; i < nNewTables; ++i) { + tableDir[pos ] = (char)(newTables[i].tag >> 24); + tableDir[pos+ 1] = (char)(newTables[i].tag >> 16); + tableDir[pos+ 2] = (char)(newTables[i].tag >> 8); + tableDir[pos+ 3] = (char) newTables[i].tag; + tableDir[pos+ 4] = (char)(newTables[i].checksum >> 24); + tableDir[pos+ 5] = (char)(newTables[i].checksum >> 16); + tableDir[pos+ 6] = (char)(newTables[i].checksum >> 8); + tableDir[pos+ 7] = (char) newTables[i].checksum; + tableDir[pos+ 8] = (char)(newTables[i].offset >> 24); + tableDir[pos+ 9] = (char)(newTables[i].offset >> 16); + tableDir[pos+10] = (char)(newTables[i].offset >> 8); + tableDir[pos+11] = (char) newTables[i].offset; + tableDir[pos+12] = (char)(newTables[i].len >> 24); + tableDir[pos+13] = (char)(newTables[i].len >> 16); + tableDir[pos+14] = (char)(newTables[i].len >> 8); + tableDir[pos+15] = (char) newTables[i].len; + pos += 16; + } + (*outputFunc)(outputStream, tableDir, 12 + nNewTables * 16); + + // compute the file checksum + fileChecksum = computeTableChecksum((Guchar *)tableDir, + 12 + nNewTables * 16); + for (i = 0; i < nNewTables; ++i) { + fileChecksum += newTables[i].checksum; + } + fileChecksum = 0xb1b0afba - fileChecksum; + + // write the tables + for (i = 0; i < nNewTables; ++i) { + if (newTables[i].tag == headTag) { + if (checkRegion(newTables[i].origOffset, newTables[i].len)) { + (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, 8); + checksumBuf[0] = (char)(fileChecksum >> 24); + checksumBuf[1] = (char)(fileChecksum >> 16); + checksumBuf[2] = (char)(fileChecksum >> 8); + checksumBuf[3] = (char)fileChecksum; + (*outputFunc)(outputStream, checksumBuf, 4); + (*outputFunc)(outputStream, + (char *)file + newTables[i].origOffset + 12, + newTables[i].len - 12); + } else { + for (j = 0; j < newTables[i].len; ++j) { + (*outputFunc)(outputStream, "\0", 1); + } + } + } else if (newTables[i].tag == cmapTag && replacementCmapTable) { + (*outputFunc)(outputStream, (char *)replacementCmapTable, + newTables[i].len); + } else if (newTables[i].tag == cmapTag && codeToGID) { + (*outputFunc)(outputStream, newCmapTab, newTables[i].len); + } else if (newTables[i].tag == cmapTag && missingCmap) { + (*outputFunc)(outputStream, cmapTab, newTables[i].len); + } else if (newTables[i].tag == nameTag && name) { + (*outputFunc)(outputStream, newNameTab, newTables[i].len); + } else if (newTables[i].tag == nameTag && missingName) { + (*outputFunc)(outputStream, nameTab, newTables[i].len); + } else if (newTables[i].tag == postTag && missingPost) { + (*outputFunc)(outputStream, postTab, newTables[i].len); + } else if (newTables[i].tag == os2Tag && missingOS2) { + (*outputFunc)(outputStream, os2Tab, newTables[i].len); + } else if (newTables[i].tag == hheaTag && abbrevHMTX) { + (*outputFunc)(outputStream, newHHEATab, newTables[i].len); + } else if (newTables[i].tag == hmtxTag && abbrevHMTX) { + (*outputFunc)(outputStream, newHMTXTab, newTables[i].len); + } else if (newTables[i].tag == locaTag && unsortedLoca) { + for (j = 0; j <= nGlyphs; ++j) { + if (locaFmt) { + locaBuf[0] = (char)(locaTable[j].newOffset >> 24); + locaBuf[1] = (char)(locaTable[j].newOffset >> 16); + locaBuf[2] = (char)(locaTable[j].newOffset >> 8); + locaBuf[3] = (char) locaTable[j].newOffset; + (*outputFunc)(outputStream, locaBuf, 4); + } else { + locaBuf[0] = (char)(locaTable[j].newOffset >> 9); + locaBuf[1] = (char)(locaTable[j].newOffset >> 1); + (*outputFunc)(outputStream, locaBuf, 2); + } + } + } else if (newTables[i].tag == glyfTag && unsortedLoca) { + pos = tables[seekTable("glyf")].offset; + for (j = 0; j < nGlyphs; ++j) { + n = locaTable[j].len; + if (n > 0) { + k = locaTable[j].origOffset; + if (checkRegion(pos + k, n)) { + (*outputFunc)(outputStream, (char *)file + pos + k, n); + } else { + for (k = 0; k < n; ++k) { + (*outputFunc)(outputStream, "\0", 1); + } + } + if ((k = locaTable[j].len & 3)) { + (*outputFunc)(outputStream, "\0\0\0\0", 4 - k); + } + } + } + } else { + if (checkRegion(newTables[i].origOffset, newTables[i].len)) { + (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, + newTables[i].len); + } else { + for (j = 0; j < newTables[i].len; ++j) { + (*outputFunc)(outputStream, "\0", 1); + } + } + } + if (newTables[i].len & 3) { + (*outputFunc)(outputStream, "\0\0\0", 4 - (newTables[i].len & 3)); + } + } + + gfree(newHMTXTab); + gfree(newHHEATab); + gfree(newCmapTab); + gfree(newNameTab); + gfree(tableDir); + gfree(newTables); + gfree(locaTable); + return gTrue; +} + +void FoFiTrueType::cvtEncoding(char **encoding, + FoFiOutputFunc outputFunc, + void *outputStream) { + const char *name; + GString *buf; + int i; + + (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); + if (encoding) { + for (i = 0; i < 256; ++i) { + if (!(name = encoding[i])) { + name = ".notdef"; + } + buf = GString::format("dup {0:d} /", i); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, name, (int)strlen(name)); + (*outputFunc)(outputStream, " put\n", 5); + } + } else { + for (i = 0; i < 256; ++i) { + buf = GString::format("dup {0:d} /c{1:02x} put\n", i, i); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + } + (*outputFunc)(outputStream, "readonly def\n", 13); +} + +void FoFiTrueType::cvtCharStrings(char **encoding, + int *codeToGID, + FoFiOutputFunc outputFunc, + void *outputStream) { + char *name; + GString *buf; + char buf2[16]; + int i, k; + + // always define '.notdef' + (*outputFunc)(outputStream, "/CharStrings 256 dict dup begin\n", 32); + (*outputFunc)(outputStream, "/.notdef 0 def\n", 15); + + // map char name to glyph index: + // 1. use encoding to map name to char code + // 2. use codeToGID to map char code to glyph index + // N.B. We do this in reverse order because font subsets can have + // weird encodings that use the same character name twice, and + // the first definition is probably the one we want. + k = 0; // make gcc happy + for (i = 255; i >= 0; --i) { + if (encoding) { + name = encoding[i]; + } else { + snprintf(buf2, sizeof(buf2), "c%02x", i); + name = buf2; + } + if (name && strcmp(name, ".notdef")) { + k = codeToGID[i]; + // note: Distiller (maybe Adobe's PS interpreter in general) + // doesn't like TrueType fonts that have CharStrings entries + // which point to nonexistent glyphs, hence the (k < nGlyphs) + // test + if (k > 0 && k < nGlyphs) { + (*outputFunc)(outputStream, "/", 1); + (*outputFunc)(outputStream, name, (int)strlen(name)); + buf = GString::format(" {0:d} def\n", k); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + } + } + + (*outputFunc)(outputStream, "end readonly def\n", 17); +} + +void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, + void *outputStream, GString *name, + GBool needVerticalMetrics, + int *maxUsedGlyph) { + Guchar headData[54]; + TrueTypeLoca *locaTable; + Guchar *locaData; + TrueTypeTable newTables[nT42Tables]; + Guchar tableDir[12 + nT42Tables*16]; + GBool ok; + Guint checksum; + int nNewTables; + int glyfTableLen, length, pos, glyfPos, i, j, k; + Guchar vheaTab[36] = { + 0, 1, 0, 0, // table version number + 0, 0, // ascent + 0, 0, // descent + 0, 0, // reserved + 0, 0, // max advance height + 0, 0, // min top side bearing + 0, 0, // min bottom side bearing + 0, 0, // y max extent + 0, 0, // caret slope rise + 0, 1, // caret slope run + 0, 0, // caret offset + 0, 0, // reserved + 0, 0, // reserved + 0, 0, // reserved + 0, 0, // reserved + 0, 0, // metric data format + 0, 1 // number of advance heights in vmtx table + }; + Guchar *vmtxTab; + GBool needVhea, needVmtx; + int advance; + + // construct the 'head' table, zero out the font checksum + i = seekTable("head"); + pos = tables[i].offset; + if (!checkRegion(pos, 54)) { + return; + } + memcpy(headData, file + pos, 54); + headData[8] = headData[9] = headData[10] = headData[11] = (Guchar)0; + + // check for a bogus loca format field in the 'head' table + // (I've encountered fonts with loca format set to 0x0100 instead of 0x0001) + if (locaFmt != 0 && locaFmt != 1) { + headData[50] = 0; + headData[51] = 1; + } + + // read the original 'loca' table, pad entries out to 4 bytes, and + // sort it into proper order -- some (non-compliant) fonts have + // out-of-order loca tables; in order to correctly handle the case + // where (compliant) fonts have empty entries in the middle of the + // table, cmpTrueTypeLocaOffset uses offset as its primary sort key, + // and idx as its secondary key (ensuring that adjacent entries with + // the same pos value remain in the same order) + // + // NB: a glyph description containing 12 zero bytes should be a + // valid empty glyph (from my reading of the TrueType spec), but + // Acrobat chokes on this (which is an issue when an Xpdf-generated + // PS file is converted back to PDF - with Ghostscript or + // Distiller), so we drop any glyph descriptions of 12 or fewer + // bytes -- an empty glyph description generates an empty glyph with + // no errors + locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca)); + i = seekTable("loca"); + pos = tables[i].offset; + i = seekTable("glyf"); + glyfTableLen = tables[i].len; + ok = gTrue; + for (i = 0; i <= nGlyphs; ++i) { + locaTable[i].idx = i; + if (locaFmt) { + locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok); + } else { + locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok); + } + if (locaTable[i].origOffset < 0 || + locaTable[i].origOffset > glyfTableLen) { + locaTable[i].origOffset = glyfTableLen; + } + } +#if HAVE_STD_SORT + std::sort(locaTable, locaTable + nGlyphs + 1, + cmpTrueTypeLocaOffsetFunctor()); +#else + qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), + &cmpTrueTypeLocaOffset); +#endif + for (i = 0; i < nGlyphs; ++i) { + locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset; + } + locaTable[nGlyphs].len = 0; +#if HAVE_STD_SORT + std::sort(locaTable, locaTable + nGlyphs + 1, cmpTrueTypeLocaIdxFunctor()); +#else + qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), + &cmpTrueTypeLocaIdx); +#endif + pos = 0; + *maxUsedGlyph = -1; + for (i = 0; i <= nGlyphs; ++i) { + locaTable[i].newOffset = pos; + if (locaTable[i].len > 12) { + pos += locaTable[i].len; + if (pos & 3) { + pos += 4 - (pos & 3); + } + *maxUsedGlyph = i; + } + } + + // construct the new 'loca' table + locaData = (Guchar *)gmallocn(nGlyphs + 1, (locaFmt ? 4 : 2)); + for (i = 0; i <= nGlyphs; ++i) { + pos = locaTable[i].newOffset; + if (locaFmt) { + locaData[4*i ] = (Guchar)(pos >> 24); + locaData[4*i+1] = (Guchar)(pos >> 16); + locaData[4*i+2] = (Guchar)(pos >> 8); + locaData[4*i+3] = (Guchar) pos; + } else { + locaData[2*i ] = (Guchar)(pos >> 9); + locaData[2*i+1] = (Guchar)(pos >> 1); + } + } + + // count the number of tables + nNewTables = 0; + for (i = 0; i < nT42Tables; ++i) { + if (t42Tables[i].required || + seekTable(t42Tables[i].tag) >= 0) { + ++nNewTables; + } + } + vmtxTab = NULL; // make gcc happy + advance = 0; // make gcc happy + if (needVerticalMetrics) { + needVhea = seekTable("vhea") < 0; + needVmtx = seekTable("vmtx") < 0; + if (needVhea || needVmtx) { + i = seekTable("head"); + advance = getU16BE(tables[i].offset + 18, &ok); // units per em + if (needVhea) { + ++nNewTables; + } + if (needVmtx) { + ++nNewTables; + } + } + } + + // construct the new table headers, including table checksums + // (pad each table out to a multiple of 4 bytes) + pos = 12 + nNewTables*16; + k = 0; + for (i = 0; i < nT42Tables; ++i) { + length = -1; + checksum = 0; // make gcc happy + if (i == t42HeadTable) { + length = 54; + checksum = computeTableChecksum(headData, 54); + } else if (i == t42LocaTable) { + length = (nGlyphs + 1) * (locaFmt ? 4 : 2); + checksum = computeTableChecksum(locaData, length); + } else if (i == t42GlyfTable) { + length = 0; + checksum = 0; + glyfPos = tables[seekTable("glyf")].offset; + for (j = 0; j < nGlyphs; ++j) { + if (locaTable[j].len > 12) { + length += locaTable[j].len; + if (length & 3) { + length += 4 - (length & 3); + } + if (checkRegion(glyfPos + locaTable[j].origOffset, + locaTable[j].len)) { + checksum += + computeTableChecksum(file + glyfPos + locaTable[j].origOffset, + locaTable[j].len); + } + } + } + } else { + if ((j = seekTable(t42Tables[i].tag)) >= 0) { + length = tables[j].len; + if (checkRegion(tables[j].offset, length)) { + checksum = computeTableChecksum(file + tables[j].offset, length); + } + } else if (needVerticalMetrics && i == t42VheaTable) { + vheaTab[10] = (Guchar)(advance / 256); // max advance height + vheaTab[11] = (Guchar)(advance % 256); + length = sizeof(vheaTab); + checksum = computeTableChecksum(vheaTab, length); + } else if (needVerticalMetrics && i == t42VmtxTable) { + length = 4 + (nGlyphs - 1) * 2; + vmtxTab = (Guchar *)gmalloc(length); + vmtxTab[0] = (Guchar)(advance / 256); + vmtxTab[1] = (Guchar)(advance % 256); + for (j = 2; j < length; j += 2) { + vmtxTab[j] = 0; + vmtxTab[j+1] = 0; + } + checksum = computeTableChecksum(vmtxTab, length); + } else if (t42Tables[i].required) { + //~ error(-1, "Embedded TrueType font is missing a required table ('%s')", + //~ t42Tables[i].tag); + length = 0; + checksum = 0; + } + } + if (length >= 0) { + newTables[k].tag = ((t42Tables[i].tag[0] & 0xff) << 24) | + ((t42Tables[i].tag[1] & 0xff) << 16) | + ((t42Tables[i].tag[2] & 0xff) << 8) | + (t42Tables[i].tag[3] & 0xff); + newTables[k].checksum = checksum; + newTables[k].offset = pos; + newTables[k].len = length; + pos += length; + if (pos & 3) { + pos += 4 - (length & 3); + } + ++k; + } + } + + // construct the table directory + tableDir[0] = 0x00; // sfnt version + tableDir[1] = 0x01; + tableDir[2] = 0x00; + tableDir[3] = 0x00; + tableDir[4] = 0; // numTables + tableDir[5] = (Guchar)nNewTables; + tableDir[6] = 0; // searchRange + tableDir[7] = (Guchar)128; + tableDir[8] = 0; // entrySelector + tableDir[9] = 3; + tableDir[10] = 0; // rangeShift + tableDir[11] = (Guchar)(16 * nNewTables - 128); + pos = 12; + for (i = 0; i < nNewTables; ++i) { + tableDir[pos ] = (Guchar)(newTables[i].tag >> 24); + tableDir[pos+ 1] = (Guchar)(newTables[i].tag >> 16); + tableDir[pos+ 2] = (Guchar)(newTables[i].tag >> 8); + tableDir[pos+ 3] = (Guchar) newTables[i].tag; + tableDir[pos+ 4] = (Guchar)(newTables[i].checksum >> 24); + tableDir[pos+ 5] = (Guchar)(newTables[i].checksum >> 16); + tableDir[pos+ 6] = (Guchar)(newTables[i].checksum >> 8); + tableDir[pos+ 7] = (Guchar) newTables[i].checksum; + tableDir[pos+ 8] = (Guchar)(newTables[i].offset >> 24); + tableDir[pos+ 9] = (Guchar)(newTables[i].offset >> 16); + tableDir[pos+10] = (Guchar)(newTables[i].offset >> 8); + tableDir[pos+11] = (Guchar) newTables[i].offset; + tableDir[pos+12] = (Guchar)(newTables[i].len >> 24); + tableDir[pos+13] = (Guchar)(newTables[i].len >> 16); + tableDir[pos+14] = (Guchar)(newTables[i].len >> 8); + tableDir[pos+15] = (Guchar) newTables[i].len; + pos += 16; + } + + // compute the font checksum and store it in the head table + checksum = computeTableChecksum(tableDir, 12 + nNewTables*16); + for (i = 0; i < nNewTables; ++i) { + checksum += newTables[i].checksum; + } + checksum = 0xb1b0afba - checksum; // because the TrueType spec says so + headData[ 8] = (Guchar)(checksum >> 24); + headData[ 9] = (Guchar)(checksum >> 16); + headData[10] = (Guchar)(checksum >> 8); + headData[11] = (Guchar) checksum; + + // start the sfnts array + if (name) { + (*outputFunc)(outputStream, "/", 1); + (*outputFunc)(outputStream, name->getCString(), name->getLength()); + (*outputFunc)(outputStream, " [\n", 3); + } else { + (*outputFunc)(outputStream, "/sfnts [\n", 9); + } + + // write the table directory + dumpString(tableDir, 12 + nNewTables*16, outputFunc, outputStream); + + // write the tables + for (i = 0; i < nNewTables; ++i) { + if (i == t42HeadTable) { + dumpString(headData, 54, outputFunc, outputStream); + } else if (i == t42LocaTable) { + length = (nGlyphs + 1) * (locaFmt ? 4 : 2); + dumpString(locaData, length, outputFunc, outputStream); + } else if (i == t42GlyfTable) { + glyfPos = tables[seekTable("glyf")].offset; + for (j = 0; j < nGlyphs; ++j) { + if (locaTable[j].len > 12 && + checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) { + dumpString(file + glyfPos + locaTable[j].origOffset, + locaTable[j].len, outputFunc, outputStream); + } + } + } else { + // length == 0 means the table is missing and the error was + // already reported during the construction of the table + // headers + if ((length = newTables[i].len) > 0) { + if ((j = seekTable(t42Tables[i].tag)) >= 0 && + checkRegion(tables[j].offset, tables[j].len)) { + dumpString(file + tables[j].offset, tables[j].len, + outputFunc, outputStream); + } else if (needVerticalMetrics && i == t42VheaTable) { + dumpString(vheaTab, length, outputFunc, outputStream); + } else if (needVerticalMetrics && i == t42VmtxTable) { + dumpString(vmtxTab, length, outputFunc, outputStream); + } + } + } + } + + // end the sfnts array + (*outputFunc)(outputStream, "] def\n", 6); + + gfree(locaData); + gfree(locaTable); + if (vmtxTab) { + gfree(vmtxTab); + } +} + +void FoFiTrueType::dumpString(Guchar *s, int length, + FoFiOutputFunc outputFunc, + void *outputStream) { + GString *buf; + int pad, i, j; + + (*outputFunc)(outputStream, "<", 1); + for (i = 0; i < length; i += 32) { + for (j = 0; j < 32 && i+j < length; ++j) { + buf = GString::format("{0:02x}", s[i+j] & 0xff); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (i % (65536 - 32) == 65536 - 64) { + (*outputFunc)(outputStream, ">\n<", 3); + } else if (i+32 < length) { + (*outputFunc)(outputStream, "\n", 1); + } + } + if (length & 3) { + pad = 4 - (length & 3); + for (i = 0; i < pad; ++i) { + (*outputFunc)(outputStream, "00", 2); + } + } + // add an extra zero byte because the Adobe Type 42 spec says so + (*outputFunc)(outputStream, "00>\n", 4); +} + +Guint FoFiTrueType::computeTableChecksum(Guchar *data, int length) { + Guint checksum, word; + int i; + + checksum = 0; + for (i = 0; i+3 < length; i += 4) { + word = ((data[i ] & 0xff) << 24) + + ((data[i+1] & 0xff) << 16) + + ((data[i+2] & 0xff) << 8) + + (data[i+3] & 0xff); + checksum += word; + } + if (length & 3) { + word = 0; + i = length & ~3; + switch (length & 3) { + case 3: + word |= (data[i+2] & 0xff) << 8; + case 2: + word |= (data[i+1] & 0xff) << 16; + case 1: + word |= (data[i ] & 0xff) << 24; + break; + } + checksum += word; + } + return checksum; +} + +void FoFiTrueType::parse(int fontNum, GBool allowHeadlessCFF) { + Guint topTag; + int offset, pos, ver, i, j, k; + + parsedOk = gTrue; + + // check for a dfont or TrueType collection (TTC) + // offset = start of actual TrueType font file (table positions are + // relative to this + // pos = position of table directory (relative to offset) + if (isDfont) { + parseDfont(fontNum, &offset, &pos); + } else { + offset = 0; + topTag = getU32BE(0, &parsedOk); + if (!parsedOk) { + return; + } + if (topTag == ttcfTag) { + parseTTC(fontNum, &pos); + } else { + pos = 0; + } + } + if (!parsedOk) { + return; + } + + // check the sfnt version + ver = getU32BE(offset + pos, &parsedOk); + if (!parsedOk) { + return; + } + openTypeCFF = ver == 0x4f54544f; // 'OTTO' + + // read the table directory + nTables = getU16BE(offset + pos + 4, &parsedOk); + if (!parsedOk) { + return; + } + tables = (TrueTypeTable *)gmallocn(nTables, sizeof(TrueTypeTable)); + pos += 12; + j = 0; + for (i = 0; i < nTables; ++i) { + tables[j].tag = getU32BE(offset + pos, &parsedOk); + tables[j].checksum = getU32BE(offset + pos + 4, &parsedOk); + tables[j].offset = offset + (int)getU32BE(offset + pos + 8, &parsedOk); + tables[j].len = (int)getU32BE(offset + pos + 12, &parsedOk); + if (tables[j].offset >= 0 && + tables[j].len >= 0 && + tables[j].offset + tables[j].len >= tables[j].offset && + tables[j].offset + tables[j].len <= len) { + // ignore any bogus entries in the table directory + ++j; + } + pos += 16; + } + nTables = j; + if (!parsedOk) { + return; + } + + // check for the head table; allow for a head-less OpenType CFF font + headlessCFF = gFalse; + if (seekTable("head") < 0) { + if (openTypeCFF && allowHeadlessCFF && seekTable("CFF ") >= 0) { + headlessCFF = gTrue; + nGlyphs = 0; + bbox[0] = bbox[1] = bbox[2] = bbox[3] = 0; + locaFmt = 0; + return; + } + parsedOk = gFalse; + return; + } + + // check for other tables that are required by both the TrueType + // spec and the Type 42 spec + if (seekTable("hhea") < 0 || + seekTable("maxp") < 0 || + seekTable("hmtx") < 0 || + (!openTypeCFF && seekTable("loca") < 0) || + (!openTypeCFF && seekTable("glyf") < 0) || + (openTypeCFF && seekTable("CFF ") < 0)) { + parsedOk = gFalse; + return; + } + + // read the cmaps + if ((i = seekTable("cmap")) >= 0 && tables[i].len >= 4) { + pos = tables[i].offset + 2; + nCmaps = getU16BE(pos, &parsedOk); + pos += 2; + if (!parsedOk) { + return; + } + cmaps = (TrueTypeCmap *)gmallocn(nCmaps, sizeof(TrueTypeCmap)); + k = 0; + for (j = 0; j < nCmaps; ++j) { + cmaps[k].platform = getU16BE(pos, &parsedOk); + cmaps[k].encoding = getU16BE(pos + 2, &parsedOk); + cmaps[k].offset = getU32BE(pos + 4, &parsedOk); + pos += 8; + if (cmaps[k].offset >= tables[i].len) { + // skip any invalid subtables + continue; + } + cmaps[k].offset += tables[i].offset; + cmaps[k].fmt = getU16BE(cmaps[k].offset, &parsedOk); + cmaps[k].len = getU16BE(cmaps[k].offset + 2, &parsedOk); + ++k; + } + nCmaps = k; + if (!parsedOk) { + return; + } + } + + // get the number of glyphs from the maxp table + i = seekTable("maxp"); + nGlyphs = getU16BE(tables[i].offset + 4, &parsedOk); + if (!parsedOk) { + return; + } + + // get the bbox and loca table format from the head table + i = seekTable("head"); + bbox[0] = getS16BE(tables[i].offset + 36, &parsedOk); + bbox[1] = getS16BE(tables[i].offset + 38, &parsedOk); + bbox[2] = getS16BE(tables[i].offset + 40, &parsedOk); + bbox[3] = getS16BE(tables[i].offset + 42, &parsedOk); + locaFmt = getS16BE(tables[i].offset + 50, &parsedOk); + if (!parsedOk) { + return; + } + + // make sure the loca table is sane (correct length) + // NB: out-of-bounds entries are handled in writeTTF() + if (!openTypeCFF) { + i = seekTable("loca"); + if (tables[i].len < (locaFmt ? 4 : 2)) { + parsedOk = gFalse; + return; + } + if (tables[i].len < (nGlyphs + 1) * (locaFmt ? 4 : 2)) { + nGlyphs = tables[i].len / (locaFmt ? 4 : 2) - 1; + } + if (!parsedOk) { + return; + } + } + + // read the post table + readPostTable(); +} + +// Get the table directory position +void FoFiTrueType::parseTTC(int fontNum, int *pos) { + int nFonts; + + isTTC = gTrue; + nFonts = getU32BE(8, &parsedOk); + if (!parsedOk) { + return; + } + if (fontNum < 0 || fontNum >= nFonts) { + parsedOk = gFalse; + return; + } + *pos = getU32BE(12 + 4 * fontNum, &parsedOk); +} + +void FoFiTrueType::parseDfont(int fontNum, int *offset, int *startPos) { + int resMapOffset, resDataOffset; + int resTypeListOffset, nTypes, typeTag; + int nFonts, refListOffset, dataOffset; + int pos, i; + + resDataOffset = getU32BE(0, &parsedOk); + resMapOffset = getU32BE(4, &parsedOk); + if (!parsedOk) { + return; + } + + resTypeListOffset = getU16BE(resMapOffset + 24, &parsedOk); + // resNameListOffset = getU16BE(resMapOffset + 26, &parsedOk); + nTypes = getU16BE(resMapOffset + 28, &parsedOk) + 1; + if (!parsedOk) { + return; + } + + pos = 0; // make gcc happy + for (i = 0; i < nTypes; ++i) { + pos = resMapOffset + resTypeListOffset + 2 + 8*i; + typeTag = getU32BE(pos, &parsedOk); + if (!parsedOk) { + return; + } + if (typeTag == 0x73666e74) { // 'sfnt' + break; + } + } + if (i >= nTypes) { + parsedOk = gFalse; + return; + } + nFonts = getU16BE(pos + 4, &parsedOk) + 1; + refListOffset = getU16BE(pos + 6, &parsedOk); + if (!parsedOk) { + return; + } + if (fontNum < 0 || fontNum >= nFonts) { + parsedOk = gFalse; + return; + } + pos = resMapOffset + resTypeListOffset + refListOffset + 12 * fontNum; + dataOffset = getU32BE(pos + 4, &parsedOk) & 0x00ffffff; + if (!parsedOk) { + return; + } + // the data offset points to a 4-byte length field, which we skip over + *offset = resDataOffset + dataOffset + 4; + *startPos = 0; +} + +void FoFiTrueType::readPostTable() { + GString *name; + int tablePos, postFmt, stringIdx, stringPos; + GBool ok; + int i, j, n, m; + + ok = gTrue; + if ((i = seekTable("post")) < 0) { + return; + } + tablePos = tables[i].offset; + postFmt = getU32BE(tablePos, &ok); + if (!ok) { + goto err; + } + if (postFmt == 0x00010000) { + nameToGID = new GHash(gTrue); + for (i = 0; i < 258; ++i) { + nameToGID->add(new GString(macGlyphNames[i]), i); + } + } else if (postFmt == 0x00020000) { + nameToGID = new GHash(gTrue); + n = getU16BE(tablePos + 32, &ok); + if (!ok) { + goto err; + } + stringIdx = 0; + stringPos = tablePos + 34 + 2*n; + for (i = 0; i < n && i < nGlyphs; ++i) { + ok = gTrue; + j = getU16BE(tablePos + 34 + 2*i, &ok); + if (j < 258) { + nameToGID->removeInt(macGlyphNames[j]); + nameToGID->add(new GString(macGlyphNames[j]), i); + } else { + j -= 258; + if (j != stringIdx) { + for (stringIdx = 0, stringPos = tablePos + 34 + 2*n; + stringIdx < j; + ++stringIdx, stringPos += 1 + getU8(stringPos, &ok)) ; + if (!ok) { + continue; + } + } + m = getU8(stringPos, &ok); + if (!ok || !checkRegion(stringPos + 1, m)) { + continue; + } + name = new GString((char *)&file[stringPos + 1], m); + nameToGID->removeInt(name); + nameToGID->add(name, i); + ++stringIdx; + stringPos += 1 + m; + } + } + } else if (postFmt == 0x00028000) { + nameToGID = new GHash(gTrue); + for (i = 0; i < nGlyphs; ++i) { + j = getU8(tablePos + 32 + i, &ok); + if (!ok) { + continue; + } + if (j < 258) { + nameToGID->removeInt(macGlyphNames[j]); + nameToGID->add(new GString(macGlyphNames[j]), i); + } + } + } + + return; + + err: + if (nameToGID) { + delete nameToGID; + nameToGID = NULL; + } +} + +int FoFiTrueType::seekTable(const char *tag) { + Guint tagI; + int i; + + tagI = ((tag[0] & 0xff) << 24) | + ((tag[1] & 0xff) << 16) | + ((tag[2] & 0xff) << 8) | + (tag[3] & 0xff); + for (i = 0; i < nTables; ++i) { + if (tables[i].tag == tagI) { + return i; + } + } + return -1; +} diff --git a/fofi/FoFiTrueType.h b/fofi/FoFiTrueType.h new file mode 100644 index 0000000..619e1bd --- /dev/null +++ b/fofi/FoFiTrueType.h @@ -0,0 +1,216 @@ +//======================================================================== +// +// FoFiTrueType.h +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FOFITRUETYPE_H +#define FOFITRUETYPE_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "FoFiBase.h" + +class GString; +class GHash; +struct TrueTypeTable; +struct TrueTypeCmap; + +//------------------------------------------------------------------------ +// FoFiTrueType +//------------------------------------------------------------------------ + +class FoFiTrueType: public FoFiBase { +public: + + // Create a FoFiTrueType object from a memory buffer. If + // <allowHeadlessCFF> is true, OpenType CFF fonts without the 'head' + // table are permitted -- this is useful when calling the convert* + // functions. + static FoFiTrueType *make(char *fileA, int lenA, int fontNum, + GBool allowHeadlessCFF = gFalse); + + // Create a FoFiTrueType object from a file on disk. If + // <allowHeadlessCFF> is true, OpenType CFF fonts without the 'head' + // table are permitted -- this is useful when calling the convert* + // functions. + static FoFiTrueType *load(char *fileName, int fontNum, + GBool allowHeadlessCFF = gFalse); + + virtual ~FoFiTrueType(); + + // Returns true if this an OpenType font containing CFF data, false + // if it's a TrueType font (or OpenType font with TrueType data). + GBool isOpenTypeCFF() { return openTypeCFF; } + + // Returns true if this is an OpenType CFF font that is missing the + // 'head' table. This is a violation of the OpenType spec, but the + // embedded CFF font can be usable for some purposes (e.g., the + // convert* functions). + GBool isHeadlessCFF() { return headlessCFF; } + + // Return the number of cmaps defined by this font. + int getNumCmaps(); + + // Return the platform ID of the <i>th cmap. + int getCmapPlatform(int i); + + // Return the encoding ID of the <i>th cmap. + int getCmapEncoding(int i); + + // Return the index of the cmap for <platform>, <encoding>. Returns + // -1 if there is no corresponding cmap. + int findCmap(int platform, int encoding); + + // Return the GID corresponding to <c> according to the <i>th cmap. + int mapCodeToGID(int i, int c); + + // Returns the GID corresponding to <name> according to the post + // table. Returns 0 if there is no mapping for <name> or if the + // font does not have a post table. + int mapNameToGID(char *name); + + // Return the mapping from CIDs to GIDs, and return the number of + // CIDs in *<nCIDs>. This is only useful for CID fonts. (Only + // useful for OpenType CFF fonts.) + int *getCIDToGIDMap(int *nCIDs); + + // Returns the least restrictive embedding licensing right (as + // defined by the TrueType spec): + // * 4: OS/2 table is missing or invalid + // * 3: installable embedding + // * 2: editable embedding + // * 1: preview & print embedding + // * 0: restricted license embedding + int getEmbeddingRights(); + + // Return the font matrix as an array of six numbers. (Only useful + // for OpenType CFF fonts.) + void getFontMatrix(double *mat); + + // Return the number of glyphs in the font. + int getNumGlyphs() { return nGlyphs; } + + // Returns true if this looks like a CJK font that uses bytecode + // instructions to assemble glyphs. + GBool checkForTrickyCJK(); + + // Convert to a Type 42 font, suitable for embedding in a PostScript + // file. <psName> will be used as the PostScript font name (so we + // don't need to depend on the 'name' table in the font). The + // <encoding> array specifies the mapping from char codes to names. + // If <encoding> is NULL, the encoding is unknown or undefined. The + // <codeToGID> array specifies the mapping from char codes to GIDs. + // (Not useful for OpenType CFF fonts.) + void convertToType42(char *psName, char **encoding, + int *codeToGID, + FoFiOutputFunc outputFunc, void *outputStream); + + // Convert to a Type 1 font, suitable for embedding in a PostScript + // file. This is only useful with 8-bit fonts. If <newEncoding> is + // not NULL, it will be used in place of the encoding in the Type 1C + // font. If <ascii> is true the eexec section will be hex-encoded, + // otherwise it will be left as binary data. If <psName> is + // non-NULL, it will be used as the PostScript font name. (Only + // useful for OpenType CFF fonts.) + void convertToType1(char *psName, const char **newEncoding, GBool ascii, + FoFiOutputFunc outputFunc, void *outputStream); + + // Convert to a Type 2 CIDFont, suitable for embedding in a + // PostScript file. <psName> will be used as the PostScript font + // name (so we don't need to depend on the 'name' table in the + // font). The <cidMap> array maps CIDs to GIDs; it has <nCIDs> + // entries. (Not useful for OpenType CFF fonts.) + void convertToCIDType2(char *psName, int *cidMap, int nCIDs, + GBool needVerticalMetrics, + FoFiOutputFunc outputFunc, void *outputStream); + + // Convert to a Type 0 CIDFont, suitable for embedding in a + // PostScript file. <psName> will be used as the PostScript font + // name. (Only useful for OpenType CFF fonts.) + void convertToCIDType0(char *psName, int *cidMap, int nCIDs, + FoFiOutputFunc outputFunc, void *outputStream); + + // Convert to a Type 0 (but non-CID) composite font, suitable for + // embedding in a PostScript file. <psName> will be used as the + // PostScript font name (so we don't need to depend on the 'name' + // table in the font). The <cidMap> array maps CIDs to GIDs; it has + // <nCIDs> entries. (Not useful for OpenType CFF fonts.) + void convertToType0(char *psName, int *cidMap, int nCIDs, + GBool needVerticalMetrics, + FoFiOutputFunc outputFunc, void *outputStream); + + // Convert to a Type 0 (but non-CID) composite font, suitable for + // embedding in a PostScript file. <psName> will be used as the + // PostScript font name. (Only useful for OpenType CFF fonts.) + void convertToType0(char *psName, int *cidMap, int nCIDs, + FoFiOutputFunc outputFunc, void *outputStream); + + // Write a clean TTF file, filling in missing tables and correcting + // various other errors. If <name> is non-NULL, the font is renamed + // to <name>. If <codeToGID> is non-NULL, the font is re-encoded, + // using a Windows Unicode cmap. If <name> is NULL and the font is + // complete and correct, it will be written unmodified. If + // <replacementCmapTable> is non-NULL it will be used as the cmap + // table in the written font (overriding any existing cmap table + // and/or the codeToGID arg). (Not useful for OpenType CFF fonts.) + // Returns true if the font was modified. + GBool writeTTF(FoFiOutputFunc outputFunc, void *outputStream, + char *name = NULL, int *codeToGID = NULL, + Guchar *replacementCmapTable = NULL, + int replacementCmapTableLen = 0); + + // Returns a pointer to the CFF font embedded in this OpenType font. + // If successful, sets *<start> and *<length>, and returns true. + // Otherwise returns false. (Only useful for OpenType CFF fonts). + GBool getCFFBlock(char **start, int *length); + +private: + + FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, + int fontNum, GBool isDfont, GBool allowHeadlessCFF); + void cvtEncoding(char **encoding, + FoFiOutputFunc outputFunc, + void *outputStream); + void cvtCharStrings(char **encoding, + int *codeToGID, + FoFiOutputFunc outputFunc, + void *outputStream); + void cvtSfnts(FoFiOutputFunc outputFunc, + void *outputStream, GString *name, + GBool needVerticalMetrics, + int *maxUsedGlyph); + void dumpString(Guchar *s, int length, + FoFiOutputFunc outputFunc, + void *outputStream); + Guint computeTableChecksum(Guchar *data, int length); + void parse(int fontNum, GBool allowHeadlessCFF); + void parseTTC(int fontNum, int *pos); + void parseDfont(int fontNum, int *offset, int *pos); + void readPostTable(); + int seekTable(const char *tag); + + TrueTypeTable *tables; + int nTables; + TrueTypeCmap *cmaps; + int nCmaps; + int nGlyphs; + int locaFmt; + int bbox[4]; + GHash *nameToGID; + GBool openTypeCFF; + GBool headlessCFF; + GBool isDfont; + GBool isTTC; + + GBool parsedOk; +}; + +#endif diff --git a/fofi/FoFiType1.cc b/fofi/FoFiType1.cc new file mode 100644 index 0000000..83ec53e --- /dev/null +++ b/fofi/FoFiType1.cc @@ -0,0 +1,359 @@ +//======================================================================== +// +// FoFiType1.cc +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdlib.h> +#include <string.h> +#include "gmem.h" +#include "gmempp.h" +#include "FoFiEncodings.h" +#include "FoFiType1.h" + +//------------------------------------------------------------------------ +// FoFiType1 +//------------------------------------------------------------------------ + +FoFiType1 *FoFiType1::make(char *fileA, int lenA) { + return new FoFiType1(fileA, lenA, gFalse); +} + +FoFiType1 *FoFiType1::load(char *fileName) { + char *fileA; + int lenA; + + if (!(fileA = FoFiBase::readFile(fileName, &lenA))) { + return NULL; + } + return new FoFiType1(fileA, lenA, gTrue); +} + +FoFiType1::FoFiType1(char *fileA, int lenA, GBool freeFileDataA): + FoFiBase(fileA, lenA, freeFileDataA) +{ + name = NULL; + encoding = NULL; + fontMatrix[0] = 0.001; + fontMatrix[1] = 0; + fontMatrix[2] = 0; + fontMatrix[3] = 0.001; + fontMatrix[4] = 0; + fontMatrix[5] = 0; + parsed = gFalse; + undoPFB(); +} + +FoFiType1::~FoFiType1() { + int i; + + if (name) { + gfree(name); + } + if (encoding && encoding != (char **)fofiType1StandardEncoding) { + for (i = 0; i < 256; ++i) { + gfree(encoding[i]); + } + gfree(encoding); + } +} + +char *FoFiType1::getName() { + if (!parsed) { + parse(); + } + return name; +} + +char **FoFiType1::getEncoding() { + if (!parsed) { + parse(); + } + return encoding; +} + +void FoFiType1::getFontMatrix(double *mat) { + int i; + + if (!parsed) { + parse(); + } + for (i = 0; i < 6; ++i) { + mat[i] = fontMatrix[i]; + } +} + +void FoFiType1::writeEncoded(const char **newEncoding, + FoFiOutputFunc outputFunc, void *outputStream) { + char buf[512]; + char *line, *line2, *p; + int i; + + // copy everything up to the encoding + for (line = (char *)file; + line && line + 9 <= (char *)file + len && strncmp(line, "/Encoding", 9); + line = getNextLine(line)) ; + if (!line) { + // no encoding - just copy the whole font file + (*outputFunc)(outputStream, (char *)file, len); + return; + } + (*outputFunc)(outputStream, (char *)file, (int)(line - (char *)file)); + + // write the new encoding + (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); + (*outputFunc)(outputStream, + "0 1 255 {1 index exch /.notdef put} for\n", 40); + for (i = 0; i < 256; ++i) { + if (newEncoding[i]) { + snprintf(buf, sizeof(buf), "dup %d /%s put\n", i, newEncoding[i]); + (*outputFunc)(outputStream, buf, (int)strlen(buf)); + } + } + (*outputFunc)(outputStream, "readonly def\n", 13); + + // find the end of the encoding data + //~ this ought to parse PostScript tokens + if (line + 30 <= (char *)file + len && + !strncmp(line, "/Encoding StandardEncoding def", 30)) { + line = getNextLine(line); + } else { + // skip "/Encoding" + one whitespace char, + // then look for 'def' preceded by PostScript whitespace + p = line + 10; + line = NULL; + for (; p < (char *)file + len; ++p) { + if ((*p == ' ' || *p == '\t' || *p == '\x0a' || + *p == '\x0d' || *p == '\x0c' || *p == '\0') && + p + 4 <= (char *)file + len && + !strncmp(p + 1, "def", 3)) { + line = p + 4; + break; + } + } + } + + // some fonts have two /Encoding entries in their dictionary, so we + // check for a second one here + if (line) { + for (line2 = line, i = 0; + i < 20 && line2 && line2 + 9 <= (char *)file + len && + strncmp(line2, "/Encoding", 9); + line2 = getNextLine(line2), ++i) ; + if (i < 20 && line2) { + (*outputFunc)(outputStream, line, (int)(line2 - line)); + if (line2 + 30 <= (char *)file + len && + !strncmp(line2, "/Encoding StandardEncoding def", 30)) { + line = getNextLine(line2); + } else { + // skip "/Encoding", + // then look for 'def' preceded by PostScript whitespace + p = line2 + 9; + line = NULL; + for (; p < (char *)file + len; ++p) { + if ((*p == ' ' || *p == '\t' || *p == '\x0a' || + *p == '\x0d' || *p == '\x0c' || *p == '\0') && + p + 4 <= (char *)file + len && + !strncmp(p + 1, "def", 3)) { + line = p + 4; + break; + } + } + } + } + + // copy everything after the encoding + if (line) { + (*outputFunc)(outputStream, line, (int)(((char *)file + len) - line)); + } + } +} + +char *FoFiType1::getNextLine(char *line) { + while (line < (char *)file + len && *line != '\x0a' && *line != '\x0d') { + ++line; + } + if (line < (char *)file + len && *line == '\x0d') { + ++line; + } + if (line < (char *)file + len && *line == '\x0a') { + ++line; + } + if (line >= (char *)file + len) { + return NULL; + } + return line; +} + +void FoFiType1::parse() { + char *line, *line1, *p, *p2; + char buf[256]; + char c; + int n, code, base, i, j; + GBool gotMatrix, startsWithDup, endsWithDup; + + gotMatrix = gFalse; + for (i = 1, line = (char *)file; + i <= 100 && line && (!name || !encoding || !gotMatrix); + ++i) { + + // get font name + if (!name && line + 9 <= (char *)file + len && + !strncmp(line, "/FontName", 9)) { + n = 255; + if (line + n > (char *)file + len) { + n = (int)(((char *)file + len) - line); + } + strncpy(buf, line, n); + buf[n] = '\0'; + if ((p = strchr(buf+9, '/')) && + (p = strtok(p+1, " \t\n\r"))) { + name = copyString(p); + } + line = getNextLine(line); + + // get encoding + } else if (!encoding && line + 30 <= (char *)file + len && + !strncmp(line, "/Encoding StandardEncoding def", 30)) { + encoding = (char **)fofiType1StandardEncoding; + } else if (!encoding && line + 19 <= (char *)file + len && + !strncmp(line, "/Encoding 256 array", 19)) { + encoding = (char **)gmallocn(256, sizeof(char *)); + for (j = 0; j < 256; ++j) { + encoding[j] = NULL; + } + for (j = 0, line = getNextLine(line); + j < 300 && line && (line1 = getNextLine(line)); + ++j, line = line1) { + if ((n = (int)(line1 - line)) > 255) { + n = 255; + } + strncpy(buf, line, n); + buf[n] = '\0'; + for (p = buf; *p == ' ' || *p == '\t'; ++p) ; + endsWithDup = !strncmp(line - 4, "dup\x0a", 4) || + !strncmp(line - 5, "dup\x0d", 4); + startsWithDup = !strncmp(p, "dup", 3); + if (endsWithDup || startsWithDup) { + if (startsWithDup) { + p += 3; + } + while (1) { + for (; *p == ' ' || *p == '\t'; ++p) ; + code = 0; + if (*p == '8' && p[1] == '#') { + base = 8; + p += 2; + } else if (*p >= '0' && *p <= '9') { + base = 10; + } else { + break; + } + for (; *p >= '0' && *p < '0' + base; ++p) { + code = code * base + (*p - '0'); + } + for (; *p == ' ' || *p == '\t'; ++p) ; + if (*p != '/') { + break; + } + ++p; + for (p2 = p; *p2 && *p2 != ' ' && *p2 != '\t'; ++p2) ; + if (code >= 0 && code < 256) { + c = *p2; + *p2 = '\0'; + gfree(encoding[code]); + encoding[code] = copyString(p); + *p2 = c; + } + for (p = p2; *p == ' ' || *p == '\t'; ++p) ; + if (strncmp(p, "put", 3)) { + break; + } + for (p += 3; *p == ' ' || *p == '\t'; ++p) ; + if (strncmp(p, "dup", 3)) { + break; + } + p += 3; + } + } else { + if (strtok(buf, " \t") && + (p = strtok(NULL, " \t\n\r")) && !strcmp(p, "def")) { + break; + } + } + } + //~ check for getinterval/putinterval junk + + } else if (!gotMatrix && line + 11 <= (char *)file + len && + !strncmp(line, "/FontMatrix", 11)) { + n = 255; + if (line + 11 + n > (char *)file + len) { + n = (int)(((char *)file + len) - (line + 11)); + } + strncpy(buf, line + 11, n); + buf[n] = '\0'; + if ((p = strchr(buf, '['))) { + ++p; + if ((p2 = strchr(p, ']'))) { + *p2 = '\0'; + for (j = 0; j < 6; ++j) { + if ((p = strtok(j == 0 ? p : (char *)NULL, " \t\n\r"))) { + fontMatrix[j] = atof(p); + } else { + break; + } + } + } + } + gotMatrix = gTrue; + + } else { + line = getNextLine(line); + } + } + + parsed = gTrue; +} + +// Undo the PFB encoding, i.e., remove the PFB headers. +void FoFiType1::undoPFB() { + GBool ok; + Guchar *file2; + int pos1, pos2, type; + Guint segLen; + + ok = gTrue; + if (getU8(0, &ok) != 0x80 || !ok) { + return; + } + file2 = (Guchar *)gmalloc(len); + pos1 = pos2 = 0; + while (getU8(pos1, &ok) == 0x80 && ok) { + type = getU8(pos1 + 1, &ok); + if (type < 1 || type > 2 || !ok) { + break; + } + segLen = getU32LE(pos1 + 2, &ok); + pos1 += 6; + if (!ok || !checkRegion(pos1, segLen)) { + break; + } + memcpy(file2 + pos2, file + pos1, segLen); + pos1 += segLen; + pos2 += segLen; + } + if (freeFileData) { + gfree(fileData); + } + file = fileData = file2; + freeFileData = gTrue; + len = pos2; +} diff --git a/fofi/FoFiType1.h b/fofi/FoFiType1.h new file mode 100644 index 0000000..4a64f24 --- /dev/null +++ b/fofi/FoFiType1.h @@ -0,0 +1,64 @@ +//======================================================================== +// +// FoFiType1.h +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FOFITYPE1_H +#define FOFITYPE1_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "FoFiBase.h" + +//------------------------------------------------------------------------ +// FoFiType1 +//------------------------------------------------------------------------ + +class FoFiType1: public FoFiBase { +public: + + // Create a FoFiType1 object from a memory buffer. + static FoFiType1 *make(char *fileA, int lenA); + + // Create a FoFiType1 object from a file on disk. + static FoFiType1 *load(char *fileName); + + virtual ~FoFiType1(); + + // Return the font name. + char *getName(); + + // Return the encoding, as an array of 256 names (any of which may + // be NULL). + char **getEncoding(); + + // Return the font matrix as an array of six numbers. + void getFontMatrix(double *mat); + + // Write a version of the Type 1 font file with a new encoding. + void writeEncoded(const char **newEncoding, + FoFiOutputFunc outputFunc, void *outputStream); + +private: + + FoFiType1(char *fileA, int lenA, GBool freeFileDataA); + + char *getNextLine(char *line); + void parse(); + void undoPFB(); + + char *name; + char **encoding; + double fontMatrix[6]; + GBool parsed; +}; + +#endif diff --git a/fofi/FoFiType1C.cc b/fofi/FoFiType1C.cc new file mode 100644 index 0000000..b6a1339 --- /dev/null +++ b/fofi/FoFiType1C.cc @@ -0,0 +1,3405 @@ +//======================================================================== +// +// FoFiType1C.cc +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include "gmem.h" +#include "gmempp.h" +#include "GString.h" +#include "GHash.h" +#include "FoFiEncodings.h" +#include "FoFiType1C.h" + +//------------------------------------------------------------------------ + +static char hexChars[17] = "0123456789ABCDEF"; + +#define type1cSubrRecursionLimit 20 + +//------------------------------------------------------------------------ + +GBool Type1COp::isZero() { + switch (kind) { + case type1COpInteger: return intgr == 0; + case type1COpFloat: return flt == 0; + case type1COpRational: return rat.num == 0; + default: return gFalse; // shouldn't happen + } +} + +GBool Type1COp::isNegative() { + switch (kind) { + case type1COpInteger: + return intgr < 0; + case type1COpFloat: + return flt < 0; + case type1COpRational: + return (rat.num < 0) != (rat.den < 0); + default: + // shouldn't happen + return gFalse; + } +} + +int Type1COp::toInt() { + switch (kind) { + case type1COpInteger: + return intgr; + case type1COpFloat: + if (flt < -2e9 || flt > 2e9) { + return 0; + } + return (int)flt; + case type1COpRational: + if (rat.den == 0) { + return 0; + } + return rat.num / rat.den; + default: + // shouldn't happen + return 0; + } +} + +double Type1COp::toFloat() { + switch (kind) { + case type1COpInteger: + return (double)intgr; + case type1COpFloat: + return flt; + case type1COpRational: + if (rat.den == 0) { + return 0; + } + return (double)rat.num / (double)rat.den; + default: + // shouldn't happen + return 0.0; + } +} + +//------------------------------------------------------------------------ +// FoFiType1C +//------------------------------------------------------------------------ + +FoFiType1C *FoFiType1C::make(char *fileA, int lenA) { + FoFiType1C *ff; + + ff = new FoFiType1C(fileA, lenA, gFalse); + if (!ff->parse()) { + delete ff; + return NULL; + } + return ff; +} + +FoFiType1C *FoFiType1C::load(char *fileName) { + FoFiType1C *ff; + char *fileA; + int lenA; + + if (!(fileA = FoFiBase::readFile(fileName, &lenA))) { + return NULL; + } + ff = new FoFiType1C(fileA, lenA, gTrue); + if (!ff->parse()) { + delete ff; + return NULL; + } + return ff; +} + +FoFiType1C::FoFiType1C(char *fileA, int lenA, GBool freeFileDataA): + FoFiBase(fileA, lenA, freeFileDataA) +{ + name = NULL; + encoding = NULL; + privateDicts = NULL; + fdSelect = NULL; + charset = NULL; +} + +FoFiType1C::~FoFiType1C() { + int i; + + if (name) { + delete name; + } + if (encoding && + encoding != (char **)fofiType1StandardEncoding && + encoding != (char **)fofiType1ExpertEncoding) { + for (i = 0; i < 256; ++i) { + gfree(encoding[i]); + } + gfree(encoding); + } + if (privateDicts) { + gfree(privateDicts); + } + if (fdSelect) { + gfree(fdSelect); + } + if (charset && + charset != fofiType1CISOAdobeCharset && + charset != fofiType1CExpertCharset && + charset != fofiType1CExpertSubsetCharset) { + gfree(charset); + } +} + +char *FoFiType1C::getName() { + return name ? name->getCString() : (char *)NULL; +} + +char **FoFiType1C::getEncoding() { + return encoding; +} + +GString *FoFiType1C::getGlyphName(int gid) { + char buf[256]; + GBool ok; + + ok = gTrue; + getString(charset[gid], buf, &ok); + if (!ok) { + return NULL; + } + return new GString(buf); +} + +GHash *FoFiType1C::getNameToGIDMap() { + GHash *map; + char name[256]; + GBool ok; + int gid; + + map = new GHash(gTrue); + for (gid = 0; gid < nGlyphs; ++gid) { + ok = gTrue; + getString(charset[gid], name, &ok); + if (ok) { + map->add(new GString(name), gid); + } + } + return map; +} + +int *FoFiType1C::getCIDToGIDMap(int *nCIDs) { + int *map; + int n, i; + + // a CID font's top dict has ROS as the first operator + if (topDict.firstOp != 0x0c1e) { + *nCIDs = 0; + return NULL; + } + + // in a CID font, the charset data is the GID-to-CID mapping, so all + // we have to do is reverse it + n = 0; + for (i = 0; i < nGlyphs; ++i) { + if (charset[i] > n) { + n = charset[i]; + } + } + ++n; + map = (int *)gmallocn(n, sizeof(int)); + memset(map, 0, n * sizeof(int)); + for (i = 0; i < nGlyphs; ++i) { + map[charset[i]] = i; + } + *nCIDs = n; + return map; +} + +void FoFiType1C::getFontMatrix(double *mat) { + int i; + + if (topDict.firstOp == 0x0c1e && privateDicts[0].hasFontMatrix) { + if (topDict.hasFontMatrix) { + mat[0] = topDict.fontMatrix[0] * privateDicts[0].fontMatrix[0] + + topDict.fontMatrix[1] * privateDicts[0].fontMatrix[2]; + mat[1] = topDict.fontMatrix[0] * privateDicts[0].fontMatrix[1] + + topDict.fontMatrix[1] * privateDicts[0].fontMatrix[3]; + mat[2] = topDict.fontMatrix[2] * privateDicts[0].fontMatrix[0] + + topDict.fontMatrix[3] * privateDicts[0].fontMatrix[2]; + mat[3] = topDict.fontMatrix[2] * privateDicts[0].fontMatrix[1] + + topDict.fontMatrix[3] * privateDicts[0].fontMatrix[3]; + mat[4] = topDict.fontMatrix[4] * privateDicts[0].fontMatrix[0] + + topDict.fontMatrix[5] * privateDicts[0].fontMatrix[2]; + mat[5] = topDict.fontMatrix[4] * privateDicts[0].fontMatrix[1] + + topDict.fontMatrix[5] * privateDicts[0].fontMatrix[3]; + } else { + for (i = 0; i < 6; ++i) { + mat[i] = privateDicts[0].fontMatrix[i]; + } + } + } else { + for (i = 0; i < 6; ++i) { + mat[i] = topDict.fontMatrix[i]; + } + } +} + +void FoFiType1C::convertToType1(char *psName, const char **newEncoding, + GBool ascii, FoFiOutputFunc outputFunc, + void *outputStream) { + int psNameLen; + Type1CEexecBuf eb; + Type1CIndex subrIdx; + Type1CIndexVal val; + GString *buf; + char buf2[256]; + const char **enc; + GBool ok; + int i; + + if (psName) { + psNameLen = (int)strlen(psName); + } else { + psName = name->getCString(); + psNameLen = name->getLength(); + } + + // write header and font dictionary, up to encoding + ok = gTrue; + (*outputFunc)(outputStream, "%!FontType1-1.0: ", 17); + (*outputFunc)(outputStream, psName, psNameLen); + if (topDict.versionSID != 0) { + getString(topDict.versionSID, buf2, &ok); + (*outputFunc)(outputStream, buf2, (int)strlen(buf2)); + } + (*outputFunc)(outputStream, "\n", 1); + // the dictionary needs room for 12 entries: the following 9, plus + // Private and CharStrings (in the eexec section) and FID (which is + // added by definefont) + (*outputFunc)(outputStream, "12 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontInfo 10 dict dup begin\n", 28); + if (topDict.versionSID != 0) { + (*outputFunc)(outputStream, "/version ", 9); + writePSString(buf2, outputFunc, outputStream); + (*outputFunc)(outputStream, " readonly def\n", 14); + } + if (topDict.noticeSID != 0) { + getString(topDict.noticeSID, buf2, &ok); + (*outputFunc)(outputStream, "/Notice ", 8); + writePSString(buf2, outputFunc, outputStream); + (*outputFunc)(outputStream, " readonly def\n", 14); + } + if (topDict.copyrightSID != 0) { + getString(topDict.copyrightSID, buf2, &ok); + (*outputFunc)(outputStream, "/Copyright ", 11); + writePSString(buf2, outputFunc, outputStream); + (*outputFunc)(outputStream, " readonly def\n", 14); + } + if (topDict.fullNameSID != 0) { + getString(topDict.fullNameSID, buf2, &ok); + (*outputFunc)(outputStream, "/FullName ", 10); + writePSString(buf2, outputFunc, outputStream); + (*outputFunc)(outputStream, " readonly def\n", 14); + } + if (topDict.familyNameSID != 0) { + getString(topDict.familyNameSID, buf2, &ok); + (*outputFunc)(outputStream, "/FamilyName ", 12); + writePSString(buf2, outputFunc, outputStream); + (*outputFunc)(outputStream, " readonly def\n", 14); + } + if (topDict.weightSID != 0) { + getString(topDict.weightSID, buf2, &ok); + (*outputFunc)(outputStream, "/Weight ", 8); + writePSString(buf2, outputFunc, outputStream); + (*outputFunc)(outputStream, " readonly def\n", 14); + } + if (topDict.isFixedPitch) { + (*outputFunc)(outputStream, "/isFixedPitch true def\n", 23); + } else { + (*outputFunc)(outputStream, "/isFixedPitch false def\n", 24); + } + buf = GString::format("/ItalicAngle {0:.4g} def\n", topDict.italicAngle); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format("/UnderlinePosition {0:.4g} def\n", + topDict.underlinePosition); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format("/UnderlineThickness {0:.4g} def\n", + topDict.underlineThickness); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "end readonly def\n", 17); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, psNameLen); + (*outputFunc)(outputStream, " def\n", 5); + buf = GString::format("/PaintType {0:d} def\n", topDict.paintType); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/FontType 1 def\n", 16); + buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] readonly def\n", + topDict.fontMatrix[0], topDict.fontMatrix[1], + topDict.fontMatrix[2], topDict.fontMatrix[3], + topDict.fontMatrix[4], topDict.fontMatrix[5]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] readonly def\n", + topDict.fontBBox[0], topDict.fontBBox[1], + topDict.fontBBox[2], topDict.fontBBox[3]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format("/StrokeWidth {0:.4g} def\n", topDict.strokeWidth); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + if (topDict.uniqueID != 0) { + buf = GString::format("/UniqueID {0:d} def\n", topDict.uniqueID); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + + // write the encoding + (*outputFunc)(outputStream, "/Encoding ", 10); + if (!newEncoding && encoding == (char **)fofiType1StandardEncoding) { + (*outputFunc)(outputStream, "StandardEncoding def\n", 21); + } else { + (*outputFunc)(outputStream, "256 array\n", 10); + (*outputFunc)(outputStream, + "0 1 255 {1 index exch /.notdef put} for\n", 40); + enc = newEncoding ? newEncoding : (const char **)encoding; + for (i = 0; i < 256; ++i) { + if (enc[i]) { + buf = GString::format("dup {0:d} /{1:s} put\n", i, enc[i]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + } + (*outputFunc)(outputStream, "readonly def\n", 13); + } + (*outputFunc)(outputStream, "currentdict end\n", 16); + + // start the binary section + (*outputFunc)(outputStream, "currentfile eexec\n", 18); + eb.outputFunc = outputFunc; + eb.outputStream = outputStream; + eb.ascii = ascii; + eb.r1 = 55665; + eb.line = 0; + + // write the private dictionary + eexecWrite(&eb, "\x83\xca\x73\xd5"); + eexecWrite(&eb, "dup /Private 32 dict dup begin\n"); + eexecWrite(&eb, "/RD {string currentfile exch readstring pop}" + " executeonly def\n"); + eexecWrite(&eb, "/ND {noaccess def} executeonly def\n"); + eexecWrite(&eb, "/NP {noaccess put} executeonly def\n"); + eexecWrite(&eb, "/MinFeature {16 16} def\n"); + eexecWrite(&eb, "/password 5839 def\n"); + if (privateDicts[0].nBlueValues) { + eexecWrite(&eb, "/BlueValues ["); + // number of entries must be even + int n = privateDicts[0].nBlueValues & ~1; + for (i = 0; i < n; ++i) { + buf = GString::format("{0:s}{1:d}", + i > 0 ? " " : "", privateDicts[0].blueValues[i]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].nOtherBlues) { + eexecWrite(&eb, "/OtherBlues ["); + // number of entries must be even + int n = privateDicts[0].nOtherBlues & ~1; + for (i = 0; i < n; ++i) { + buf = GString::format("{0:s}{1:d}", + i > 0 ? " " : "", privateDicts[0].otherBlues[i]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].nFamilyBlues) { + eexecWrite(&eb, "/FamilyBlues ["); + // number of entries must be even + int n = privateDicts[0].nFamilyBlues & ~1; + for (i = 0; i < n; ++i) { + buf = GString::format("{0:s}{1:d}", + i > 0 ? " " : "", privateDicts[0].familyBlues[i]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].nFamilyOtherBlues) { + eexecWrite(&eb, "/FamilyOtherBlues ["); + // number of entries must be even + int n = privateDicts[0].nFamilyOtherBlues & ~1; + for (i = 0; i < n; ++i) { + buf = GString::format("{0:s}{1:d}", i > 0 ? " " : "", + privateDicts[0].familyOtherBlues[i]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].blueScale != 0.039625) { + buf = GString::format("/BlueScale {0:.4g} def\n", + privateDicts[0].blueScale); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].blueShift != 7) { + buf = GString::format("/BlueShift {0:d} def\n", privateDicts[0].blueShift); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].blueFuzz != 1) { + buf = GString::format("/BlueFuzz {0:d} def\n", privateDicts[0].blueFuzz); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].hasStdHW) { + buf = GString::format("/StdHW [{0:.4g}] def\n", privateDicts[0].stdHW); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].hasStdVW) { + buf = GString::format("/StdVW [{0:.4g}] def\n", privateDicts[0].stdVW); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].nStemSnapH) { + // the StemSnapH array should be unique values in ascending order -- + // if not, just skip it + for (i = 1; i < privateDicts[0].nStemSnapH; ++i) { + if (privateDicts[0].stemSnapH[i-1] >= privateDicts[0].stemSnapH[i]) { + break; + } + } + if (i == privateDicts[0].nStemSnapH) { + eexecWrite(&eb, "/StemSnapH ["); + for (i = 0; i < privateDicts[0].nStemSnapH; ++i) { + buf = GString::format("{0:s}{1:.4g}", + i > 0 ? " " : "", privateDicts[0].stemSnapH[i]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + } + if (privateDicts[0].nStemSnapV) { + // the StemSnapV array should be unique values in ascending order -- + // if not, just skip it + for (i = 1; i < privateDicts[0].nStemSnapV; ++i) { + if (privateDicts[0].stemSnapV[i-1] >= privateDicts[0].stemSnapV[i]) { + break; + } + } + if (i == privateDicts[0].nStemSnapV) { + eexecWrite(&eb, "/StemSnapV ["); + for (i = 0; i < privateDicts[0].nStemSnapV; ++i) { + buf = GString::format("{0:s}{1:.4g}", + i > 0 ? " " : "", privateDicts[0].stemSnapV[i]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + } + if (privateDicts[0].hasForceBold) { + buf = GString::format("/ForceBold {0:s} def\n", + privateDicts[0].forceBold ? "true" : "false"); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].forceBoldThreshold != 0) { + buf = GString::format("/ForceBoldThreshold {0:.4g} def\n", + privateDicts[0].forceBoldThreshold); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].languageGroup != 0) { + buf = GString::format("/LanguageGroup {0:d} def\n", + privateDicts[0].languageGroup); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].expansionFactor != 0.06) { + buf = GString::format("/ExpansionFactor {0:.4g} def\n", + privateDicts[0].expansionFactor); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + + // set up subroutines + ok = gTrue; + getIndex(privateDicts[0].subrsOffset, &subrIdx, &ok); + if (!ok) { + subrIdx.pos = -1; + } + + // write the CharStrings + buf = GString::format("2 index /CharStrings {0:d} dict dup begin\n", + nGlyphs); + eexecWrite(&eb, buf->getCString()); + delete buf; + for (i = 0; i < nGlyphs; ++i) { + ok = gTrue; + getIndexVal(&charStringsIdx, i, &val, &ok); + if (ok) { + getString(charset[i], buf2, &ok); + if (ok) { + eexecCvtGlyph(&eb, buf2, val.pos, val.len, &subrIdx, &privateDicts[0]); + } + } + } + eexecWrite(&eb, "end\n"); + eexecWrite(&eb, "end\n"); + eexecWrite(&eb, "readonly put\n"); + eexecWrite(&eb, "noaccess put\n"); + eexecWrite(&eb, "dup /FontName get exch definefont pop\n"); + eexecWrite(&eb, "mark currentfile closefile\n"); + + // trailer + if (ascii && eb.line > 0) { + (*outputFunc)(outputStream, "\n", 1); + } + for (i = 0; i < 8; ++i) { + (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65); + } + (*outputFunc)(outputStream, "cleartomark\n", 12); +} + +void FoFiType1C::convertToCIDType0(char *psName, int *codeMap, int nCodes, + FoFiOutputFunc outputFunc, + void *outputStream) { + int *cidMap; + GString *charStrings; + int *charStringOffsets; + Type1CIndex subrIdx; + Type1CIndexVal val; + int nCIDs, gdBytes; + GString *buf; + char buf2[256]; + GBool ok; + int gid, offset, n, i, j, k; + + // compute the CID count and build the CID-to-GID mapping + if (codeMap) { + nCIDs = nCodes; + cidMap = (int *)gmallocn(nCIDs, sizeof(int)); + for (i = 0; i < nCodes; ++i) { + if (codeMap[i] >= 0 && codeMap[i] < nGlyphs) { + cidMap[i] = codeMap[i]; + } else { + cidMap[i] = -1; + } + } + } else if (topDict.firstOp == 0x0c1e) { + nCIDs = 0; + for (i = 0; i < nGlyphs; ++i) { + if (charset[i] >= nCIDs) { + nCIDs = charset[i] + 1; + } + } + cidMap = (int *)gmallocn(nCIDs, sizeof(int)); + for (i = 0; i < nCIDs; ++i) { + cidMap[i] = -1; + } + for (i = 0; i < nGlyphs; ++i) { + cidMap[charset[i]] = i; + } + } else { + nCIDs = nGlyphs; + cidMap = (int *)gmallocn(nCIDs, sizeof(int)); + for (i = 0; i < nCIDs; ++i) { + cidMap[i] = i; + } + } + + // build the charstrings + charStrings = new GString(); + charStringOffsets = (int *)gmallocn(nCIDs + 1, sizeof(int)); + for (i = 0; i < nCIDs; ++i) { + charStringOffsets[i] = charStrings->getLength(); + if ((gid = cidMap[i]) >= 0) { + ok = gTrue; + getIndexVal(&charStringsIdx, gid, &val, &ok); + if (ok) { + getIndex(privateDicts[fdSelect ? fdSelect[gid] : 0].subrsOffset, + &subrIdx, &ok); + if (!ok) { + subrIdx.pos = -1; + } + cvtGlyph(val.pos, val.len, charStrings, + &subrIdx, &privateDicts[fdSelect ? fdSelect[gid] : 0], + gTrue, 0); + } + } + } + charStringOffsets[nCIDs] = charStrings->getLength(); + + // compute gdBytes = number of bytes needed for charstring offsets + // (offset size needs to account for the charstring offset table, + // with a worst case of five bytes per entry, plus the charstrings + // themselves) + i = (nCIDs + 1) * 5 + charStrings->getLength(); + if (i < 0x100) { + gdBytes = 1; + } else if (i < 0x10000) { + gdBytes = 2; + } else if (i < 0x1000000) { + gdBytes = 3; + } else { + gdBytes = 4; + } + + // begin the font dictionary + (*outputFunc)(outputStream, "/CIDInit /ProcSet findresource begin\n", 37); + (*outputFunc)(outputStream, "20 dict begin\n", 14); + (*outputFunc)(outputStream, "/CIDFontName /", 14); + (*outputFunc)(outputStream, psName, (int)strlen(psName)); + (*outputFunc)(outputStream, " def\n", 5); + (*outputFunc)(outputStream, "/CIDFontType 0 def\n", 19); + (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32); + if (topDict.registrySID > 0 && topDict.orderingSID > 0) { + ok = gTrue; + getString(topDict.registrySID, buf2, &ok); + if (ok) { + (*outputFunc)(outputStream, " /Registry (", 13); + (*outputFunc)(outputStream, buf2, (int)strlen(buf2)); + (*outputFunc)(outputStream, ") def\n", 6); + } + ok = gTrue; + getString(topDict.orderingSID, buf2, &ok); + if (ok) { + (*outputFunc)(outputStream, " /Ordering (", 13); + (*outputFunc)(outputStream, buf2, (int)strlen(buf2)); + (*outputFunc)(outputStream, ") def\n", 6); + } + } else { + (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24); + (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27); + } + buf = GString::format(" /Supplement {0:d} def\n", topDict.supplement); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "end def\n", 8); + if (topDict.hasFontMatrix) { + buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n", + topDict.fontMatrix[0], topDict.fontMatrix[1], + topDict.fontMatrix[2], topDict.fontMatrix[3], + topDict.fontMatrix[4], topDict.fontMatrix[5]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } else if (privateDicts[0].hasFontMatrix) { + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + } else { + (*outputFunc)(outputStream, + "/FontMatrix [0.001 0 0 0.001 0 0] def\n", 38); + } + buf = GString::format("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] def\n", + topDict.fontBBox[0], topDict.fontBBox[1], + topDict.fontBBox[2], topDict.fontBBox[3]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/FontInfo 1 dict dup begin\n", 27); + (*outputFunc)(outputStream, " /FSType 8 def\n", 16); + (*outputFunc)(outputStream, "end def\n", 8); + + // CIDFont-specific entries + buf = GString::format("/CIDCount {0:d} def\n", nCIDs); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/FDBytes 1 def\n", 15); + buf = GString::format("/GDBytes {0:d} def\n", gdBytes); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/CIDMapOffset 0 def\n", 20); + if (topDict.paintType != 0) { + buf = GString::format("/PaintType {0:d} def\n", topDict.paintType); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format("/StrokeWidth {0:.4g} def\n", topDict.strokeWidth); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + + // FDArray entry + buf = GString::format("/FDArray {0:d} array\n", nFDs); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + for (i = 0; i < nFDs; ++i) { + buf = GString::format("dup {0:d} 10 dict begin\n", i); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/FontType 1 def\n", 16); + if (privateDicts[i].hasFontMatrix) { + buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n", + privateDicts[i].fontMatrix[0], + privateDicts[i].fontMatrix[1], + privateDicts[i].fontMatrix[2], + privateDicts[i].fontMatrix[3], + privateDicts[i].fontMatrix[4], + privateDicts[i].fontMatrix[5]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } else { + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + } + buf = GString::format("/PaintType {0:d} def\n", topDict.paintType); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/Private 32 dict begin\n", 23); + if (privateDicts[i].nBlueValues) { + (*outputFunc)(outputStream, "/BlueValues [", 13); + for (j = 0; j < privateDicts[i].nBlueValues; ++j) { + buf = GString::format("{0:s}{1:d}", + j > 0 ? " " : "", privateDicts[i].blueValues[j]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].nOtherBlues) { + (*outputFunc)(outputStream, "/OtherBlues [", 13); + for (j = 0; j < privateDicts[i].nOtherBlues; ++j) { + buf = GString::format("{0:s}{1:d}", + j > 0 ? " " : "", privateDicts[i].otherBlues[j]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].nFamilyBlues) { + (*outputFunc)(outputStream, "/FamilyBlues [", 14); + for (j = 0; j < privateDicts[i].nFamilyBlues; ++j) { + buf = GString::format("{0:s}{1:d}", + j > 0 ? " " : "", + privateDicts[i].familyBlues[j]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].nFamilyOtherBlues) { + (*outputFunc)(outputStream, "/FamilyOtherBlues [", 19); + for (j = 0; j < privateDicts[i].nFamilyOtherBlues; ++j) { + buf = GString::format("{0:s}{1:d}", j > 0 ? " " : "", + privateDicts[i].familyOtherBlues[j]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].blueScale != 0.039625) { + buf = GString::format("/BlueScale {0:.4g} def\n", + privateDicts[i].blueScale); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].blueShift != 7) { + buf = GString::format("/BlueShift {0:d} def\n", + privateDicts[i].blueShift); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].blueFuzz != 1) { + buf = GString::format("/BlueFuzz {0:d} def\n", privateDicts[i].blueFuzz); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].hasStdHW) { + buf = GString::format("/StdHW [{0:.4g}] def\n", privateDicts[i].stdHW); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].hasStdVW) { + buf = GString::format("/StdVW [{0:.4g}] def\n", privateDicts[i].stdVW); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].nStemSnapH) { + // the StemSnapH array should be unique values in ascending order -- + // if not, just skip it + for (j = 1; j < privateDicts[i].nStemSnapH; ++j) { + if (privateDicts[i].stemSnapH[j-1] >= privateDicts[i].stemSnapH[j]) { + break; + } + } + if (j == privateDicts[i].nStemSnapH) { + (*outputFunc)(outputStream, "/StemSnapH [", 12); + for (j = 0; j < privateDicts[i].nStemSnapH; ++j) { + buf = GString::format("{0:s}{1:.4g}", + j > 0 ? " " : "", privateDicts[i].stemSnapH[j]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + } + } + if (privateDicts[i].nStemSnapV) { + // the StemSnapV array should be unique values in ascending order -- + // if not, just skip it + for (j = 1; j < privateDicts[i].nStemSnapV; ++j) { + if (privateDicts[i].stemSnapV[j-1] >= privateDicts[i].stemSnapV[j]) { + break; + } + } + if (j == privateDicts[i].nStemSnapV) { + (*outputFunc)(outputStream, "/StemSnapV [", 12); + for (j = 0; j < privateDicts[i].nStemSnapV; ++j) { + buf = GString::format("{0:s}{1:.4g}", + j > 0 ? " " : "", privateDicts[i].stemSnapV[j]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + } + } + if (privateDicts[i].hasForceBold) { + buf = GString::format("/ForceBold {0:s} def\n", + privateDicts[i].forceBold ? "true" : "false"); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].forceBoldThreshold != 0) { + buf = GString::format("/ForceBoldThreshold {0:.4g} def\n", + privateDicts[i].forceBoldThreshold); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].languageGroup != 0) { + buf = GString::format("/LanguageGroup {0:d} def\n", + privateDicts[i].languageGroup); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].expansionFactor != 0.06) { + buf = GString::format("/ExpansionFactor {0:.4g} def\n", + privateDicts[i].expansionFactor); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "currentdict end def\n", 20); + (*outputFunc)(outputStream, "currentdict end put\n", 20); + } + (*outputFunc)(outputStream, "def\n", 4); + + // start the binary section + offset = (nCIDs + 1) * (1 + gdBytes); + buf = GString::format("(Hex) {0:d} StartData\n", + offset + charStrings->getLength()); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + + // write the charstring offset (CIDMap) table + for (i = 0; i <= nCIDs; i += 6) { + for (j = 0; j < 6 && i+j <= nCIDs; ++j) { + if (i+j < nCIDs && cidMap[i+j] >= 0 && fdSelect) { + buf2[0] = (char)fdSelect[cidMap[i+j]]; + } else { + buf2[0] = (char)0; + } + n = offset + charStringOffsets[i+j]; + for (k = gdBytes; k >= 1; --k) { + buf2[k] = (char)(n & 0xff); + n >>= 8; + } + for (k = 0; k <= gdBytes; ++k) { + buf = GString::format("{0:02x}", buf2[k] & 0xff); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + } + (*outputFunc)(outputStream, "\n", 1); + } + + // write the charstring data + n = charStrings->getLength(); + for (i = 0; i < n; i += 32) { + for (j = 0; j < 32 && i+j < n; ++j) { + buf = GString::format("{0:02x}", charStrings->getChar(i+j) & 0xff); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (i + 32 >= n) { + (*outputFunc)(outputStream, ">", 1); + } + (*outputFunc)(outputStream, "\n", 1); + } + + gfree(charStringOffsets); + delete charStrings; + gfree(cidMap); +} + +void FoFiType1C::convertToType0(char *psName, int *codeMap, int nCodes, + FoFiOutputFunc outputFunc, + void *outputStream) { + int *cidMap; + Type1CIndex subrIdx; + Type1CIndexVal val; + int nCIDs; + GString *buf; + Type1CEexecBuf eb; + GBool ok; + int fd, i, j, k; + + // compute the CID count and build the CID-to-GID mapping + if (codeMap) { + nCIDs = nCodes; + cidMap = (int *)gmallocn(nCIDs, sizeof(int)); + for (i = 0; i < nCodes; ++i) { + if (codeMap[i] >= 0 && codeMap[i] < nGlyphs) { + cidMap[i] = codeMap[i]; + } else { + cidMap[i] = -1; + } + } + } else if (topDict.firstOp == 0x0c1e) { + nCIDs = 0; + for (i = 0; i < nGlyphs; ++i) { + if (charset[i] >= nCIDs) { + nCIDs = charset[i] + 1; + } + } + cidMap = (int *)gmallocn(nCIDs, sizeof(int)); + for (i = 0; i < nCIDs; ++i) { + cidMap[i] = -1; + } + for (i = 0; i < nGlyphs; ++i) { + cidMap[charset[i]] = i; + } + } else { + nCIDs = nGlyphs; + cidMap = (int *)gmallocn(nCIDs, sizeof(int)); + for (i = 0; i < nCIDs; ++i) { + cidMap[i] = i; + } + } + + // write the descendant Type 1 fonts + for (i = 0; i < nCIDs; i += 256) { + + //~ this assumes that all CIDs in this block have the same FD -- + //~ to handle multiple FDs correctly, need to somehow divide the + //~ font up by FD; as a kludge we ignore CID 0, which is .notdef + fd = 0; + // if fdSelect is NULL, we have an 8-bit font, so just leave fd=0 + if (fdSelect) { + for (j = i==0 ? 1 : 0; j < 256 && i+j < nCIDs; ++j) { + if (cidMap[i+j] >= 0) { + fd = fdSelect[cidMap[i+j]]; + break; + } + } + } + if (fd < 0 || fd >= nFDs) { + // this will only happen in a broken/damaged font + fd = 0; + } + + // font dictionary (unencrypted section) + (*outputFunc)(outputStream, "16 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, (int)strlen(psName)); + buf = GString::format("_{0:02x} def\n", i >> 8); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/FontType 1 def\n", 16); + if (privateDicts[fd].hasFontMatrix) { + buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n", + privateDicts[fd].fontMatrix[0], + privateDicts[fd].fontMatrix[1], + privateDicts[fd].fontMatrix[2], + privateDicts[fd].fontMatrix[3], + privateDicts[fd].fontMatrix[4], + privateDicts[fd].fontMatrix[5]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } else if (topDict.hasFontMatrix) { + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + } else { + (*outputFunc)(outputStream, + "/FontMatrix [0.001 0 0 0.001 0 0] def\n", 38); + } + buf = GString::format("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] def\n", + topDict.fontBBox[0], topDict.fontBBox[1], + topDict.fontBBox[2], topDict.fontBBox[3]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format("/PaintType {0:d} def\n", topDict.paintType); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + if (topDict.paintType != 0) { + buf = GString::format("/StrokeWidth {0:.4g} def\n", topDict.strokeWidth); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); + for (j = 0; j < 256 && i+j < nCIDs; ++j) { + buf = GString::format("dup {0:d} /c{1:02x} put\n", j, j); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (j < 256) { + buf = GString::format("{0:d} 1 255 {{ 1 index exch /.notdef put }} for\n", + j); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "readonly def\n", 13); + (*outputFunc)(outputStream, "currentdict end\n", 16); + + // start the binary section + (*outputFunc)(outputStream, "currentfile eexec\n", 18); + eb.outputFunc = outputFunc; + eb.outputStream = outputStream; + eb.ascii = gTrue; + eb.r1 = 55665; + eb.line = 0; + + // start the private dictionary + eexecWrite(&eb, "\x83\xca\x73\xd5"); + eexecWrite(&eb, "dup /Private 32 dict dup begin\n"); + eexecWrite(&eb, "/RD {string currentfile exch readstring pop}" + " executeonly def\n"); + eexecWrite(&eb, "/ND {noaccess def} executeonly def\n"); + eexecWrite(&eb, "/NP {noaccess put} executeonly def\n"); + eexecWrite(&eb, "/MinFeature {16 16} def\n"); + eexecWrite(&eb, "/password 5839 def\n"); + if (privateDicts[fd].nBlueValues) { + eexecWrite(&eb, "/BlueValues ["); + for (k = 0; k < privateDicts[fd].nBlueValues; ++k) { + buf = GString::format("{0:s}{1:d}", + k > 0 ? " " : "", + privateDicts[fd].blueValues[k]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].nOtherBlues) { + eexecWrite(&eb, "/OtherBlues ["); + for (k = 0; k < privateDicts[fd].nOtherBlues; ++k) { + buf = GString::format("{0:s}{1:d}", + k > 0 ? " " : "", + privateDicts[fd].otherBlues[k]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].nFamilyBlues) { + eexecWrite(&eb, "/FamilyBlues ["); + for (k = 0; k < privateDicts[fd].nFamilyBlues; ++k) { + buf = GString::format("{0:s}{1:d}", k > 0 ? " " : "", + privateDicts[fd].familyBlues[k]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].nFamilyOtherBlues) { + eexecWrite(&eb, "/FamilyOtherBlues ["); + for (k = 0; k < privateDicts[fd].nFamilyOtherBlues; ++k) { + buf = GString::format("{0:s}{1:d}", k > 0 ? " " : "", + privateDicts[fd].familyOtherBlues[k]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].blueScale != 0.039625) { + buf = GString::format("/BlueScale {0:.4g} def\n", + privateDicts[fd].blueScale); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].blueShift != 7) { + buf = GString::format("/BlueShift {0:d} def\n", + privateDicts[fd].blueShift); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].blueFuzz != 1) { + buf = GString::format("/BlueFuzz {0:d} def\n", + privateDicts[fd].blueFuzz); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].hasStdHW) { + buf = GString::format("/StdHW [{0:.4g}] def\n", privateDicts[fd].stdHW); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].hasStdVW) { + buf = GString::format("/StdVW [{0:.4g}] def\n", privateDicts[fd].stdVW); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].nStemSnapH) { + // the StemSnapH array should be unique values in ascending order -- + // if not, just skip it + for (k = 1; k < privateDicts[fd].nStemSnapH; ++k) { + if (privateDicts[fd].stemSnapH[k-1] >= privateDicts[fd].stemSnapH[k]) { + break; + } + } + if (k == privateDicts[fd].nStemSnapH) { + eexecWrite(&eb, "/StemSnapH ["); + for (k = 0; k < privateDicts[fd].nStemSnapH; ++k) { + buf = GString::format("{0:s}{1:.4g}", + k > 0 ? " " : "", + privateDicts[fd].stemSnapH[k]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + } + if (privateDicts[fd].nStemSnapV) { + // the StemSnapV array should be unique values in ascending order -- + // if not, just skip it + for (k = 1; k < privateDicts[fd].nStemSnapV; ++k) { + if (privateDicts[fd].stemSnapV[k-1] >= privateDicts[fd].stemSnapV[k]) { + break; + } + } + if (k == privateDicts[fd].nStemSnapV) { + eexecWrite(&eb, "/StemSnapV ["); + for (k = 0; k < privateDicts[fd].nStemSnapV; ++k) { + buf = GString::format("{0:s}{1:.4g}", + k > 0 ? " " : "", + privateDicts[fd].stemSnapV[k]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + } + if (privateDicts[fd].hasForceBold) { + buf = GString::format("/ForceBold {0:s} def\n", + privateDicts[fd].forceBold ? "true" : "false"); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].forceBoldThreshold != 0) { + buf = GString::format("/ForceBoldThreshold {0:.4g} def\n", + privateDicts[fd].forceBoldThreshold); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].languageGroup != 0) { + buf = GString::format("/LanguageGroup {0:d} def\n", + privateDicts[fd].languageGroup); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].expansionFactor != 0.06) { + buf = GString::format("/ExpansionFactor {0:.4g} def\n", + privateDicts[fd].expansionFactor); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + + // set up the subroutines + ok = gTrue; + getIndex(privateDicts[fd].subrsOffset, &subrIdx, &ok); + if (!ok) { + subrIdx.pos = -1; + } + + // start the CharStrings + eexecWrite(&eb, "2 index /CharStrings 256 dict dup begin\n"); + + // write the .notdef CharString + ok = gTrue; + getIndexVal(&charStringsIdx, 0, &val, &ok); + if (ok) { + eexecCvtGlyph(&eb, ".notdef", val.pos, val.len, + &subrIdx, &privateDicts[fd]); + } + + // write the CharStrings + for (j = 0; j < 256 && i+j < nCIDs; ++j) { + if (cidMap[i+j] >= 0) { + ok = gTrue; + getIndexVal(&charStringsIdx, cidMap[i+j], &val, &ok); + if (ok) { + buf = GString::format("c{0:02x}", j); + eexecCvtGlyph(&eb, buf->getCString(), val.pos, val.len, + &subrIdx, &privateDicts[fd]); + delete buf; + } + } + } + eexecWrite(&eb, "end\n"); + eexecWrite(&eb, "end\n"); + eexecWrite(&eb, "readonly put\n"); + eexecWrite(&eb, "noaccess put\n"); + eexecWrite(&eb, "dup /FontName get exch definefont pop\n"); + eexecWrite(&eb, "mark currentfile closefile\n"); + + // trailer + if (eb.line > 0) { + (*outputFunc)(outputStream, "\n", 1); + } + for (j = 0; j < 8; ++j) { + (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65); + } + (*outputFunc)(outputStream, "cleartomark\n", 12); + } + + // write the Type 0 parent font + (*outputFunc)(outputStream, "16 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, (int)strlen(psName)); + (*outputFunc)(outputStream, " def\n", 5); + (*outputFunc)(outputStream, "/FontType 0 def\n", 16); + if (topDict.hasFontMatrix) { + buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n", + topDict.fontMatrix[0], topDict.fontMatrix[1], + topDict.fontMatrix[2], topDict.fontMatrix[3], + topDict.fontMatrix[4], topDict.fontMatrix[5]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } else { + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + } + (*outputFunc)(outputStream, "/FMapType 2 def\n", 16); + (*outputFunc)(outputStream, "/Encoding [\n", 12); + for (i = 0; i < nCIDs; i += 256) { + buf = GString::format("{0:d}\n", i >> 8); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + (*outputFunc)(outputStream, "/FDepVector [\n", 14); + for (i = 0; i < nCIDs; i += 256) { + (*outputFunc)(outputStream, "/", 1); + (*outputFunc)(outputStream, psName, (int)strlen(psName)); + buf = GString::format("_{0:02x} findfont\n", i >> 8); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); + + gfree(cidMap); +} + +void FoFiType1C::eexecCvtGlyph(Type1CEexecBuf *eb, const char *glyphName, + int offset, int nBytes, + Type1CIndex *subrIdx, + Type1CPrivateDict *pDict) { + GString *buf; + GString *charBuf; + + // generate the charstring + charBuf = new GString(); + cvtGlyph(offset, nBytes, charBuf, subrIdx, pDict, gTrue, 0); + + buf = GString::format("/{0:s} {1:d} RD ", glyphName, charBuf->getLength()); + eexecWrite(eb, buf->getCString()); + delete buf; + eexecWriteCharstring(eb, (Guchar *)charBuf->getCString(), + charBuf->getLength()); + eexecWrite(eb, " ND\n"); + + delete charBuf; +} + +void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, + Type1CIndex *subrIdx, Type1CPrivateDict *pDict, + GBool top, int recursion) { + Type1CIndexVal val; + Type1COp zero, tmp; + GBool ok, dInt; + double d, dx, dy; + Gushort r2; + Guchar byte; + int pos, subrBias, start, num, den, i, k; + + if (recursion > type1cSubrRecursionLimit) { + //~ error(-1, "Recursive loop in Type1C glyph"); + return; + } + + start = charBuf->getLength(); + if (top) { + charBuf->append((char)73); + charBuf->append((char)58); + charBuf->append((char)147); + charBuf->append((char)134); + nOps = 0; + nHints = 0; + firstOp = gTrue; + openPath = gFalse; + } + + zero.kind = type1COpInteger; + zero.intgr = 0; + + pos = offset; + while (pos < offset + nBytes) { + ok = gTrue; + pos = getOp(pos, gTrue, &ok); + if (!ok) { + break; + } + if (ops[nOps - 1].kind == type1COpOperator) { + --nOps; // drop the operator + switch (ops[nOps].op) { + case 0x0001: // hstem + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = gFalse; + } + if (nOps & 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hstem", nOps); + } + d = 0; + dInt = gTrue; + for (k = 0; k+1 < nOps; k += 2) { + // convert Type 2 edge hints (-20 or -21) to Type 1 ghost hints + if (ops[k+1].isNegative()) { + d += ops[k].toFloat() + ops[k+1].toFloat(); + dInt &= ops[k].kind == type1COpInteger; + dInt &= ops[k+1].kind == type1COpInteger; + if (dInt) { + tmp.kind = type1COpInteger; + tmp.intgr = (int)(d + 0.5); + } else { + tmp.kind = type1COpFloat; + tmp.flt = d; + } + cvtNum(tmp, charBuf); + if (ops[k+1].kind == type1COpInteger) { + tmp.kind = type1COpInteger; + tmp.intgr = -ops[k+1].intgr; + } else if (ops[k+1].kind == type1COpRational) { + tmp.kind = type1COpRational; + tmp.rat.num = -ops[k+1].rat.num; + tmp.rat.den = ops[k+1].rat.den; + } else { + tmp.kind = type1COpFloat; + tmp.flt = -ops[k+1].toFloat(); + } + cvtNum(tmp, charBuf); + } else { + d += ops[k].toFloat(); + dInt &= ops[k].kind == type1COpInteger; + if (dInt) { + tmp.kind = type1COpInteger; + tmp.intgr = (int)(d + 0.5); + } else { + tmp.kind = type1COpFloat; + tmp.flt = d; + } + cvtNum(tmp, charBuf); + cvtNum(ops[k+1], charBuf); + d += ops[k+1].toFloat(); + dInt &= ops[k+1].kind == type1COpInteger; + } + charBuf->append((char)1); + } + nHints += nOps / 2; + nOps = 0; + break; + case 0x0003: // vstem + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = gFalse; + } + if (nOps & 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 vstem", nOps); + } + d = 0; + dInt = gTrue; + for (k = 0; k+1 < nOps; k += 2) { + // convert Type 2 edge hints (-20 or -21) to Type 1 ghost hints + if (ops[k+1].isNegative()) { + d += ops[k].toFloat() + ops[k+1].toFloat(); + dInt &= ops[k].kind == type1COpInteger; + dInt &= ops[k+1].kind == type1COpInteger; + if (dInt) { + tmp.kind = type1COpInteger; + tmp.intgr = (int)(d + 0.5); + } else { + tmp.kind = type1COpFloat; + tmp.flt = d; + } + cvtNum(tmp, charBuf); + if (ops[k+1].kind == type1COpInteger) { + tmp.kind = type1COpInteger; + tmp.intgr = -ops[k+1].intgr; + } else if (ops[k+1].kind == type1COpRational) { + tmp.kind = type1COpRational; + tmp.rat.num = -ops[k+1].rat.num; + tmp.rat.den = ops[k+1].rat.den; + } else { + tmp.kind = type1COpFloat; + tmp.flt = -ops[k+1].toFloat(); + } + cvtNum(tmp, charBuf); + } else { + d += ops[k].toFloat(); + dInt &= ops[k].kind == type1COpInteger; + if (dInt) { + tmp.kind = type1COpInteger; + tmp.intgr = (int)(d + 0.5); + } else { + tmp.kind = type1COpFloat; + tmp.flt = d; + } + cvtNum(tmp, charBuf); + cvtNum(ops[k+1], charBuf); + d += ops[k+1].toFloat(); + dInt &= ops[k+1].kind == type1COpInteger; + } + charBuf->append((char)3); + } + nHints += nOps / 2; + nOps = 0; + break; + case 0x0004: // vmoveto + if (firstOp) { + cvtGlyphWidth(nOps == 2, charBuf, pDict); + firstOp = gFalse; + } + if (openPath) { + charBuf->append((char)9); + openPath = gFalse; + } + if (nOps != 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps); + } + cvtNum(ops[0], charBuf); + charBuf->append((char)4); + nOps = 0; + break; + case 0x0005: // rlineto + if (nOps < 2 || nOps % 2 != 0) { + //~ error(-1, "Wrong number of args (%d) to Type 2 rlineto", nOps); + } + for (k = 0; k+1 < nOps; k += 2) { + cvtNum(ops[k], charBuf); + cvtNum(ops[k+1], charBuf); + charBuf->append((char)5); + } + nOps = 0; + openPath = gTrue; + break; + case 0x0006: // hlineto + if (nOps < 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hlineto", nOps); + } + for (k = 0; k < nOps; ++k) { + cvtNum(ops[k], charBuf); + charBuf->append((char)((k & 1) ? 7 : 6)); + } + nOps = 0; + openPath = gTrue; + break; + case 0x0007: // vlineto + if (nOps < 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 vlineto", nOps); + } + for (k = 0; k < nOps; ++k) { + cvtNum(ops[k], charBuf); + charBuf->append((char)((k & 1) ? 6 : 7)); + } + nOps = 0; + openPath = gTrue; + break; + case 0x0008: // rrcurveto + if (nOps < 6 || nOps % 6 != 0) { + //~ error(-1, "Wrong number of args (%d) to Type 2 rrcurveto", nOps); + } + for (k = 0; k < nOps; k += 6) { + cvtNum(ops[k], charBuf); + cvtNum(ops[k+1], charBuf); + cvtNum(ops[k+2], charBuf); + cvtNum(ops[k+3], charBuf); + cvtNum(ops[k+4], charBuf); + cvtNum(ops[k+5], charBuf); + charBuf->append((char)8); + } + nOps = 0; + openPath = gTrue; + break; + case 0x000a: // callsubr + if (nOps >= 1) { + subrBias = (subrIdx->len < 1240) + ? 107 : (subrIdx->len < 33900) ? 1131 : 32768; + k = subrBias + ops[nOps - 1].toInt(); + --nOps; + ok = gTrue; + getIndexVal(subrIdx, k, &val, &ok); + if (ok) { + cvtGlyph(val.pos, val.len, charBuf, subrIdx, pDict, gFalse, + recursion + 1); + } + } else { + //~ error(-1, "Too few args to Type 2 callsubr"); + } + // don't clear the stack + break; + case 0x000b: // return + // don't clear the stack + break; + case 0x000e: // endchar / seac + if (firstOp) { + cvtGlyphWidth(nOps == 1 || nOps == 5, charBuf, pDict); + firstOp = gFalse; + } + if (openPath) { + charBuf->append((char)9); + openPath = gFalse; + } + if (nOps == 4) { + cvtNum(zero, charBuf); + cvtNum(ops[0], charBuf); + cvtNum(ops[1], charBuf); + cvtNum(ops[2], charBuf); + cvtNum(ops[3], charBuf); + charBuf->append((char)12)->append((char)6); + } else if (nOps == 0) { + charBuf->append((char)14); + } else { + //~ error(-1, "Wrong number of args (%d) to Type 2 endchar", nOps); + } + nOps = 0; + break; + case 0x000f: // (obsolete) + // this op is ignored, but we need the glyph width + if (firstOp) { + cvtGlyphWidth(nOps > 0, charBuf, pDict); + firstOp = gFalse; + } + nOps = 0; + break; + case 0x0010: // blend + //~ error(-1, "Unimplemented Type 2 charstring op: %d", file[i]); + nOps = 0; + break; + case 0x0012: // hstemhm + // ignored + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = gFalse; + } + if (nOps & 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hstemhm", nOps); + } + nHints += nOps / 2; + nOps = 0; + break; + case 0x0013: // hintmask + // ignored + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = gFalse; + } + if (nOps > 0) { + if (nOps & 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hintmask/vstemhm", + //~ nOps); + } + nHints += nOps / 2; + } + pos += (nHints + 7) >> 3; + nOps = 0; + break; + case 0x0014: // cntrmask + // ignored + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = gFalse; + } + if (nOps > 0) { + if (nOps & 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 cntrmask/vstemhm", + //~ nOps); + } + nHints += nOps / 2; + } + pos += (nHints + 7) >> 3; + nOps = 0; + break; + case 0x0015: // rmoveto + if (firstOp) { + cvtGlyphWidth(nOps == 3, charBuf, pDict); + firstOp = gFalse; + } + if (openPath) { + charBuf->append((char)9); + openPath = gFalse; + } + if (nOps != 2) { + //~ error(-1, "Wrong number of args (%d) to Type 2 rmoveto", nOps); + } + cvtNum(ops[0], charBuf); + cvtNum(ops[1], charBuf); + charBuf->append((char)21); + nOps = 0; + break; + case 0x0016: // hmoveto + if (firstOp) { + cvtGlyphWidth(nOps == 2, charBuf, pDict); + firstOp = gFalse; + } + if (openPath) { + charBuf->append((char)9); + openPath = gFalse; + } + if (nOps != 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hmoveto", nOps); + } + cvtNum(ops[0], charBuf); + charBuf->append((char)22); + nOps = 0; + break; + case 0x0017: // vstemhm + // ignored + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = gFalse; + } + if (nOps & 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 vstemhm", nOps); + } + nHints += nOps / 2; + nOps = 0; + break; + case 0x0018: // rcurveline + if (nOps < 8 || (nOps - 2) % 6 != 0) { + //~ error(-1, "Wrong number of args (%d) to Type 2 rcurveline", nOps); + } + for (k = 0; k <= nOps - 8; k += 6) { + cvtNum(ops[k], charBuf); + cvtNum(ops[k+1], charBuf); + cvtNum(ops[k+2], charBuf); + cvtNum(ops[k+3], charBuf); + cvtNum(ops[k+4], charBuf); + cvtNum(ops[k+5], charBuf); + charBuf->append((char)8); + } + cvtNum(ops[k], charBuf); + cvtNum(ops[k+1], charBuf); + charBuf->append((char)5); + nOps = 0; + openPath = gTrue; + break; + case 0x0019: // rlinecurve + if (nOps < 8 || (nOps - 6) % 2 != 0) { + //~ error(-1, "Wrong number of args (%d) to Type 2 rlinecurve", nOps); + } + for (k = 0; k <= nOps - 8; k += 2) { + cvtNum(ops[k], charBuf); + cvtNum(ops[k+1], charBuf); + charBuf->append((char)5); + } + cvtNum(ops[k], charBuf); + cvtNum(ops[k+1], charBuf); + cvtNum(ops[k+2], charBuf); + cvtNum(ops[k+3], charBuf); + cvtNum(ops[k+4], charBuf); + cvtNum(ops[k+5], charBuf); + charBuf->append((char)8); + nOps = 0; + openPath = gTrue; + break; + case 0x001a: // vvcurveto + if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { + //~ error(-1, "Wrong number of args (%d) to Type 2 vvcurveto", nOps); + } + if (nOps % 2 == 1 && nOps >= 5) { + cvtNum(ops[0], charBuf); + cvtNum(ops[1], charBuf); + cvtNum(ops[2], charBuf); + cvtNum(ops[3], charBuf); + cvtNum(zero, charBuf); + cvtNum(ops[4], charBuf); + charBuf->append((char)8); + k = 5; + } else { + k = 0; + } + for (; k+3 < nOps; k += 4) { + cvtNum(zero, charBuf); + cvtNum(ops[k], charBuf); + cvtNum(ops[k+1], charBuf); + cvtNum(ops[k+2], charBuf); + cvtNum(zero, charBuf); + cvtNum(ops[k+3], charBuf); + charBuf->append((char)8); + } + nOps = 0; + openPath = gTrue; + break; + case 0x001b: // hhcurveto + if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hhcurveto", nOps); + } + if (nOps % 2 == 1 && nOps >= 5) { + cvtNum(ops[1], charBuf); + cvtNum(ops[0], charBuf); + cvtNum(ops[2], charBuf); + cvtNum(ops[3], charBuf); + cvtNum(ops[4], charBuf); + cvtNum(zero, charBuf); + charBuf->append((char)8); + k = 5; + } else { + k = 0; + } + for (; k+3 < nOps; k += 4) { + cvtNum(ops[k], charBuf); + cvtNum(zero, charBuf); + cvtNum(ops[k+1], charBuf); + cvtNum(ops[k+2], charBuf); + cvtNum(ops[k+3], charBuf); + cvtNum(zero, charBuf); + charBuf->append((char)8); + } + nOps = 0; + openPath = gTrue; + break; + case 0x001d: // callgsubr + if (nOps >= 1) { + k = gsubrBias + ops[nOps - 1].toInt(); + --nOps; + ok = gTrue; + getIndexVal(&gsubrIdx, k, &val, &ok); + if (ok) { + cvtGlyph(val.pos, val.len, charBuf, subrIdx, pDict, gFalse, + recursion + 1); + } + } else { + //~ error(-1, "Too few args to Type 2 callgsubr"); + } + // don't clear the stack + break; + case 0x001e: // vhcurveto + if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { + //~ error(-1, "Wrong number of args (%d) to Type 2 vhcurveto", nOps); + } + for (k = 0; k+3 < nOps && k != nOps-5; k += 4) { + if (k % 8 == 0) { + cvtNum(ops[k], charBuf); + cvtNum(ops[k+1], charBuf); + cvtNum(ops[k+2], charBuf); + cvtNum(ops[k+3], charBuf); + charBuf->append((char)30); + } else { + cvtNum(ops[k], charBuf); + cvtNum(ops[k+1], charBuf); + cvtNum(ops[k+2], charBuf); + cvtNum(ops[k+3], charBuf); + charBuf->append((char)31); + } + } + if (k == nOps-5) { + if (k % 8 == 0) { + cvtNum(zero, charBuf); + cvtNum(ops[k], charBuf); + cvtNum(ops[k+1], charBuf); + cvtNum(ops[k+2], charBuf); + cvtNum(ops[k+3], charBuf); + cvtNum(ops[k+4], charBuf); + } else { + cvtNum(ops[k], charBuf); + cvtNum(zero, charBuf); + cvtNum(ops[k+1], charBuf); + cvtNum(ops[k+2], charBuf); + cvtNum(ops[k+4], charBuf); + cvtNum(ops[k+3], charBuf); + } + charBuf->append((char)8); + } + nOps = 0; + openPath = gTrue; + break; + case 0x001f: // hvcurveto + if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hvcurveto", nOps); + } + for (k = 0; k+3 < nOps && k != nOps-5; k += 4) { + if (k % 8 == 0) { + cvtNum(ops[k], charBuf); + cvtNum(ops[k+1], charBuf); + cvtNum(ops[k+2], charBuf); + cvtNum(ops[k+3], charBuf); + charBuf->append((char)31); + } else { + cvtNum(ops[k], charBuf); + cvtNum(ops[k+1], charBuf); + cvtNum(ops[k+2], charBuf); + cvtNum(ops[k+3], charBuf); + charBuf->append((char)30); + } + } + if (k == nOps-5) { + if (k % 8 == 0) { + cvtNum(ops[k], charBuf); + cvtNum(zero, charBuf); + cvtNum(ops[k+1], charBuf); + cvtNum(ops[k+2], charBuf); + cvtNum(ops[k+4], charBuf); + cvtNum(ops[k+3], charBuf); + } else { + cvtNum(zero, charBuf); + cvtNum(ops[k], charBuf); + cvtNum(ops[k+1], charBuf); + cvtNum(ops[k+2], charBuf); + cvtNum(ops[k+3], charBuf); + cvtNum(ops[k+4], charBuf); + } + charBuf->append((char)8); + } + nOps = 0; + openPath = gTrue; + break; + case 0x0c00: // dotsection (should be Type 1 only?) + // ignored + nOps = 0; + break; + case 0x0c0c: // div + if (nOps >= 2) { + num = ops[nOps-2].toInt(); + den = ops[nOps-1].toInt(); + --nOps; + ops[nOps-1].kind = type1COpRational; + ops[nOps-1].rat.num = num; + ops[nOps-1].rat.den = den; + } else { + //~ error(-1, "Wrong number of args (%d) to Type 2 div", nOps); + } + break; + case 0x0c03: // and + case 0x0c04: // or + case 0x0c05: // not + case 0x0c08: // store + case 0x0c09: // abs + case 0x0c0a: // add + case 0x0c0b: // sub + case 0x0c0d: // load + case 0x0c0e: // neg + case 0x0c0f: // eq + case 0x0c12: // drop + case 0x0c14: // put + case 0x0c15: // get + case 0x0c16: // ifelse + case 0x0c17: // random + case 0x0c18: // mul + case 0x0c1a: // sqrt + case 0x0c1b: // dup + case 0x0c1c: // exch + case 0x0c1d: // index + case 0x0c1e: // roll + //~ error(-1, "Unimplemented Type 2 charstring op: 12.%d", file[i+1]); + nOps = 0; + break; + case 0x0c22: // hflex + if (nOps == 7) { + cvtNum(ops[0], charBuf); + cvtNum(zero, charBuf); + cvtNum(ops[1], charBuf); + cvtNum(ops[2], charBuf); + cvtNum(ops[3], charBuf); + cvtNum(zero, charBuf); + charBuf->append((char)8); + cvtNum(ops[4], charBuf); + cvtNum(zero, charBuf); + cvtNum(ops[5], charBuf); + if (ops[2].kind == type1COpInteger) { + tmp.kind = type1COpInteger; + tmp.intgr = -ops[2].intgr; + } else if (ops[2].kind == type1COpRational) { + tmp.kind = type1COpRational; + tmp.rat.num = -ops[2].rat.num; + tmp.rat.den = ops[2].rat.den; + } else { + tmp.kind = type1COpFloat; + tmp.flt = -ops[2].toFloat(); + } + cvtNum(tmp, charBuf); + cvtNum(ops[6], charBuf); + cvtNum(zero, charBuf); + charBuf->append((char)8); + } else { + //~ error(-1, "Wrong number of args (%d) to Type 2 hflex", nOps); + } + nOps = 0; + openPath = gTrue; + break; + case 0x0c23: // flex + if (nOps == 13) { + cvtNum(ops[0], charBuf); + cvtNum(ops[1], charBuf); + cvtNum(ops[2], charBuf); + cvtNum(ops[3], charBuf); + cvtNum(ops[4], charBuf); + cvtNum(ops[5], charBuf); + charBuf->append((char)8); + cvtNum(ops[6], charBuf); + cvtNum(ops[7], charBuf); + cvtNum(ops[8], charBuf); + cvtNum(ops[9], charBuf); + cvtNum(ops[10], charBuf); + cvtNum(ops[11], charBuf); + charBuf->append((char)8); + } else { + //~ error(-1, "Wrong number of args (%d) to Type 2 flex", nOps); + } + nOps = 0; + openPath = gTrue; + break; + case 0x0c24: // hflex1 + if (nOps == 9) { + cvtNum(ops[0], charBuf); + cvtNum(ops[1], charBuf); + cvtNum(ops[2], charBuf); + cvtNum(ops[3], charBuf); + cvtNum(ops[4], charBuf); + cvtNum(zero, charBuf); + charBuf->append((char)8); + cvtNum(ops[5], charBuf); + cvtNum(zero, charBuf); + cvtNum(ops[6], charBuf); + cvtNum(ops[7], charBuf); + cvtNum(ops[8], charBuf); + if (ops[1].kind == type1COpInteger && + ops[3].kind == type1COpInteger && + ops[7].kind == type1COpInteger) { + tmp.kind = type1COpInteger; + tmp.intgr = -(ops[1].intgr + ops[3].intgr + ops[7].intgr); + } else { + tmp.kind = type1COpFloat; + tmp.flt = -(ops[1].toFloat() + ops[3].toFloat() + ops[7].toFloat()); + } + cvtNum(tmp, charBuf); + charBuf->append((char)8); + } else { + //~ error(-1, "Wrong number of args (%d) to Type 2 hflex1", nOps); + } + nOps = 0; + openPath = gTrue; + break; + case 0x0c25: // flex1 + if (nOps == 11) { + cvtNum(ops[0], charBuf); + cvtNum(ops[1], charBuf); + cvtNum(ops[2], charBuf); + cvtNum(ops[3], charBuf); + cvtNum(ops[4], charBuf); + cvtNum(ops[5], charBuf); + charBuf->append((char)8); + cvtNum(ops[6], charBuf); + cvtNum(ops[7], charBuf); + cvtNum(ops[8], charBuf); + cvtNum(ops[9], charBuf); + dx = ops[0].toFloat() + ops[2].toFloat() + ops[4].toFloat() + + ops[6].toFloat() + ops[8].toFloat(); + dy = ops[1].toFloat() + ops[3].toFloat() + ops[5].toFloat() + + ops[7].toFloat() + ops[9].toFloat(); + if (fabs(dx) > fabs(dy)) { + cvtNum(ops[10], charBuf); + if (ops[1].kind == type1COpInteger && + ops[3].kind == type1COpInteger && + ops[5].kind == type1COpInteger && + ops[7].kind == type1COpInteger && + ops[9].kind == type1COpInteger) { + tmp.kind = type1COpInteger; + tmp.intgr = -(int)dy; + } else { + tmp.kind = type1COpFloat; + tmp.flt = -dy; + } + cvtNum(tmp, charBuf); + } else { + if (ops[0].kind == type1COpInteger && + ops[2].kind == type1COpInteger && + ops[4].kind == type1COpInteger && + ops[6].kind == type1COpInteger && + ops[8].kind == type1COpInteger) { + tmp.kind = type1COpInteger; + tmp.intgr = -(int)dx; + } else { + tmp.kind = type1COpFloat; + tmp.flt = -dx; + } + cvtNum(tmp, charBuf); + cvtNum(ops[10], charBuf); + } + charBuf->append((char)8); + } else { + //~ error(-1, "Wrong number of args (%d) to Type 2 flex1", nOps); + } + nOps = 0; + openPath = gTrue; + break; + default: + //~ error(-1, "Illegal Type 2 charstring op: %04x", + //~ ops[nOps].op); + nOps = 0; + break; + } + } + } + + // charstring encryption + if (top) { + r2 = 4330; + for (i = start; i < charBuf->getLength(); ++i) { + byte = (Guchar)(charBuf->getChar(i) ^ (r2 >> 8)); + charBuf->setChar(i, byte); + r2 = (Gushort)((byte + r2) * 52845 + 22719); + } + } +} + +void FoFiType1C::cvtGlyphWidth(GBool useOp, GString *charBuf, + Type1CPrivateDict *pDict) { + Type1COp zero, w; + int i; + + if (useOp) { + if (pDict->nominalWidthXInt & (ops[0].kind == type1COpInteger)) { + w.kind = type1COpInteger; + w.intgr = (int)(pDict->nominalWidthX + ops[0].intgr); + } else { + w.kind = type1COpFloat; + w.flt = pDict->nominalWidthX + ops[0].toFloat(); + } + for (i = 1; i < nOps; ++i) { + ops[i-1] = ops[i]; + } + --nOps; + } else { + if (pDict->defaultWidthXInt) { + w.kind = type1COpInteger; + w.intgr = (int)pDict->defaultWidthX; + } else { + w.kind = type1COpFloat; + w.flt = pDict->defaultWidthX; + } + } + zero.kind = type1COpInteger; + zero.intgr = 0; + cvtNum(zero, charBuf); + cvtNum(w, charBuf); + charBuf->append((char)13); +} + +void FoFiType1C::cvtNum(Type1COp op, GString *charBuf) { + Type1COp tmp; + Guchar buf[12]; + int y, n; + + n = 0; + switch (op.kind) { + case type1COpInteger: + y = op.intgr; + if (y >= -107 && y <= 107) { + buf[0] = (Guchar)(y + 139); + n = 1; + } else if (y > 107 && y <= 1131) { + y -= 108; + buf[0] = (Guchar)((y >> 8) + 247); + buf[1] = (Guchar)(y & 0xff); + n = 2; + } else if (y < -107 && y >= -1131) { + y = -y - 108; + buf[0] = (Guchar)((y >> 8) + 251); + buf[1] = (Guchar)(y & 0xff); + n = 2; + } else { + buf[0] = 255; + buf[1] = (Guchar)(y >> 24); + buf[2] = (Guchar)(y >> 16); + buf[3] = (Guchar)(y >> 8); + buf[4] = (Guchar)y; + n = 5; + } + break; + case type1COpFloat: + if (op.flt >= -32768 && op.flt < 32768) { + y = (int)(op.flt * 256.0); + buf[0] = 255; + buf[1] = (Guchar)(y >> 24); + buf[2] = (Guchar)(y >> 16); + buf[3] = (Guchar)(y >> 8); + buf[4] = (Guchar)y; + buf[5] = 255; + buf[6] = 0; + buf[7] = 0; + buf[8] = 1; + buf[9] = 0; + buf[10] = 12; + buf[11] = 12; + n = 12; + } else { + //~ error(-1, "Type 2 fixed point constant out of range"); + } + break; + case type1COpRational: + tmp.kind = type1COpInteger; + tmp.intgr = op.rat.num; + cvtNum(tmp, charBuf); + tmp.intgr = op.rat.den; + cvtNum(tmp, charBuf); + buf[0] = 0x0c; + buf[1] = 0x0c; + n = 2; + break; + default: // shouldn't happen + break; + } + charBuf->append((char *)buf, n); +} + +void FoFiType1C::eexecWrite(Type1CEexecBuf *eb, const char *s) { + Guchar *p; + Guchar x; + + for (p = (Guchar *)s; *p; ++p) { + x = *p ^ (Guchar)(eb->r1 >> 8); + eb->r1 = (Gushort)((x + eb->r1) * 52845 + 22719); + if (eb->ascii) { + (*eb->outputFunc)(eb->outputStream, &hexChars[x >> 4], 1); + (*eb->outputFunc)(eb->outputStream, &hexChars[x & 0x0f], 1); + eb->line += 2; + if (eb->line == 64) { + (*eb->outputFunc)(eb->outputStream, "\n", 1); + eb->line = 0; + } + } else { + (*eb->outputFunc)(eb->outputStream, (char *)&x, 1); + } + } +} + +void FoFiType1C::eexecWriteCharstring(Type1CEexecBuf *eb, + Guchar *s, int n) { + Guchar x; + int i; + + // eexec encryption + for (i = 0; i < n; ++i) { + x = s[i] ^ (Guchar)(eb->r1 >> 8); + eb->r1 = (Gushort)((x + eb->r1) * 52845 + 22719); + if (eb->ascii) { + (*eb->outputFunc)(eb->outputStream, &hexChars[x >> 4], 1); + (*eb->outputFunc)(eb->outputStream, &hexChars[x & 0x0f], 1); + eb->line += 2; + if (eb->line == 64) { + (*eb->outputFunc)(eb->outputStream, "\n", 1); + eb->line = 0; + } + } else { + (*eb->outputFunc)(eb->outputStream, (char *)&x, 1); + } + } +} + +void FoFiType1C::writePSString(char *s, FoFiOutputFunc outputFunc, + void *outputStream) { + char buf[80]; + char *p; + int i, c; + + i = 0; + buf[i++] = '('; + for (p = s; *p; ++p) { + c = *p & 0xff; + if (c == '(' || c == ')' || c == '\\') { + buf[i++] = '\\'; + buf[i++] = (char)c; + } else if (c < 0x20 || c >= 0x80) { + buf[i++] = '\\'; + buf[i++] = (char)('0' + ((c >> 6) & 7)); + buf[i++] = (char)('0' + ((c >> 3) & 7)); + buf[i++] = (char)('0' + (c & 7)); + } else { + buf[i++] = (char)c; + } + if (i >= 64) { + buf[i++] = '\\'; + buf[i++] = '\n'; + (*outputFunc)(outputStream, buf, i); + i = 0; + } + } + buf[i++] = ')'; + (*outputFunc)(outputStream, buf, i); +} + +void FoFiType1C::convertToOpenType(FoFiOutputFunc outputFunc, + void *outputStream, + int nWidths, Gushort *widths, + Guchar *cmapTable, int cmapTableLen) { + // dummy OS/2 table (taken from FoFiTrueType::writeTTF) + static Guchar os2Tab[86] = { + 0, 1, // version + 0, 1, // xAvgCharWidth + 0x01, 0x90, // usWeightClass + 0, 5, // usWidthClass + 0, 0, // fsType + 0, 0, // ySubscriptXSize + 0, 0, // ySubscriptYSize + 0, 0, // ySubscriptXOffset + 0, 0, // ySubscriptYOffset + 0, 0, // ySuperscriptXSize + 0, 0, // ySuperscriptYSize + 0, 0, // ySuperscriptXOffset + 0, 0, // ySuperscriptYOffset + 0, 0, // yStrikeoutSize + 0, 0, // yStrikeoutPosition + 0, 0, // sFamilyClass + 0, 0, 0, 0, 0, // panose + 0, 0, 0, 0, 0, + 0, 0, 0, 0, // ulUnicodeRange1 + 0, 0, 0, 0, // ulUnicodeRange2 + 0, 0, 0, 0, // ulUnicodeRange3 + 0, 0, 0, 0, // ulUnicodeRange4 + 0, 0, 0, 0, // achVendID + 0, 0, // fsSelection + 0, 0, // usFirstCharIndex + 0, 0, // usLastCharIndex + 0, 0, // sTypoAscender + 0, 0, // sTypoDescender + 0, 0, // sTypoLineGap + 0x20, 0x00, // usWinAscent + 0x20, 0x00, // usWinDescent + 0, 0, 0, 1, // ulCodePageRange1 + 0, 0, 0, 0 // ulCodePageRange2 + }; + Guchar headTable[54], hheaTable[36], maxpTable[6]; + Guchar nameTable[26], postTable[32]; + Guchar *hmtxTable; + static const char *tableTag[9] = { + "CFF ", + "OS/2", + "cmap", + "head", + "hhea", + "hmtx", + "maxp", + "name", + "post" + }; + Guchar *tableData[9]; + int tableLength[9]; + Guchar header[12 + 9*16]; + double mat[6]; + Gushort maxWidth; + Guint checksum, fileChecksum; + int unitsPerEm, xMin, yMin, xMax, yMax, offset, i; + + //--- CFF_ table + tableData[0] = file; + tableLength[0] = len; + + //--- OS/2 table + tableData[1] = os2Tab; + tableLength[1] = 86; + + //--- cmap table + tableData[2] = cmapTable; + tableLength[2] = cmapTableLen; + + //--- head table + getFontMatrix(mat); + if (mat[0] == 0) { + unitsPerEm = 1000; + } else { + unitsPerEm = (int)(1 / mat[0] + 0.5); + } + xMin = (int)(topDict.fontBBox[0] + 0.5); + yMin = (int)(topDict.fontBBox[1] + 0.5); + xMax = (int)(topDict.fontBBox[2] + 0.5); + yMax = (int)(topDict.fontBBox[3] + 0.5); + headTable[ 0] = 0x00; // version + headTable[ 1] = 0x01; + headTable[ 2] = 0x00; + headTable[ 3] = 0x00; + headTable[ 4] = 0x00; // revision + headTable[ 5] = 0x00; + headTable[ 6] = 0x00; + headTable[ 7] = 0x00; + headTable[ 8] = 0x00; // checksumAdjustment + headTable[ 9] = 0x00; // (set later) + headTable[10] = 0x00; + headTable[11] = 0x00; + headTable[12] = 0x5f; // magicNumber + headTable[13] = 0x0f; + headTable[14] = 0x3c; + headTable[15] = 0xf5; + headTable[16] = 0x00; // flags + headTable[17] = 0x03; + headTable[18] = (Guchar)(unitsPerEm >> 8); // unitsPerEm + headTable[19] = (Guchar)unitsPerEm; + headTable[20] = 0x00; // created + headTable[21] = 0x00; + headTable[22] = 0x00; + headTable[23] = 0x00; + headTable[24] = 0x00; + headTable[25] = 0x00; + headTable[26] = 0x00; + headTable[27] = 0x00; + headTable[28] = 0x00; // modified + headTable[29] = 0x00; + headTable[30] = 0x00; + headTable[31] = 0x00; + headTable[32] = 0x00; + headTable[33] = 0x00; + headTable[34] = 0x00; + headTable[35] = 0x00; + headTable[36] = (Guchar)(xMin >> 8); // xMin + headTable[37] = (Guchar)xMin; + headTable[38] = (Guchar)(yMin >> 8); // yMin + headTable[39] = (Guchar)yMin; + headTable[40] = (Guchar)(xMax >> 8); // xMax + headTable[41] = (Guchar)xMax; + headTable[42] = (Guchar)(yMax >> 8); // yMax + headTable[43] = (Guchar)yMax; + headTable[44] = 0; // macStyle + headTable[45] = 0; + headTable[46] = 0; // lowestRecPPEM + headTable[47] = 3; + headTable[48] = 0; // fontDirectionHint + headTable[49] = 2; // (deprecated) + headTable[50] = 0; // indexToLocFormat + headTable[51] = 0; // (n/a to CFF fonts) + headTable[52] = 0; // glyphDataFormat + headTable[53] = 0; // (n/a to CFF fonts) + tableData[3] = headTable; + tableLength[3] = 54; + + //--- hhea table + maxWidth = widths[0]; + for (i = 1; i < nWidths; ++i) { + if (widths[i] > maxWidth) { + maxWidth = widths[i]; + } + } + hheaTable[ 0] = 0x00; // version + hheaTable[ 1] = 0x01; + hheaTable[ 2] = 0x00; + hheaTable[ 3] = 0x00; + hheaTable[ 4] = (Guchar)(yMax >> 8); // ascender + hheaTable[ 5] = (Guchar)yMax; + hheaTable[ 6] = (Guchar)(yMin >> 8); // descender + hheaTable[ 7] = (Guchar)yMin; + hheaTable[ 8] = 0; // lineGap + hheaTable[ 9] = 0; + hheaTable[10] = (Guchar)(maxWidth >> 8); // advanceWidthMax + hheaTable[11] = (Guchar)maxWidth; + hheaTable[12] = 0; // minLeftSideBearing + hheaTable[13] = 0; + hheaTable[14] = 0; // minRightSideBearing + hheaTable[15] = 0; + hheaTable[16] = (Guchar)(maxWidth >> 8); // xMaxExtent + hheaTable[17] = (Guchar)maxWidth; + hheaTable[18] = 0; // caretSlopeRise + hheaTable[19] = 1; + hheaTable[20] = 0; // caretSlopeRun + hheaTable[21] = 0; + hheaTable[22] = 0; // caretOffset + hheaTable[23] = 0; + hheaTable[24] = 0; // reserved + hheaTable[25] = 0; + hheaTable[26] = 0; // reserved + hheaTable[27] = 0; + hheaTable[28] = 0; // reserved + hheaTable[29] = 0; + hheaTable[30] = 0; // reserved + hheaTable[31] = 0; + hheaTable[32] = 0; // metricDataFormat + hheaTable[33] = 0; + hheaTable[34] = (Guchar)(nWidths >> 8); // numberOfHMetrics + hheaTable[35] = (Guchar)nWidths; + tableData[4] = hheaTable; + tableLength[4] = 36; + + //--- hmtx table + //~ this currently sets LSB to 0 for all glyphs + hmtxTable = (Guchar *)gmallocn(nWidths, 4); + for (i = 0; i < nWidths; ++i) { + hmtxTable[4*i ] = (Guchar)(widths[i] >> 8); + hmtxTable[4*i+1] = (Guchar)widths[i]; + hmtxTable[4*i+2] = 0; + hmtxTable[4*i+3] = 0; + } + tableData[5] = hmtxTable; + tableLength[5] = 4 * nWidths; + + //--- maxp table + maxpTable[0] = 0x00; // version = 0.5 + maxpTable[1] = 0x00; + maxpTable[2] = 0x50; + maxpTable[3] = 0x00; + maxpTable[4] = (Guchar)(nGlyphs >> 8); // numGlyphs + maxpTable[5] = (Guchar)nGlyphs; + tableData[6] = maxpTable; + tableLength[6] = 6; + + //--- name table + nameTable[ 0] = 0x00; // format + nameTable[ 1] = 0x00; + nameTable[ 2] = 0x00; // count + nameTable[ 3] = 0x01; + nameTable[ 4] = 0x00; // stringOffset + nameTable[ 5] = 0x12; + nameTable[ 6] = 0x00; // platformID + nameTable[ 7] = 0x00; + nameTable[ 8] = 0x00; // encodingID + nameTable[ 9] = 0x03; + nameTable[10] = 0x00; // languageID + nameTable[11] = 0x00; + nameTable[12] = 0x00; // nameID + nameTable[13] = 0x00; + nameTable[14] = 0x00; // length + nameTable[15] = 0x08; + nameTable[16] = 0x00; // offset + nameTable[17] = 0x00; + nameTable[18] = 0x00; // string data + nameTable[19] = (Guchar)'n'; + nameTable[20] = 0x00; + nameTable[21] = (Guchar)'o'; + nameTable[22] = 0x00; + nameTable[23] = (Guchar)'n'; + nameTable[24] = 0x00; + nameTable[25] = (Guchar)'e'; + tableData[7] = nameTable; + tableLength[7] = 26; + + //--- post table + postTable[ 0] = 0x00; // version = 3.0 + postTable[ 1] = 0x03; + postTable[ 2] = 0x00; + postTable[ 3] = 0x00; + postTable[ 4] = 0x00; // italicAngle + postTable[ 5] = 0x00; + postTable[ 6] = 0x00; + postTable[ 7] = 0x00; + postTable[ 8] = 0x00; // underlinePosition + postTable[ 9] = 0x00; + postTable[10] = 0x00; // underlineThickness + postTable[11] = 0x00; + postTable[12] = 0x00; // isFixedPitch + postTable[13] = 0x00; + postTable[14] = 0x00; + postTable[15] = 0x00; + postTable[16] = 0x00; // minMemType42 + postTable[17] = 0x00; + postTable[18] = 0x00; + postTable[19] = 0x00; + postTable[20] = 0x00; // maxMemType42 + postTable[21] = 0x00; + postTable[22] = 0x00; + postTable[23] = 0x00; + postTable[24] = 0x00; // minMemType1 + postTable[25] = 0x00; + postTable[26] = 0x00; + postTable[27] = 0x00; + postTable[28] = 0x00; // maxMemType1 + postTable[29] = 0x00; + postTable[30] = 0x00; + postTable[31] = 0x00; + tableData[8] = postTable; + tableLength[8] = 32; + + //--- header and table directory + header[ 0] = 'O'; // sfnt version + header[ 1] = 'T'; + header[ 2] = 'T'; + header[ 3] = 'O'; + header[ 4] = 0x00; // numTables + header[ 5] = 0x09; + header[ 6] = 0x00; // searchRange + header[ 7] = 0x80; + header[ 8] = 0x00; // entrySelector + header[ 9] = 0x03; + header[10] = 0x00; // rangeShift + header[11] = 0x10; + offset = 12 + 9*16; + fileChecksum = 0; + for (i = 0; i < 9; ++i) { + header[12 + i*16 + 0] = tableTag[i][0]; + header[12 + i*16 + 1] = tableTag[i][1]; + header[12 + i*16 + 2] = tableTag[i][2]; + header[12 + i*16 + 3] = tableTag[i][3]; + checksum = computeOpenTypeTableChecksum(tableData[i], tableLength[i]); + fileChecksum += checksum; + header[12 + i*16 + 4] = (Guchar)(checksum >> 24); + header[12 + i*16 + 5] = (Guchar)(checksum >> 16); + header[12 + i*16 + 6] = (Guchar)(checksum >> 8); + header[12 + i*16 + 7] = (Guchar)checksum; + header[12 + i*16 + 8] = (Guchar)(offset >> 24); + header[12 + i*16 + 9] = (Guchar)(offset >> 16); + header[12 + i*16 + 10] = (Guchar)(offset >> 8); + header[12 + i*16 + 11] = (Guchar)offset; + header[12 + i*16 + 12] = (Guchar)(tableLength[i] >> 24); + header[12 + i*16 + 13] = (Guchar)(tableLength[i] >> 16); + header[12 + i*16 + 14] = (Guchar)(tableLength[i] >> 8); + header[12 + i*16 + 15] = (Guchar)tableLength[i]; + offset += tableLength[i]; + if (tableLength[i] & 3) { + offset += 4 - (tableLength[i] & 3); + } + } + + //--- file checksum + fileChecksum += computeOpenTypeTableChecksum(header, 12 + 9*16); + fileChecksum = 0xb1b0afba - fileChecksum; + headTable[ 8] = (Guchar)(fileChecksum >> 24); + headTable[ 9] = (Guchar)(fileChecksum >> 16); + headTable[10] = (Guchar)(fileChecksum >> 8); + headTable[11] = (Guchar)fileChecksum; + + //--- write the OpenType font + (*outputFunc)(outputStream, (char *)header, 12 + 9*16); + for (i = 0; i < 9; ++i) { + (*outputFunc)(outputStream, (char *)tableData[i], tableLength[i]); + if (tableLength[i] & 3) { + (*outputFunc)(outputStream, "\0\0\0", 4 - (tableLength[i] & 3)); + } + } + + gfree(hmtxTable); +} + +Guint FoFiType1C::computeOpenTypeTableChecksum(Guchar *data, int length) { + Guint checksum, word; + int i; + + checksum = 0; + for (i = 0; i+3 < length; i += 4) { + word = ((data[i ] & 0xff) << 24) + + ((data[i+1] & 0xff) << 16) + + ((data[i+2] & 0xff) << 8) + + (data[i+3] & 0xff); + checksum += word; + } + if (length & 3) { + word = 0; + i = length & ~3; + switch (length & 3) { + case 3: + word |= (data[i+2] & 0xff) << 8; + case 2: + word |= (data[i+1] & 0xff) << 16; + case 1: + word |= (data[i ] & 0xff) << 24; + break; + } + checksum += word; + } + return checksum; +} + +GBool FoFiType1C::parse() { + Type1CIndex fdIdx; + Type1CIndexVal val; + int i; + + parsedOk = gTrue; + + // some tools embed Type 1C fonts with an extra whitespace char at + // the beginning + if (len > 0 && file[0] != '\x01') { + ++file; + --len; + } + + // find the indexes + getIndex(getU8(2, &parsedOk), &nameIdx, &parsedOk); + getIndex(nameIdx.endPos, &topDictIdx, &parsedOk); + getIndex(topDictIdx.endPos, &stringIdx, &parsedOk); + getIndex(stringIdx.endPos, &gsubrIdx, &parsedOk); + if (!parsedOk) { + return gFalse; + } + gsubrBias = (gsubrIdx.len < 1240) ? 107 + : (gsubrIdx.len < 33900) ? 1131 : 32768; + + // read the first font name + getIndexVal(&nameIdx, 0, &val, &parsedOk); + if (!parsedOk) { + return gFalse; + } + name = new GString((char *)&file[val.pos], val.len); + + // read the top dict for the first font + readTopDict(); + + // for CID fonts: read the FDArray dicts and private dicts + if (topDict.firstOp == 0x0c1e) { + if (topDict.fdArrayOffset == 0) { + nFDs = 1; + privateDicts = (Type1CPrivateDict *)gmalloc(sizeof(Type1CPrivateDict)); + readPrivateDict(0, 0, &privateDicts[0]); + } else { + getIndex(topDict.fdArrayOffset, &fdIdx, &parsedOk); + if (!parsedOk) { + return gFalse; + } + nFDs = fdIdx.len; + privateDicts = (Type1CPrivateDict *) + gmallocn(nFDs, sizeof(Type1CPrivateDict)); + for (i = 0; i < nFDs; ++i) { + getIndexVal(&fdIdx, i, &val, &parsedOk); + if (!parsedOk) { + return gFalse; + } + readFD(val.pos, val.len, &privateDicts[i]); + } + } + + // for 8-bit fonts: read the private dict + } else { + nFDs = 1; + privateDicts = (Type1CPrivateDict *)gmalloc(sizeof(Type1CPrivateDict)); + readPrivateDict(topDict.privateOffset, topDict.privateSize, + &privateDicts[0]); + } + + // check for parse errors in the private dict(s) + if (!parsedOk) { + return gFalse; + } + + // get the charstrings index + if (topDict.charStringsOffset <= 0) { + parsedOk = gFalse; + return gFalse; + } + getIndex(topDict.charStringsOffset, &charStringsIdx, &parsedOk); + if (!parsedOk) { + return gFalse; + } + nGlyphs = charStringsIdx.len; + + // for CID fonts: read the FDSelect table + if (topDict.firstOp == 0x0c1e) { + readFDSelect(); + if (!parsedOk) { + return gFalse; + } + } + + // read the charset + if (!readCharset()) { + parsedOk = gFalse; + return gFalse; + } + + // for 8-bit fonts: build the encoding + if (topDict.firstOp != 0x0c14 && topDict.firstOp != 0x0c1e) { + buildEncoding(); + if (!parsedOk) { + return gFalse; + } + } + + return parsedOk; +} + +void FoFiType1C::readTopDict() { + Type1CIndexVal topDictPtr; + int pos; + + topDict.firstOp = -1; + topDict.versionSID = 0; + topDict.noticeSID = 0; + topDict.copyrightSID = 0; + topDict.fullNameSID = 0; + topDict.familyNameSID = 0; + topDict.weightSID = 0; + topDict.isFixedPitch = 0; + topDict.italicAngle = 0; + topDict.underlinePosition = -100; + topDict.underlineThickness = 50; + topDict.paintType = 0; + topDict.charstringType = 2; + topDict.fontMatrix[0] = 0.001; + topDict.fontMatrix[1] = 0; + topDict.fontMatrix[2] = 0; + topDict.fontMatrix[3] = 0.001; + topDict.fontMatrix[4] = 0; + topDict.fontMatrix[5] = 0; + topDict.hasFontMatrix = gFalse; + topDict.uniqueID = 0; + topDict.fontBBox[0] = 0; + topDict.fontBBox[1] = 0; + topDict.fontBBox[2] = 0; + topDict.fontBBox[3] = 0; + topDict.strokeWidth = 0; + topDict.charsetOffset = 0; + topDict.encodingOffset = 0; + topDict.charStringsOffset = 0; + topDict.privateSize = 0; + topDict.privateOffset = 0; + topDict.registrySID = 0; + topDict.orderingSID = 0; + topDict.supplement = 0; + topDict.fdArrayOffset = 0; + topDict.fdSelectOffset = 0; + + getIndexVal(&topDictIdx, 0, &topDictPtr, &parsedOk); + pos = topDictPtr.pos; + nOps = 0; + while (pos < topDictPtr.pos + topDictPtr.len) { + pos = getOp(pos, gFalse, &parsedOk); + if (!parsedOk) { + break; + } + if (ops[nOps - 1].kind == type1COpOperator) { + --nOps; // drop the operator + if (topDict.firstOp < 0) { + topDict.firstOp = ops[nOps].op; + } + switch (ops[nOps].op) { + case 0x0000: topDict.versionSID = ops[0].toInt(); break; + case 0x0001: topDict.noticeSID = ops[0].toInt(); break; + case 0x0c00: topDict.copyrightSID = ops[0].toInt(); break; + case 0x0002: topDict.fullNameSID = ops[0].toInt(); break; + case 0x0003: topDict.familyNameSID = ops[0].toInt(); break; + case 0x0004: topDict.weightSID = ops[0].toInt(); break; + case 0x0c01: topDict.isFixedPitch = ops[0].toInt(); break; + case 0x0c02: topDict.italicAngle = ops[0].toFloat(); break; + case 0x0c03: topDict.underlinePosition = ops[0].toFloat(); break; + case 0x0c04: topDict.underlineThickness = ops[0].toFloat(); break; + case 0x0c05: topDict.paintType = ops[0].toInt(); break; + case 0x0c06: topDict.charstringType = ops[0].toInt(); break; + case 0x0c07: topDict.fontMatrix[0] = ops[0].toFloat(); + topDict.fontMatrix[1] = ops[1].toFloat(); + topDict.fontMatrix[2] = ops[2].toFloat(); + topDict.fontMatrix[3] = ops[3].toFloat(); + topDict.fontMatrix[4] = ops[4].toFloat(); + topDict.fontMatrix[5] = ops[5].toFloat(); + topDict.hasFontMatrix = gTrue; + break; + case 0x000d: topDict.uniqueID = ops[0].toInt(); break; + case 0x0005: topDict.fontBBox[0] = ops[0].toFloat(); + topDict.fontBBox[1] = ops[1].toFloat(); + topDict.fontBBox[2] = ops[2].toFloat(); + topDict.fontBBox[3] = ops[3].toFloat(); + break; + case 0x0c08: topDict.strokeWidth = ops[0].toFloat(); break; + case 0x000f: topDict.charsetOffset = ops[0].toInt(); break; + case 0x0010: topDict.encodingOffset = ops[0].toInt(); break; + case 0x0011: topDict.charStringsOffset = ops[0].toInt(); break; + case 0x0012: topDict.privateSize = ops[0].toInt(); + topDict.privateOffset = ops[1].toInt(); + break; + case 0x0c1e: topDict.registrySID = ops[0].toInt(); + topDict.orderingSID = ops[1].toInt(); + topDict.supplement = ops[2].toInt(); + break; + case 0x0c24: topDict.fdArrayOffset = ops[0].toInt(); break; + case 0x0c25: topDict.fdSelectOffset = ops[0].toInt(); break; + } + nOps = 0; + } + } +} + +// Read a CID font dict (FD) - this pulls out the private dict +// pointer, and reads the private dict. It also pulls the FontMatrix +// (if any) out of the FD. +void FoFiType1C::readFD(int offset, int length, Type1CPrivateDict *pDict) { + int pos, pSize, pOffset; + double fontMatrix[6]; + GBool hasFontMatrix; + + hasFontMatrix = gFalse; + fontMatrix[0] = fontMatrix[1] = fontMatrix[2] = 0; // make gcc happy + fontMatrix[3] = fontMatrix[4] = fontMatrix[5] = 0; + pSize = pOffset = 0; + pos = offset; + nOps = 0; + while (pos < offset + length) { + pos = getOp(pos, gFalse, &parsedOk); + if (!parsedOk) { + return; + } + if (ops[nOps - 1].kind == type1COpOperator) { + if (ops[nOps - 1].op == 0x0012) { + if (nOps < 3) { + parsedOk = gFalse; + return; + } + pSize = ops[0].toInt(); + pOffset = ops[1].toInt(); + break; + } else if (ops[nOps - 1].op == 0x0c07) { + fontMatrix[0] = ops[0].toFloat(); + fontMatrix[1] = ops[1].toFloat(); + fontMatrix[2] = ops[2].toFloat(); + fontMatrix[3] = ops[3].toFloat(); + fontMatrix[4] = ops[4].toFloat(); + fontMatrix[5] = ops[5].toFloat(); + hasFontMatrix = gTrue; + } + nOps = 0; + } + } + readPrivateDict(pOffset, pSize, pDict); + if (hasFontMatrix) { + pDict->fontMatrix[0] = fontMatrix[0]; + pDict->fontMatrix[1] = fontMatrix[1]; + pDict->fontMatrix[2] = fontMatrix[2]; + pDict->fontMatrix[3] = fontMatrix[3]; + pDict->fontMatrix[4] = fontMatrix[4]; + pDict->fontMatrix[5] = fontMatrix[5]; + pDict->hasFontMatrix = gTrue; + } +} + +void FoFiType1C::readPrivateDict(int offset, int length, + Type1CPrivateDict *pDict) { + int pos; + + pDict->hasFontMatrix = gFalse; + pDict->nBlueValues = 0; + pDict->nOtherBlues = 0; + pDict->nFamilyBlues = 0; + pDict->nFamilyOtherBlues = 0; + pDict->blueScale = 0.039625; + pDict->blueShift = 7; + pDict->blueFuzz = 1; + pDict->hasStdHW = gFalse; + pDict->hasStdVW = gFalse; + pDict->nStemSnapH = 0; + pDict->nStemSnapV = 0; + pDict->hasForceBold = gFalse; + pDict->forceBoldThreshold = 0; + pDict->languageGroup = 0; + pDict->expansionFactor = 0.06; + pDict->initialRandomSeed = 0; + pDict->subrsOffset = 0; + pDict->defaultWidthX = 0; + pDict->defaultWidthXInt = gTrue; + pDict->nominalWidthX = 0; + pDict->nominalWidthXInt = gTrue; + + // no dictionary + if (offset == 0 || length == 0) { + return; + } + + pos = offset; + nOps = 0; + while (pos < offset + length) { + pos = getOp(pos, gFalse, &parsedOk); + if (!parsedOk) { + break; + } + if (ops[nOps - 1].kind == type1COpOperator) { + --nOps; // drop the operator + switch (ops[nOps].op) { + case 0x0006: + pDict->nBlueValues = getDeltaIntArray(pDict->blueValues, + type1CMaxBlueValues); + break; + case 0x0007: + pDict->nOtherBlues = getDeltaIntArray(pDict->otherBlues, + type1CMaxOtherBlues); + break; + case 0x0008: + pDict->nFamilyBlues = getDeltaIntArray(pDict->familyBlues, + type1CMaxBlueValues); + break; + case 0x0009: + pDict->nFamilyOtherBlues = getDeltaIntArray(pDict->familyOtherBlues, + type1CMaxOtherBlues); + break; + case 0x0c09: + pDict->blueScale = ops[0].toFloat(); + break; + case 0x0c0a: + pDict->blueShift = ops[0].toInt(); + break; + case 0x0c0b: + pDict->blueFuzz = ops[0].toInt(); + break; + case 0x000a: + pDict->stdHW = ops[0].toFloat(); + pDict->hasStdHW = gTrue; + break; + case 0x000b: + pDict->stdVW = ops[0].toFloat(); + pDict->hasStdVW = gTrue; + break; + case 0x0c0c: + pDict->nStemSnapH = getDeltaFPArray(pDict->stemSnapH, + type1CMaxStemSnap); + break; + case 0x0c0d: + pDict->nStemSnapV = getDeltaFPArray(pDict->stemSnapV, + type1CMaxStemSnap); + break; + case 0x0c0e: + pDict->forceBold = !ops[0].isZero(); + pDict->hasForceBold = gTrue; + break; + case 0x0c0f: + pDict->forceBoldThreshold = ops[0].toFloat(); + break; + case 0x0c11: + pDict->languageGroup = ops[0].toInt(); + break; + case 0x0c12: + pDict->expansionFactor = ops[0].toFloat(); + break; + case 0x0c13: + pDict->initialRandomSeed = ops[0].toInt(); + break; + case 0x0013: + pDict->subrsOffset = offset + ops[0].toInt(); + break; + case 0x0014: + pDict->defaultWidthX = ops[0].toFloat(); + pDict->defaultWidthXInt = ops[0].kind == type1COpInteger; + break; + case 0x0015: + pDict->nominalWidthX = ops[0].toFloat(); + pDict->nominalWidthXInt = ops[0].kind == type1COpInteger; + break; + } + nOps = 0; + } + } +} + +void FoFiType1C::readFDSelect() { + int fdSelectFmt, pos, nRanges, gid0, gid1, fd, i, j; + + fdSelect = (Guchar *)gmalloc(nGlyphs); + for (i = 0; i < nGlyphs; ++i) { + fdSelect[i] = 0; + } + if (topDict.fdSelectOffset != 0) { + pos = topDict.fdSelectOffset; + fdSelectFmt = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + if (fdSelectFmt == 0) { + if (!checkRegion(pos, nGlyphs)) { + parsedOk = gFalse; + return; + } + for (gid0 = 0; gid0 < nGlyphs; ++gid0) { + if (file[pos + gid0] >= nFDs) { + //~ error(-1, "Bad FDSelect table in CID font"); + parsedOk = gFalse; + return; + } + fdSelect[gid0] = file[pos + gid0]; + } + } else if (fdSelectFmt == 3) { + nRanges = getU16BE(pos, &parsedOk); + pos += 2; + gid0 = getU16BE(pos, &parsedOk); + pos += 2; + for (i = 1; i <= nRanges; ++i) { + fd = getU8(pos++, &parsedOk); + gid1 = getU16BE(pos, &parsedOk); + if (!parsedOk) { + return; + } + pos += 2; + if (gid0 > gid1 || gid1 > nGlyphs || fd >= nFDs) { + //~ error(-1, "Bad FDSelect table in CID font"); + parsedOk = gFalse; + return; + } + for (j = gid0; j < gid1; ++j) { + fdSelect[j] = (Guchar)fd; + } + gid0 = gid1; + } + } else { + //~ error(-1, "Unknown FDSelect table format in CID font"); + } + } +} + +void FoFiType1C::buildEncoding() { + char buf[256]; + int nCodes, nRanges, encFormat; + int pos, c, sid, nLeft, nSups, i, j; + + if (topDict.encodingOffset == 0) { + encoding = (char **)fofiType1StandardEncoding; + + } else if (topDict.encodingOffset == 1) { + encoding = (char **)fofiType1ExpertEncoding; + + } else { + encoding = (char **)gmallocn(256, sizeof(char *)); + for (i = 0; i < 256; ++i) { + encoding[i] = NULL; + } + pos = topDict.encodingOffset; + encFormat = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + if ((encFormat & 0x7f) == 0) { + nCodes = 1 + getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + if (nCodes > nGlyphs) { + nCodes = nGlyphs; + } + for (i = 1; i < nCodes; ++i) { + c = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + if (encoding[c]) { + gfree(encoding[c]); + } + encoding[c] = copyString(getString(charset[i], buf, &parsedOk)); + } + } else if ((encFormat & 0x7f) == 1) { + nRanges = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + nCodes = 1; + for (i = 0; i < nRanges; ++i) { + c = getU8(pos++, &parsedOk); + nLeft = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) { + if (c < 256) { + if (encoding[c]) { + gfree(encoding[c]); + } + encoding[c] = copyString(getString(charset[nCodes], buf, + &parsedOk)); + } + ++nCodes; + ++c; + } + } + } + if (encFormat & 0x80) { + nSups = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + for (i = 0; i < nSups; ++i) { + c = getU8(pos++, &parsedOk);; + if (!parsedOk) { + return;; + } + sid = getU16BE(pos, &parsedOk); + pos += 2; + if (!parsedOk) { + return; + } + if (encoding[c]) { + gfree(encoding[c]); + } + encoding[c] = copyString(getString(sid, buf, &parsedOk)); + } + } + } +} + +GBool FoFiType1C::readCharset() { + int charsetFormat, c, pos; + int nLeft, i, j; + + if (topDict.charsetOffset == 0) { + charset = fofiType1CISOAdobeCharset; + if (nGlyphs > 229) { + nGlyphs = 229; + } + } else if (topDict.charsetOffset == 1) { + charset = fofiType1CExpertCharset; + if (nGlyphs > 166) { + nGlyphs = 166; + } + } else if (topDict.charsetOffset == 2) { + charset = fofiType1CExpertSubsetCharset; + if (nGlyphs > 87) { + nGlyphs = 87; + } + } else { + charset = (Gushort *)gmallocn(nGlyphs, sizeof(Gushort)); + for (i = 0; i < nGlyphs; ++i) { + charset[i] = 0; + } + pos = topDict.charsetOffset; + charsetFormat = getU8(pos++, &parsedOk); + if (charsetFormat == 0) { + for (i = 1; i < nGlyphs; ++i) { + charset[i] = (Gushort)getU16BE(pos, &parsedOk); + pos += 2; + if (!parsedOk) { + break; + } + } + } else if (charsetFormat == 1) { + i = 1; + while (i < nGlyphs) { + c = getU16BE(pos, &parsedOk); + pos += 2; + nLeft = getU8(pos++, &parsedOk); + if (!parsedOk) { + break; + } + for (j = 0; j <= nLeft && i < nGlyphs; ++j) { + charset[i++] = (Gushort)c++; + } + } + } else if (charsetFormat == 2) { + i = 1; + while (i < nGlyphs) { + c = getU16BE(pos, &parsedOk); + pos += 2; + nLeft = getU16BE(pos, &parsedOk); + pos += 2; + if (!parsedOk) { + break; + } + for (j = 0; j <= nLeft && i < nGlyphs; ++j) { + charset[i++] = (Gushort)c++; + } + } + } + if (!parsedOk) { + gfree(charset); + charset = NULL; + return gFalse; + } + } + return gTrue; +} + +int FoFiType1C::getOp(int pos, GBool charstring, GBool *ok) { + static char nybChars[16] = "0123456789.ee -"; + Type1COp op; + char buf[65]; + int b0, b1, nyb0, nyb1, x, i; + + b0 = getU8(pos++, ok); + + if (b0 == 28) { + x = getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + if (x & 0x8000) { + x |= ~0xffff; + } + op.kind = type1COpInteger; + op.intgr = x; + + } else if (!charstring && b0 == 29) { + x = getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + if (x & 0x80000000) { + x |= ~0xffffffff; + } + op.kind = type1COpInteger; + op.intgr = x; + + } else if (!charstring && b0 == 30) { + i = 0; + do { + b1 = getU8(pos++, ok); + nyb0 = b1 >> 4; + nyb1 = b1 & 0x0f; + if (nyb0 == 0xf) { + break; + } + buf[i++] = nybChars[nyb0]; + if (i == 64) { + break; + } + if (nyb0 == 0xc) { + buf[i++] = '-'; + } + if (i == 64) { + break; + } + if (nyb1 == 0xf) { + break; + } + buf[i++] = nybChars[nyb1]; + if (i == 64) { + break; + } + if (nyb1 == 0xc) { + buf[i++] = '-'; + } + } while (i < 64); + buf[i] = '\0'; + op.kind = type1COpFloat; + op.flt = atof(buf); + + } else if (b0 >= 32 && b0 <= 246) { + op.kind = type1COpInteger; + op.intgr = b0 - 139; + + } else if (b0 >= 247 && b0 <= 250) { + op.kind = type1COpInteger; + op.intgr = ((b0 - 247) << 8) + getU8(pos++, ok) + 108; + + } else if (b0 >= 251 && b0 <= 254) { + op.kind = type1COpInteger; + op.intgr = -((b0 - 251) << 8) - getU8(pos++, ok) - 108; + + } else if (charstring && b0 == 255) { + x = getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + if (x & 0x80000000) { + x |= ~0xffffffff; + } + op.kind = type1COpFloat; + op.flt = (double)x / 65536.0; + + } else if (b0 == 12) { + op.kind = type1COpOperator; + op.op = 0x0c00 + getU8(pos++, ok); + + } else { + op.kind = type1COpOperator; + op.op = b0; + } + + if (nOps < 49) { + ops[nOps++] = op; + } + + return pos; +} + +// Convert the delta-encoded ops array to an array of ints. +int FoFiType1C::getDeltaIntArray(int *arr, int maxLen) { + int x; + int n, i; + + if ((n = nOps) > maxLen) { + n = maxLen; + } + x = 0; + for (i = 0; i < n; ++i) { + x += ops[i].toInt(); + arr[i] = x; + } + return n; +} + +// Convert the delta-encoded ops array to an array of doubles. +int FoFiType1C::getDeltaFPArray(double *arr, int maxLen) { + double x; + int n, i; + + if ((n = nOps) > maxLen) { + n = maxLen; + } + x = 0; + for (i = 0; i < n; ++i) { + x += ops[i].toFloat(); + arr[i] = x; + } + return n; +} + +void FoFiType1C::getIndex(int pos, Type1CIndex *idx, GBool *ok) { + idx->pos = pos; + idx->len = getU16BE(pos, ok); + if (idx->len == 0) { + // empty indexes are legal and contain just the length field + idx->offSize = 0; + idx->startPos = idx->endPos = pos + 2; + } else { + idx->offSize = getU8(pos + 2, ok); + if (idx->offSize < 1 || idx->offSize > 4) { + *ok = gFalse; + } + idx->startPos = pos + 3 + (idx->len + 1) * idx->offSize - 1; + if (idx->startPos < 0 || idx->startPos >= len) { + *ok = gFalse; + } + idx->endPos = idx->startPos + getUVarBE(pos + 3 + idx->len * idx->offSize, + idx->offSize, ok); + if (idx->endPos < idx->startPos || idx->endPos > len) { + *ok = gFalse; + } + } +} + +void FoFiType1C::getIndexVal(Type1CIndex *idx, int i, + Type1CIndexVal *val, GBool *ok) { + int pos0, pos1; + + if (i < 0 || i >= idx->len) { + val->pos = 0; + val->len = 0; + *ok = gFalse; + return; + } + pos0 = idx->startPos + getUVarBE(idx->pos + 3 + i * idx->offSize, + idx->offSize, ok); + pos1 = idx->startPos + getUVarBE(idx->pos + 3 + (i + 1) * idx->offSize, + idx->offSize, ok); + if (pos0 < idx->startPos || pos0 > idx->endPos || + pos1 <= idx->startPos || pos1 > idx->endPos || + pos1 < pos0) { + *ok = gFalse; + } + val->pos = pos0; + val->len = pos1 - pos0; +} + +char *FoFiType1C::getString(int sid, char *buf, GBool *ok) { + Type1CIndexVal val; + int n; + + if (sid < 0) { + buf[0] = '\0'; + } else if (sid < 391) { + strcpy(buf, fofiType1CStdStrings[sid]); + } else { + sid -= 391; + getIndexVal(&stringIdx, sid, &val, ok); + if (*ok) { + if ((n = val.len) > 255) { + n = 255; + } + strncpy(buf, (char *)&file[val.pos], n); + buf[n] = '\0'; + } else { + buf[0] = '\0'; + } + } + return buf; +} diff --git a/fofi/FoFiType1C.h b/fofi/FoFiType1C.h new file mode 100644 index 0000000..15a823c --- /dev/null +++ b/fofi/FoFiType1C.h @@ -0,0 +1,281 @@ +//======================================================================== +// +// FoFiType1C.h +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FOFITYPE1C_H +#define FOFITYPE1C_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "FoFiBase.h" + +class GHash; +class GString; + +//------------------------------------------------------------------------ + +struct Type1CIndex { + int pos; // absolute position in file + int len; // length (number of entries) + int offSize; // offset size + int startPos; // position of start of index data - 1 + int endPos; // position one byte past end of the index +}; + +struct Type1CIndexVal { + int pos; // absolute position in file + int len; // length, in bytes +}; + +struct Type1CTopDict { + int firstOp; + + int versionSID; + int noticeSID; + int copyrightSID; + int fullNameSID; + int familyNameSID; + int weightSID; + int isFixedPitch; + double italicAngle; + double underlinePosition; + double underlineThickness; + int paintType; + int charstringType; + double fontMatrix[6]; + GBool hasFontMatrix; // CID fonts are allowed to put their + // FontMatrix in the FD instead of the + // top dict + int uniqueID; + double fontBBox[4]; + double strokeWidth; + int charsetOffset; + int encodingOffset; + int charStringsOffset; + int privateSize; + int privateOffset; + + // CIDFont entries + int registrySID; + int orderingSID; + int supplement; + int fdArrayOffset; + int fdSelectOffset; +}; + +#define type1CMaxBlueValues 14 +#define type1CMaxOtherBlues 10 +#define type1CMaxStemSnap 12 + +struct Type1CPrivateDict { + double fontMatrix[6]; + GBool hasFontMatrix; + int blueValues[type1CMaxBlueValues]; + int nBlueValues; + int otherBlues[type1CMaxOtherBlues]; + int nOtherBlues; + int familyBlues[type1CMaxBlueValues]; + int nFamilyBlues; + int familyOtherBlues[type1CMaxOtherBlues]; + int nFamilyOtherBlues; + double blueScale; + int blueShift; + int blueFuzz; + double stdHW; + GBool hasStdHW; + double stdVW; + GBool hasStdVW; + double stemSnapH[type1CMaxStemSnap]; + int nStemSnapH; + double stemSnapV[type1CMaxStemSnap]; + int nStemSnapV; + GBool forceBold; + GBool hasForceBold; + double forceBoldThreshold; + int languageGroup; + double expansionFactor; + int initialRandomSeed; + int subrsOffset; + double defaultWidthX; + GBool defaultWidthXInt; + double nominalWidthX; + GBool nominalWidthXInt; +}; + +// operand kind +enum Type1COpKind { + type1COpOperator, + type1COpInteger, + type1COpFloat, + type1COpRational +}; + +// operand +struct Type1COp { + Type1COpKind kind; + union { + int op; // type1COpOperator + int intgr; // type1COpInteger + double flt; // type1COpFloat + struct { + int num, den; // type1COpRational + } rat; + }; + GBool isZero(); + GBool isNegative(); + int toInt(); + double toFloat(); +}; + +struct Type1CEexecBuf { + FoFiOutputFunc outputFunc; + void *outputStream; + GBool ascii; // ASCII encoding? + Gushort r1; // eexec encryption key + int line; // number of eexec chars left on current line +}; + +//------------------------------------------------------------------------ +// FoFiType1C +//------------------------------------------------------------------------ + +class FoFiType1C: public FoFiBase { +public: + + // Create a FoFiType1C object from a memory buffer. + static FoFiType1C *make(char *fileA, int lenA); + + // Create a FoFiType1C object from a file on disk. + static FoFiType1C *load(char *fileName); + + virtual ~FoFiType1C(); + + // Return the font name. + char *getName(); + + // Return the encoding, as an array of 256 names (any of which may + // be NULL). This is only useful with 8-bit fonts. + char **getEncoding(); + + // Get the glyph names. + int getNumGlyphs() { return nGlyphs; } + GString *getGlyphName(int gid); + + // Returns a hash mapping glyph names to GIDs. This is only useful + // with 8-bit fonts. + GHash *getNameToGIDMap(); + + // Return the mapping from CIDs to GIDs, and return the number of + // CIDs in *<nCIDs>. This is only useful for CID fonts. + int *getCIDToGIDMap(int *nCIDs); + + // Return the font matrix as an array of six numbers. + void getFontMatrix(double *mat); + + // Convert to a Type 1 font, suitable for embedding in a PostScript + // file. This is only useful with 8-bit fonts. If <newEncoding> is + // not NULL, it will be used in place of the encoding in the Type 1C + // font. If <ascii> is true the eexec section will be hex-encoded, + // otherwise it will be left as binary data. If <psName> is non-NULL, + // it will be used as the PostScript font name. + void convertToType1(char *psName, const char **newEncoding, GBool ascii, + FoFiOutputFunc outputFunc, void *outputStream); + + // Convert to a Type 0 CIDFont, suitable for embedding in a + // PostScript file. <psName> will be used as the PostScript font + // name. There are three cases for the CID-to-GID mapping: + // (1) if <codeMap> is non-NULL, then it is the CID-to-GID mapping + // (2) if <codeMap> is NULL and this is a CID CFF font, then the + // font's internal CID-to-GID mapping is used + // (3) is <codeMap> is NULL and this is an 8-bit CFF font, then + // the identity CID-to-GID mapping is used + void convertToCIDType0(char *psName, int *codeMap, int nCodes, + FoFiOutputFunc outputFunc, void *outputStream); + + // Convert to a Type 0 (but non-CID) composite font, suitable for + // embedding in a PostScript file. <psName> will be used as the + // PostScript font name. There are three cases for the CID-to-GID + // mapping: + // (1) if <codeMap> is non-NULL, then it is the CID-to-GID mapping + // (2) if <codeMap> is NULL and this is a CID CFF font, then the + // font's internal CID-to-GID mapping is used + // (3) is <codeMap> is NULL and this is an 8-bit CFF font, then + // the identity CID-to-GID mapping is used + void convertToType0(char *psName, int *codeMap, int nCodes, + FoFiOutputFunc outputFunc, void *outputStream); + + // Write an OpenType file, encapsulating the CFF font. <widths> + // provides the glyph widths (in design units) for <nWidths> glyphs. + // The cmap table must be supplied by the caller. + void convertToOpenType(FoFiOutputFunc outputFunc, void *outputStream, + int nWidths, Gushort *widths, + Guchar *cmapTable, int cmapTableLen); + +private: + + FoFiType1C(char *fileA, int lenA, GBool freeFileDataA); + void eexecCvtGlyph(Type1CEexecBuf *eb, const char *glyphName, + int offset, int nBytes, + Type1CIndex *subrIdx, + Type1CPrivateDict *pDict); + void cvtGlyph(int offset, int nBytes, GString *charBuf, + Type1CIndex *subrIdx, Type1CPrivateDict *pDict, + GBool top, int recursion); + void cvtGlyphWidth(GBool useOp, GString *charBuf, + Type1CPrivateDict *pDict); + void cvtNum(Type1COp op, GString *charBuf); + void eexecWrite(Type1CEexecBuf *eb, const char *s); + void eexecWriteCharstring(Type1CEexecBuf *eb, Guchar *s, int n); + void writePSString(char *s, FoFiOutputFunc outputFunc, void *outputStream); + Guint computeOpenTypeTableChecksum(Guchar *data, int length); + GBool parse(); + void readTopDict(); + void readFD(int offset, int length, Type1CPrivateDict *pDict); + void readPrivateDict(int offset, int length, Type1CPrivateDict *pDict); + void readFDSelect(); + void buildEncoding(); + GBool readCharset(); + int getOp(int pos, GBool charstring, GBool *ok); + int getDeltaIntArray(int *arr, int maxLen); + int getDeltaFPArray(double *arr, int maxLen); + void getIndex(int pos, Type1CIndex *idx, GBool *ok); + void getIndexVal(Type1CIndex *idx, int i, Type1CIndexVal *val, GBool *ok); + char *getString(int sid, char *buf, GBool *ok); + + GString *name; + char **encoding; + + Type1CIndex nameIdx; + Type1CIndex topDictIdx; + Type1CIndex stringIdx; + Type1CIndex gsubrIdx; + Type1CIndex charStringsIdx; + + Type1CTopDict topDict; + Type1CPrivateDict *privateDicts; + + int nGlyphs; + int nFDs; + Guchar *fdSelect; + Gushort *charset; + int gsubrBias; + + GBool parsedOk; + + Type1COp ops[49]; // operands and operator + int nOps; // number of operands + int nHints; // number of hints for the current glyph + GBool firstOp; // true if we haven't hit the first op yet + GBool openPath; // true if there is an unclosed path +}; + +#endif diff --git a/fofi/Makefile b/fofi/Makefile new file mode 100644 index 0000000..95b56dc --- /dev/null +++ b/fofi/Makefile @@ -0,0 +1,415 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.18 + +# Default target executed when no arguments are given to make. +default_target: all + +.PHONY : default_target + +# Allow only one "make -f Makefile2" at a time, but pass parallelism. +.NOTPARALLEL: + + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + + +# Disable VCS-based implicit rules. +% : %,v + + +# Disable VCS-based implicit rules. +% : RCS/% + + +# Disable VCS-based implicit rules. +% : RCS/%,v + + +# Disable VCS-based implicit rules. +% : SCCS/s.% + + +# Disable VCS-based implicit rules. +% : s.% + + +.SUFFIXES: .hpux_make_needs_suffix_list + + +# Command-line flag to silence nested $(MAKE). +$(VERBOSE)MAKESILENT = -s + +#Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: + +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E rm -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/calvin/src/xpdf-4.04 + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/calvin/src/xpdf-4.04 + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target install/strip +install/strip: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip + +# Special rule for the target install/strip +install/strip/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip/fast + +# Special rule for the target install/local +install/local: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local + +# Special rule for the target install/local +install/local/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local/fast + +# Special rule for the target install +install: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /usr/bin/cmake -P cmake_install.cmake +.PHONY : install + +# Special rule for the target install +install/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /usr/bin/cmake -P cmake_install.cmake +.PHONY : install/fast + +# Special rule for the target list_install_components +list_install_components: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\"" +.PHONY : list_install_components + +# Special rule for the target list_install_components +list_install_components/fast: list_install_components + +.PHONY : list_install_components/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /usr/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache + +.PHONY : rebuild_cache/fast + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..." + /usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache + +.PHONY : edit_cache/fast + +# The main all target +all: cmake_check_build_system + cd /home/calvin/src/xpdf-4.04 && $(CMAKE_COMMAND) -E cmake_progress_start /home/calvin/src/xpdf-4.04/CMakeFiles /home/calvin/src/xpdf-4.04/fofi//CMakeFiles/progress.marks + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 fofi/all + $(CMAKE_COMMAND) -E cmake_progress_start /home/calvin/src/xpdf-4.04/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 fofi/clean +.PHONY : clean + +# The main clean target +clean/fast: clean + +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 fofi/preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 fofi/preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + cd /home/calvin/src/xpdf-4.04 && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +# Convenience name for target. +fofi/CMakeFiles/fofi.dir/rule: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 fofi/CMakeFiles/fofi.dir/rule +.PHONY : fofi/CMakeFiles/fofi.dir/rule + +# Convenience name for target. +fofi: fofi/CMakeFiles/fofi.dir/rule + +.PHONY : fofi + +# fast build rule for target. +fofi/fast: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f fofi/CMakeFiles/fofi.dir/build.make fofi/CMakeFiles/fofi.dir/build +.PHONY : fofi/fast + +# Convenience name for target. +fofi/CMakeFiles/fofi_objs.dir/rule: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 fofi/CMakeFiles/fofi_objs.dir/rule +.PHONY : fofi/CMakeFiles/fofi_objs.dir/rule + +# Convenience name for target. +fofi_objs: fofi/CMakeFiles/fofi_objs.dir/rule + +.PHONY : fofi_objs + +# fast build rule for target. +fofi_objs/fast: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f fofi/CMakeFiles/fofi_objs.dir/build.make fofi/CMakeFiles/fofi_objs.dir/build +.PHONY : fofi_objs/fast + +FoFiBase.o: FoFiBase.cc.o + +.PHONY : FoFiBase.o + +# target to build an object file +FoFiBase.cc.o: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f fofi/CMakeFiles/fofi_objs.dir/build.make fofi/CMakeFiles/fofi_objs.dir/FoFiBase.cc.o +.PHONY : FoFiBase.cc.o + +FoFiBase.i: FoFiBase.cc.i + +.PHONY : FoFiBase.i + +# target to preprocess a source file +FoFiBase.cc.i: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f fofi/CMakeFiles/fofi_objs.dir/build.make fofi/CMakeFiles/fofi_objs.dir/FoFiBase.cc.i +.PHONY : FoFiBase.cc.i + +FoFiBase.s: FoFiBase.cc.s + +.PHONY : FoFiBase.s + +# target to generate assembly for a file +FoFiBase.cc.s: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f fofi/CMakeFiles/fofi_objs.dir/build.make fofi/CMakeFiles/fofi_objs.dir/FoFiBase.cc.s +.PHONY : FoFiBase.cc.s + +FoFiEncodings.o: FoFiEncodings.cc.o + +.PHONY : FoFiEncodings.o + +# target to build an object file +FoFiEncodings.cc.o: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f fofi/CMakeFiles/fofi_objs.dir/build.make fofi/CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.o +.PHONY : FoFiEncodings.cc.o + +FoFiEncodings.i: FoFiEncodings.cc.i + +.PHONY : FoFiEncodings.i + +# target to preprocess a source file +FoFiEncodings.cc.i: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f fofi/CMakeFiles/fofi_objs.dir/build.make fofi/CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.i +.PHONY : FoFiEncodings.cc.i + +FoFiEncodings.s: FoFiEncodings.cc.s + +.PHONY : FoFiEncodings.s + +# target to generate assembly for a file +FoFiEncodings.cc.s: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f fofi/CMakeFiles/fofi_objs.dir/build.make fofi/CMakeFiles/fofi_objs.dir/FoFiEncodings.cc.s +.PHONY : FoFiEncodings.cc.s + +FoFiIdentifier.o: FoFiIdentifier.cc.o + +.PHONY : FoFiIdentifier.o + +# target to build an object file +FoFiIdentifier.cc.o: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f fofi/CMakeFiles/fofi_objs.dir/build.make fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.o +.PHONY : FoFiIdentifier.cc.o + +FoFiIdentifier.i: FoFiIdentifier.cc.i + +.PHONY : FoFiIdentifier.i + +# target to preprocess a source file +FoFiIdentifier.cc.i: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f fofi/CMakeFiles/fofi_objs.dir/build.make fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.i +.PHONY : FoFiIdentifier.cc.i + +FoFiIdentifier.s: FoFiIdentifier.cc.s + +.PHONY : FoFiIdentifier.s + +# target to generate assembly for a file +FoFiIdentifier.cc.s: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f fofi/CMakeFiles/fofi_objs.dir/build.make fofi/CMakeFiles/fofi_objs.dir/FoFiIdentifier.cc.s +.PHONY : FoFiIdentifier.cc.s + +FoFiTrueType.o: FoFiTrueType.cc.o + +.PHONY : FoFiTrueType.o + +# target to build an object file +FoFiTrueType.cc.o: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f fofi/CMakeFiles/fofi_objs.dir/build.make fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.o +.PHONY : FoFiTrueType.cc.o + +FoFiTrueType.i: FoFiTrueType.cc.i + +.PHONY : FoFiTrueType.i + +# target to preprocess a source file +FoFiTrueType.cc.i: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f fofi/CMakeFiles/fofi_objs.dir/build.make fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.i +.PHONY : FoFiTrueType.cc.i + +FoFiTrueType.s: FoFiTrueType.cc.s + +.PHONY : FoFiTrueType.s + +# target to generate assembly for a file +FoFiTrueType.cc.s: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f fofi/CMakeFiles/fofi_objs.dir/build.make fofi/CMakeFiles/fofi_objs.dir/FoFiTrueType.cc.s +.PHONY : FoFiTrueType.cc.s + +FoFiType1.o: FoFiType1.cc.o + +.PHONY : FoFiType1.o + +# target to build an object file +FoFiType1.cc.o: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f fofi/CMakeFiles/fofi_objs.dir/build.make fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.o +.PHONY : FoFiType1.cc.o + +FoFiType1.i: FoFiType1.cc.i + +.PHONY : FoFiType1.i + +# target to preprocess a source file +FoFiType1.cc.i: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f fofi/CMakeFiles/fofi_objs.dir/build.make fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.i +.PHONY : FoFiType1.cc.i + +FoFiType1.s: FoFiType1.cc.s + +.PHONY : FoFiType1.s + +# target to generate assembly for a file +FoFiType1.cc.s: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f fofi/CMakeFiles/fofi_objs.dir/build.make fofi/CMakeFiles/fofi_objs.dir/FoFiType1.cc.s +.PHONY : FoFiType1.cc.s + +FoFiType1C.o: FoFiType1C.cc.o + +.PHONY : FoFiType1C.o + +# target to build an object file +FoFiType1C.cc.o: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f fofi/CMakeFiles/fofi_objs.dir/build.make fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.o +.PHONY : FoFiType1C.cc.o + +FoFiType1C.i: FoFiType1C.cc.i + +.PHONY : FoFiType1C.i + +# target to preprocess a source file +FoFiType1C.cc.i: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f fofi/CMakeFiles/fofi_objs.dir/build.make fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.i +.PHONY : FoFiType1C.cc.i + +FoFiType1C.s: FoFiType1C.cc.s + +.PHONY : FoFiType1C.s + +# target to generate assembly for a file +FoFiType1C.cc.s: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f fofi/CMakeFiles/fofi_objs.dir/build.make fofi/CMakeFiles/fofi_objs.dir/FoFiType1C.cc.s +.PHONY : FoFiType1C.cc.s + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... edit_cache" + @echo "... install" + @echo "... install/local" + @echo "... install/strip" + @echo "... list_install_components" + @echo "... rebuild_cache" + @echo "... fofi" + @echo "... fofi_objs" + @echo "... FoFiBase.o" + @echo "... FoFiBase.i" + @echo "... FoFiBase.s" + @echo "... FoFiEncodings.o" + @echo "... FoFiEncodings.i" + @echo "... FoFiEncodings.s" + @echo "... FoFiIdentifier.o" + @echo "... FoFiIdentifier.i" + @echo "... FoFiIdentifier.s" + @echo "... FoFiTrueType.o" + @echo "... FoFiTrueType.i" + @echo "... FoFiTrueType.s" + @echo "... FoFiType1.o" + @echo "... FoFiType1.i" + @echo "... FoFiType1.s" + @echo "... FoFiType1C.o" + @echo "... FoFiType1C.i" + @echo "... FoFiType1C.s" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + cd /home/calvin/src/xpdf-4.04 && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/fofi/cmake_install.cmake b/fofi/cmake_install.cmake new file mode 100644 index 0000000..99e1905 --- /dev/null +++ b/fofi/cmake_install.cmake @@ -0,0 +1,44 @@ +# Install script for directory: /home/calvin/src/xpdf-4.04/fofi + +# Set the install prefix +if(NOT DEFINED CMAKE_INSTALL_PREFIX) + set(CMAKE_INSTALL_PREFIX "/usr/local") +endif() +string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + +# Set the install configuration name. +if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + if(BUILD_TYPE) + string(REGEX REPLACE "^[^A-Za-z0-9_]+" "" + CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") + else() + set(CMAKE_INSTALL_CONFIG_NAME "") + endif() + message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") +endif() + +# Set the component getting installed. +if(NOT CMAKE_INSTALL_COMPONENT) + if(COMPONENT) + message(STATUS "Install component: \"${COMPONENT}\"") + set(CMAKE_INSTALL_COMPONENT "${COMPONENT}") + else() + set(CMAKE_INSTALL_COMPONENT) + endif() +endif() + +# Install shared libraries without execute permission? +if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE) + set(CMAKE_INSTALL_SO_NO_EXE "1") +endif() + +# Is this installation the result of a crosscompile? +if(NOT DEFINED CMAKE_CROSSCOMPILING) + set(CMAKE_CROSSCOMPILING "FALSE") +endif() + +# Set default install directory permissions. +if(NOT DEFINED CMAKE_OBJDUMP) + set(CMAKE_OBJDUMP "/usr/bin/objdump") +endif() + diff --git a/fofi/libfofi.a b/fofi/libfofi.a Binary files differnew file mode 100644 index 0000000..0eb6473 --- /dev/null +++ b/fofi/libfofi.a |