diff --git a/Cargo.lock b/Cargo.lock index f2f21c761c..25d8e3f313 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -452,6 +452,18 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +[[package]] +name = "filetime" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "redox_syscall", + "winapi 0.3.9", +] + [[package]] name = "flate2" version = "1.0.14" @@ -1663,6 +1675,7 @@ dependencies = [ "cc", "cfg-if 1.0.0", "error-chain", + "filetime", "flate2", "fs2", "futures", diff --git a/Cargo.toml b/Cargo.toml index bdc85c2bda..a5c1414d28 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,6 +79,7 @@ profile = [] # libz-sys = "^1.0" [dev-dependencies] +filetime = "^0.2" futures = "0.1" headers = "0.2" hyper = "0.12" @@ -87,7 +88,7 @@ tokio = "0.1.22" [package.metadata.vcpkg] git = "https://github.com/microsoft/vcpkg" -rev = "76a7e9248fb3c57350b559966dcaa2d52a5e4458" +rev = "527c0e04332db88a7906e469dca1d9f0a35726fc" [package.metadata.vcpkg.target] x86_64-apple-darwin = { install = ["freetype","harfbuzz[icu,graphite2]"] } diff --git a/build.rs b/build.rs index 3a084889fe..a2319d1b8a 100644 --- a/build.rs +++ b/build.rs @@ -318,6 +318,7 @@ fn main() { .file("tectonic/dpx-mem.c") .file("tectonic/dpx-mfileio.c") .file("tectonic/dpx-mpost.c") + .file("tectonic/dpx-mt19937ar.c") .file("tectonic/dpx-numbers.c") .file("tectonic/dpx-otl_conf.c") .file("tectonic/dpx-otl_opt.c") diff --git a/dist/azure-ci-cd.yml b/dist/azure-ci-cd.yml index 8fd386405b..5523154f99 100644 --- a/dist/azure-ci-cd.yml +++ b/dist/azure-ci-cd.yml @@ -80,12 +80,15 @@ parameters: TARGET: x86_64-apple-darwin TOOLCHAIN: stable - - name: windows - vmImage: windows-2019 - params: {} - vars: - TARGET: x86_64-pc-windows-msvc - TOOLCHAIN: stable-x86_64-pc-windows-msvc + # Temporarily disabled due to vcpkg brokenness that looks like it + # will take a little while to resolve. Tracking issue: + # https://github.com/tectonic-typesetting/tectonic/issues/668 + # - name: windows + # vmImage: windows-2019 + # params: {} + # vars: + # TARGET: x86_64-pc-windows-msvc + # TOOLCHAIN: stable-x86_64-pc-windows-msvc - name: crossBuilds type: object diff --git a/reference_sources b/reference_sources index 3b4ae66327..1d798f0f22 160000 --- a/reference_sources +++ b/reference_sources @@ -1 +1 @@ -Subproject commit 3b4ae66327b096970333eacde19118e07322bf66 +Subproject commit 1d798f0f2253cfdb6ea908e0ba4d721b5ec7d860 diff --git a/src/bin/tectonic.rs b/src/bin/tectonic.rs index 9277642647..7d5901141c 100644 --- a/src/bin/tectonic.rs +++ b/src/bin/tectonic.rs @@ -195,7 +195,7 @@ fn inner(args: CliOptions, config: PersistentConfig, status: &mut dyn StatusBack engine ); - status.dump_error_logs(&output); + status.dump_error_logs(&output.data); } } } diff --git a/src/driver.rs b/src/driver.rs index 4e7c45598e..385cb819e7 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -18,18 +18,25 @@ use std::fs::File; use std::io::Write; use std::path::{Path, PathBuf}; use std::rc::Rc; +use std::result::Result as StdResult; use std::str::FromStr; use std::time::SystemTime; -use crate::digest::DigestData; -use crate::engines::IoEventBackend; -use crate::errors::{ErrorKind, Result, ResultExt}; -use crate::io::{Bundle, InputOrigin, IoProvider, IoSetup, IoSetupBuilder, OpenResult}; -use crate::status::StatusBackend; -use crate::unstable_opts::UnstableOptions; -use crate::{ctry, errmsg, tt_error, tt_note, tt_warning}; -use crate::{BibtexEngine, Spx2HtmlEngine, TexEngine, TexResult, XdvipdfmxEngine}; -use std::result::Result as StdResult; +use crate::{ + ctry, + digest::DigestData, + engines::IoEventBackend, + errmsg, + errors::{ErrorKind, Result, ResultExt}, + io::{ + memory::MemoryFileCollection, Bundle, InputOrigin, IoProvider, IoSetup, IoSetupBuilder, + OpenResult, + }, + status::StatusBackend, + tt_error, tt_note, tt_warning, + unstable_opts::UnstableOptions, + BibtexEngine, Spx2HtmlEngine, TexEngine, TexResult, XdvipdfmxEngine, +}; /// Different patterns with which files may have been accessed by the /// underlying engines. Once a file is marked as ReadThenWritten or @@ -845,7 +852,7 @@ impl ProcessingSession { let mut n_skipped_intermediates = 0; - for (name, contents) in &*self.io.mem.files.borrow() { + for (name, file) in &*self.io.mem.files.borrow() { if name == self.io.mem.stdout_key() { continue; } @@ -882,7 +889,7 @@ impl ProcessingSession { continue; } - if contents.is_empty() { + if file.data.is_empty() { status.note_highlighted( "Not writing ", &format!("`{}`", sname), @@ -892,7 +899,7 @@ impl ProcessingSession { } let real_path = root.join(name); - let byte_len = Byte::from_bytes(contents.len() as u128); + let byte_len = Byte::from_bytes(file.data.len() as u128); status.note_highlighted( "Writing ", &format!("`{}`", real_path.to_string_lossy()), @@ -900,7 +907,7 @@ impl ProcessingSession { ); let mut f = File::create(&real_path)?; - f.write_all(contents)?; + f.write_all(&file.data)?; summ.got_written_to_disk = true; if let Some(ref mut mf_dest) = mf_dest_maybe { @@ -1009,10 +1016,10 @@ impl ProcessingSession { .files .borrow() .get(&self.tex_aux_path) - .map(|data| { + .map(|file| { // We used to use aho-corasick crate here, but it was removed to reduce the code // size. - data.windows(BIBDATA.len()).any(|s| s == BIBDATA) + file.data.windows(BIBDATA.len()).any(|s| s == BIBDATA) }) .unwrap_or(false) } @@ -1081,7 +1088,7 @@ impl ProcessingSession { let format_cache = &mut *self.io.format_cache.as_mut().unwrap(); - for (name, contents) in &*self.io.mem.files.borrow() { + for (name, file) in &*self.io.mem.files.borrow() { if name == self.io.mem.stdout_key() { continue; } @@ -1093,7 +1100,7 @@ impl ProcessingSession { } // Note that we intentionally pass 'stem', not 'name'. - ctry!(format_cache.write_format(stem, contents, status); "cannot write format file {}", sname); + ctry!(format_cache.write_format(stem, &file.data, status); "cannot write format file {}", sname); } // All done. Clear the memory layer since this was a special preparatory step. @@ -1229,7 +1236,7 @@ impl ProcessingSession { /// This will panic if you there are multiple strong references to the /// `files` map. This should only happen if you create and keep a clone of /// the `Rc<>` wrapping it before calling this function. - pub fn into_file_data(self) -> HashMap> { + pub fn into_file_data(self) -> MemoryFileCollection { Rc::try_unwrap(self.io.mem.files) .expect("multiple strong refs to MemoryIo files") .into_inner() diff --git a/src/engines/mod.rs b/src/engines/mod.rs index 842b1c1b26..260192b35d 100644 --- a/src/engines/mod.rs +++ b/src/engines/mod.rs @@ -418,6 +418,23 @@ impl<'a> ExecutionState<'a> { } } + fn input_get_mtime(&mut self, handle: *mut InputHandle) -> libc::time_t { + let rhandle: &mut InputHandle = unsafe { &mut *handle }; + let maybe_time = match rhandle.get_unix_mtime() { + Ok(t) => t, + Err(e) => { + tt_warning!(self.status, "failed to get the modification time of an input"; e); + Some(0) + } + }; + + if let Some(t) = maybe_time { + t as libc::time_t + } else { + 1 // Intentionally make this distinguishable from the error value 0 + } + } + fn input_seek(&mut self, handle: *mut InputHandle, pos: SeekFrom) -> Result { let rhandle: &mut InputHandle = unsafe { &mut *handle }; rhandle.try_seek(pos) @@ -697,6 +714,14 @@ pub extern "C" fn input_get_size( es.input_get_size(handle) } +#[no_mangle] +pub extern "C" fn input_get_mtime( + es: &mut ExecutionState, + handle: *mut InputHandle, +) -> libc::time_t { + es.input_get_mtime(handle) +} + #[no_mangle] pub extern "C" fn input_seek( es: &mut ExecutionState, diff --git a/src/engines/tex.rs b/src/engines/tex.rs index d9bc06f3f2..2a9c8d54aa 100644 --- a/src/engines/tex.rs +++ b/src/engines/tex.rs @@ -126,10 +126,16 @@ impl TexEngine { unsafe { super::tt_xetex_set_int_variable(b"shell_escape_enabled\0".as_ptr() as _, v); } - let v = if self.halt_on_error { 1 } else { 0 }; + + let mut halt_on_error = self.halt_on_error; + if unstables.continue_on_errors { + halt_on_error = false; // command-line override + } + let v = if halt_on_error { 1 } else { 0 }; unsafe { super::tt_xetex_set_int_variable(b"halt_on_error_p\0".as_ptr() as _, v); } + let v = if self.initex_mode { 1 } else { 0 }; unsafe { super::tt_xetex_set_int_variable(b"in_initex_mode\0".as_ptr() as _, v); diff --git a/src/errors.rs b/src/errors.rs index 028913a97b..2431a679b4 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -63,6 +63,7 @@ error_chain! { Reqwest(reqwest::Error); ConfigRead(ReadError); ConfigWrite(WriteError); + Time(std::time::SystemTimeError); Utf8(str::Utf8Error); Xdv(tectonic_xdv::XdvError); Zip(ZipError); diff --git a/src/io/filesystem.rs b/src/io/filesystem.rs index 4aadc58807..2b3210b36a 100644 --- a/src/io/filesystem.rs +++ b/src/io/filesystem.rs @@ -161,6 +161,15 @@ impl InputFeatures for File { Ok(self.metadata()?.len() as usize) } + fn get_unix_mtime(&mut self) -> Result> { + let sys_time = self.metadata()?.modified()?; + + // No cleaner way to convert a SystemTime to time_t, as far as I can + // tell. + let dur = sys_time.duration_since(std::time::SystemTime::UNIX_EPOCH)?; + Ok(Some(dur.as_secs() as i64)) + } + fn try_seek(&mut self, pos: SeekFrom) -> Result { Ok(self.seek(pos)?) } @@ -171,6 +180,12 @@ impl InputFeatures for BufReader { Ok(self.get_mut().metadata()?.len() as usize) } + fn get_unix_mtime(&mut self) -> Result> { + let sys_time = self.get_mut().metadata()?.modified()?; + let dur = sys_time.duration_since(std::time::SystemTime::UNIX_EPOCH)?; + Ok(Some(dur.as_secs() as i64)) + } + fn try_seek(&mut self, pos: SeekFrom) -> Result { Ok(self.seek(pos)?) } diff --git a/src/io/memory.rs b/src/io/memory.rs index 8032dfaf79..f829d6bd4b 100644 --- a/src/io/memory.rs +++ b/src/io/memory.rs @@ -1,12 +1,17 @@ // src/io/memory.rs -- I/O to in-memory buffers -// Copyright 2016-2017 the Tectonic Project +// Copyright 2016-2020 the Tectonic Project // Licensed under the MIT License. -use std::cell::RefCell; -use std::collections::HashMap; -use std::ffi::{OsStr, OsString}; -use std::io::{self, Cursor, Read, Seek, SeekFrom, Write}; -use std::rc::Rc; +//! MemoryIo is an IoProvider that stores "files" in in-memory buffers. + +use std::{ + cell::RefCell, + collections::HashMap, + ffi::{OsStr, OsString}, + io::{self, Cursor, Read, Seek, SeekFrom, Write}, + rc::Rc, + time::SystemTime, +}; use super::{ normalize_tex_path, InputFeatures, InputHandle, InputOrigin, IoProvider, OpenResult, @@ -15,41 +20,70 @@ use super::{ use crate::errors::Result; use crate::status::StatusBackend; -// MemoryIo is an IoProvider that stores "files" in in-memory buffers. -// -// When a file is "opened", we create a MemoryIoItem struct that tracks the -// data, seek cursor state, etc. - -struct MemoryIoItem { +/// Information about a file created or used inside the memory-backed I/O +/// provider. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct MemoryFileInfo { // TODO: smarter buffering structure than Vec? E.g., linked list of 4k // chunks or something. In the current scheme reallocations will get // expensive. - files: Rc>>>, + pub data: Vec, + pub unix_mtime: Option, +} + +/// A collection of files created or used inside a memory-backed I/O provider. +pub type MemoryFileCollection = HashMap; + +/// When a file is "opened", we create a MemoryIoItem struct that tracks the +/// data, seek cursor state, etc. +struct MemoryIoItem { + // This is the best way I can come up with to allow the file object to + // update its data in its parent data structure. + files: Rc>, + name: OsString, state: Cursor>, + unix_mtime: Option, + was_modified: bool, +} + +/// Get the current time as a Unix time, in a manner consistent with our Unix +/// file modification time API. We choose to make this function infallible +/// rather than injecting a bunch of Results. +fn now_as_unix_time() -> Option { + // No cleaner way to convert a SystemTime to time_t, as far as I can + // tell. + let now = SystemTime::now(); + let dur = match now.duration_since(SystemTime::UNIX_EPOCH) { + Ok(d) => d, + Err(_) => return Some(0), // indicates error to C code, if it cres + }; + Some(dur.as_secs() as i64) } impl MemoryIoItem { pub fn new( - files: &Rc>>>, + files: &Rc>, name: &OsStr, truncate: bool, ) -> MemoryIoItem { - let cur = match files.borrow_mut().remove(name) { - Some(data) => { + let (cur_data, cur_mtime) = match files.borrow_mut().remove(name) { + Some(info) => { if truncate { - Vec::new() + (Vec::new(), now_as_unix_time()) } else { - data + (info.data, info.unix_mtime) } } - None => Vec::new(), + None => (Vec::new(), now_as_unix_time()), }; MemoryIoItem { files: files.clone(), name: name.to_os_string(), - state: Cursor::new(cur), + state: Cursor::new(cur_data), + unix_mtime: cur_mtime, + was_modified: false, } } } @@ -62,6 +96,7 @@ impl Read for MemoryIoItem { impl Write for MemoryIoItem { fn write(&mut self, buf: &[u8]) -> io::Result { + self.was_modified = true; self.state.write(buf) } @@ -81,6 +116,10 @@ impl InputFeatures for MemoryIoItem { Ok(self.state.get_ref().len()) } + fn get_unix_mtime(&mut self) -> Result> { + Ok(self.unix_mtime) + } + fn try_seek(&mut self, pos: SeekFrom) -> Result { Ok(self.state.seek(pos)?) } @@ -88,16 +127,28 @@ impl InputFeatures for MemoryIoItem { impl Drop for MemoryIoItem { fn drop(&mut self) { + let unix_mtime = if self.was_modified { + now_as_unix_time() + } else { + self.unix_mtime + }; + // I think split_off() is an efficient way to move our data vector // back into the hashmap? Ideally we could "consume" self but I don't // believe that's possible in a Drop implementation. let mut mfiles = self.files.borrow_mut(); - mfiles.insert(self.name.clone(), self.state.get_mut().split_off(0)); + mfiles.insert( + self.name.clone(), + MemoryFileInfo { + data: self.state.get_mut().split_off(0), + unix_mtime, + }, + ); } } pub struct MemoryIo { - pub files: Rc>>>, + pub files: Rc>, stdout_allowed: bool, } @@ -111,7 +162,13 @@ impl MemoryIo { pub fn create_entry(&mut self, name: &OsStr, data: Vec) { let mut mfiles = self.files.borrow_mut(); - mfiles.insert(name.to_os_string(), data); + mfiles.insert( + name.to_os_string(), + MemoryFileInfo { + data, + unix_mtime: now_as_unix_time(), + }, + ); } pub fn stdout_key(&self) -> &OsStr { diff --git a/src/io/mod.rs b/src/io/mod.rs index c740125d87..0ca62795aa 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -30,6 +30,13 @@ pub mod zipbundle; pub trait InputFeatures: Read { fn get_size(&mut self) -> Result; fn try_seek(&mut self, pos: SeekFrom) -> Result; + + /// Get the modification time of this file as a Unix time. If that quantity + /// is not meaningfully defined for this input, return `Ok(None)`. This is + /// what the default implementation does. + fn get_unix_mtime(&mut self) -> Result> { + Ok(None) + } } /// What kind of source an input file ultimately came from. We keep track of @@ -207,6 +214,10 @@ impl InputFeatures for InputHandle { self.inner.get_size() } + fn get_unix_mtime(&mut self) -> Result> { + self.inner.get_unix_mtime() + } + fn try_seek(&mut self, pos: SeekFrom) -> Result { match pos { SeekFrom::Start(0) => { @@ -494,6 +505,13 @@ impl InputFeatures for GzDecoder { Err(ErrorKind::NotSizeable.into()) } + fn get_unix_mtime(&mut self) -> Result> { + // In principle we could arrange to potentially get an mtime from the + // underlying stream, but this API is only used for the \filemodtime + // primitive which shouldn't be getting access to gzipped streams. + Ok(None) + } + fn try_seek(&mut self, _: SeekFrom) -> Result { Err(ErrorKind::NotSeekable.into()) } @@ -504,6 +522,10 @@ impl InputFeatures for Cursor> { Ok(self.get_ref().len()) } + fn get_unix_mtime(&mut self) -> Result> { + Ok(None) + } + fn try_seek(&mut self, pos: SeekFrom) -> Result { Ok(self.seek(pos)?) } diff --git a/src/io/stdstreams.rs b/src/io/stdstreams.rs index acc6df404f..0629cb029e 100644 --- a/src/io/stdstreams.rs +++ b/src/io/stdstreams.rs @@ -52,6 +52,10 @@ impl InputFeatures for Cursor { Ok(self.get_ref().0.len()) } + fn get_unix_mtime(&mut self) -> Result> { + Ok(None) + } + fn try_seek(&mut self, pos: SeekFrom) -> Result { Ok(self.seek(pos)?) } diff --git a/src/lib.rs b/src/lib.rs index 9aa809c64c..3ee6bb91d2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,10 +70,9 @@ pub use crate::engines::xdvipdfmx::XdvipdfmxEngine; pub use crate::errors::{Error, ErrorKind, Result}; // Increase this whenever the engine internals change such that the contents -// of the "format" files must be regenerated -- this includes changes to the -// string pool. +// of the "format" files must be regenerated. -pub const FORMAT_SERIAL: u32 = 28; +pub const FORMAT_SERIAL: u32 = 29; /// Compile LaTeX text to a PDF. /// @@ -150,7 +149,7 @@ pub fn latex_to_pdf>(latex: T) -> Result> { }; match files.remove(OsStr::new("texput.pdf")) { - Some(data) => Ok(data), + Some(file) => Ok(file.data), None => Err(errmsg!( "LaTeX didn't report failure, but no PDF was created (??)" )), diff --git a/src/unstable_opts.rs b/src/unstable_opts.rs index c5a5be14e6..fd5aade615 100644 --- a/src/unstable_opts.rs +++ b/src/unstable_opts.rs @@ -15,6 +15,7 @@ use std::str::FromStr; const HELPMSG: &str = r#"Available unstable options: -Z help Lists all unstable options + -Z continue-on-errors Keep compiling even when severe errors occur -Z min-crossrefs= Equivalent to bibtex's -min-crossrefs flag - "include after crossrefs" [default: 2] -Z paper-size= Change the default paper size [default: letter] @@ -26,9 +27,10 @@ const HELPMSG: &str = r#"Available unstable options: // Each entry of this should correspond to a field of UnstableOptions. #[derive(Debug)] pub enum UnstableArg { + ContinueOnErrors, Help, - PaperSize(String), MinCrossrefs(i32), + PaperSize(String), ShellEscapeEnabled, } @@ -47,6 +49,8 @@ impl FromStr for UnstableArg { match arg { "help" => Ok(UnstableArg::Help), + "continue-on-errors" => Ok(UnstableArg::ContinueOnErrors), + "min-crossrefs" => value .ok_or_else(|| { "'-Z min-crossrefs ' requires a value but none was supplied".into() @@ -71,6 +75,7 @@ impl FromStr for UnstableArg { #[derive(Debug, Default)] pub struct UnstableOptions { + pub continue_on_errors: bool, pub paper_size: Option, pub shell_escape: bool, pub min_crossrefs: Option, @@ -90,6 +95,7 @@ impl UnstableOptions { print!("{}", HELPMSG); std::process::exit(0); } + ContinueOnErrors => opts.continue_on_errors = true, MinCrossrefs(num) => opts.min_crossrefs = Some(num), PaperSize(size) => opts.paper_size = Some(size), ShellEscapeEnabled => opts.shell_escape = true, diff --git a/tectonic/bibtex.c b/tectonic/bibtex.c index aca94f58f2..85bfc1e48b 100644 --- a/tectonic/bibtex.c +++ b/tectonic/bibtex.c @@ -727,12 +727,38 @@ aux_err_white_space_in_argument_print(void) puts_log("White space in argument"); } +static bool +str_ends_with(str_number s, str_number ext) +{ + int32_t str_idx, ext_idx; + ASCII_code str_char, ext_char; + + if ((str_start[ext + 1] - str_start[ext]) > (str_start[s + 1] - str_start[s])) + return false; + + str_idx = (str_start[s + 1] - str_start[s]) - 1; + ext_idx = (str_start[ext + 1] - str_start[ext]) - 1; + + while (ext_idx >= 0) { + str_char = str_pool[str_start[s] + str_idx]; + ext_char = str_pool[str_start[ext] + ext_idx]; + + if (str_char != ext_char) + return false; + + str_idx--; + ext_idx--; + } + + return true; +} static void print_bib_name(void) { print_a_pool_str(bib_list[bib_ptr]); - print_a_pool_str(s_bib_extension); + if (!str_ends_with(bib_list[bib_ptr], s_bib_extension)) + print_a_pool_str(s_bib_extension); putc_log('\n'); } @@ -741,7 +767,8 @@ static void log_pr_bib_name(void) { out_pool_str(log_file, bib_list[bib_ptr]); - out_pool_str(log_file, s_bib_extension); + if (!str_ends_with(bib_list[bib_ptr], s_bib_extension)) + out_pool_str(log_file, s_bib_extension); ttstub_output_putc (log_file, '\n'); } @@ -978,12 +1005,6 @@ static void bib_unbalanced_braces_print(void) bib_err_print(); } -static void bib_field_too_long_print(void) -{ - printf_log("Your field is more than %ld characters", (long) buf_size); - bib_err_print(); -} - static void macro_warn_print(void) { puts_log("Warning--string name \""); @@ -2128,13 +2149,12 @@ static bool compress_bib_white(void) { { if (ex_buf_ptr == buf_size) { - bib_field_too_long_print(); - return false; - } else { - - ex_buf[ex_buf_ptr] = 32 /*space */ ; - ex_buf_ptr = ex_buf_ptr + 1; + ttstub_fprintf(log_file, "Field filled up at ' ', reallocating.\n"); + buffer_overflow(); } + + ex_buf[ex_buf_ptr] = 32 /*space */ ; + ex_buf_ptr = ex_buf_ptr + 1; } while ((!scan_white_space())) { @@ -2171,18 +2191,17 @@ static bool scan_balanced_braces(void) if (store_field) { /*257: */ while ((buffer[buf_ptr2] != right_str_delim)) switch ((buffer[buf_ptr2])) { - case 123: + case 123: /*'{'*/ { bib_brace_level = bib_brace_level + 1; { - if (ex_buf_ptr == buf_size) { - bib_field_too_long_print(); - return false; - } else { - - ex_buf[ex_buf_ptr] = 123 /*left_brace */ ; - ex_buf_ptr = ex_buf_ptr + 1; + if (ex_buf_ptr >= buf_size) { + ttstub_fprintf(log_file, "Field filled up at '{', reallocating.\n"); + buffer_overflow(); } + + ex_buf[ex_buf_ptr] = 123 /*left_brace */ ; + ex_buf_ptr = ex_buf_ptr + 1; } buf_ptr2 = buf_ptr2 + 1; { @@ -2195,18 +2214,17 @@ static bool scan_balanced_braces(void) { while (true) switch ((buffer[buf_ptr2])) { - case 125: + case 125: /*'}'*/ { bib_brace_level = bib_brace_level - 1; { - if (ex_buf_ptr == buf_size) { - bib_field_too_long_print(); - return false; - } else { - - ex_buf[ex_buf_ptr] = 125 /*right_brace */ ; - ex_buf_ptr = ex_buf_ptr + 1; + if (ex_buf_ptr >= buf_size) { + ttstub_fprintf(log_file, "Field filled up at '}', reallocating.\n"); + buffer_overflow(); } + + ex_buf[ex_buf_ptr] = 125 /*right_brace */ ; + ex_buf_ptr = ex_buf_ptr + 1; } buf_ptr2 = buf_ptr2 + 1; { @@ -2221,18 +2239,17 @@ static bool scan_balanced_braces(void) goto loop_exit; } break; - case 123: + case 123: /*'{'*/ { bib_brace_level = bib_brace_level + 1; { - if (ex_buf_ptr == buf_size) { - bib_field_too_long_print(); - return false; - } else { - - ex_buf[ex_buf_ptr] = 123 /*left_brace */ ; - ex_buf_ptr = ex_buf_ptr + 1; + if (ex_buf_ptr >= buf_size) { + ttstub_fprintf(log_file, "Field filled up at '{', reallocating.\n"); + buffer_overflow(); } + + ex_buf[ex_buf_ptr] = 123 /*left_brace */ ; + ex_buf_ptr = ex_buf_ptr + 1; } buf_ptr2 = buf_ptr2 + 1; { @@ -2248,14 +2265,13 @@ static bool scan_balanced_braces(void) default: { { - if (ex_buf_ptr == buf_size) { - bib_field_too_long_print(); - return false; - } else { - - ex_buf[ex_buf_ptr] = buffer[buf_ptr2]; - ex_buf_ptr = ex_buf_ptr + 1; + if (ex_buf_ptr >= buf_size) { + ttstub_fprintf(log_file, "Field filled up at %ld, reallocating.\n", (long) buffer[buf_ptr2]); + buffer_overflow(); } + + ex_buf[ex_buf_ptr] = buffer[buf_ptr2]; + ex_buf_ptr = ex_buf_ptr + 1; } buf_ptr2 = buf_ptr2 + 1; { @@ -2283,14 +2299,13 @@ static bool scan_balanced_braces(void) default: { { - if (ex_buf_ptr == buf_size) { - bib_field_too_long_print(); - return false; - } else { - - ex_buf[ex_buf_ptr] = buffer[buf_ptr2]; - ex_buf_ptr = ex_buf_ptr + 1; + if (ex_buf_ptr >= buf_size) { + ttstub_fprintf(log_file, "Field filled up at %ld, reallocating.\n", (long) buffer[buf_ptr2]); + buffer_overflow(); } + + ex_buf[ex_buf_ptr] = buffer[buf_ptr2]; + ex_buf_ptr = ex_buf_ptr + 1; } buf_ptr2 = buf_ptr2 + 1; { @@ -2402,14 +2417,13 @@ static bool scan_a_field_token_and_eat_white(void) while ((tmp_ptr < buf_ptr2)) { { - if (ex_buf_ptr == buf_size) { - bib_field_too_long_print(); - return false; - } else { - - ex_buf[ex_buf_ptr] = buffer[tmp_ptr]; - ex_buf_ptr = ex_buf_ptr + 1; + if (ex_buf_ptr >= buf_size) { + ttstub_fprintf(log_file, "Field filled up at %ld, reallocating.\n", (long) buffer[tmp_ptr]); + buffer_overflow(); } + + ex_buf[ex_buf_ptr] = buffer[tmp_ptr]; + ex_buf_ptr = ex_buf_ptr + 1; } tmp_ptr = tmp_ptr + 1; } @@ -2457,14 +2471,13 @@ static bool scan_a_field_token_and_eat_white(void) if ((tmp_ptr < tmp_end_ptr) && (lex_class[str_pool[tmp_ptr]] == 1 /*white_space */ )) { { - if (ex_buf_ptr == buf_size) { - bib_field_too_long_print(); - return false; - } else { - - ex_buf[ex_buf_ptr] = 32 /*space */ ; - ex_buf_ptr = ex_buf_ptr + 1; + if (ex_buf_ptr >= buf_size) { + ttstub_fprintf(log_file, "Field filled up at ' ', reallocating.\n"); + buffer_overflow(); } + + ex_buf[ex_buf_ptr] = 32 /*space */ ; + ex_buf_ptr = ex_buf_ptr + 1; } tmp_ptr = tmp_ptr + 1; while ((tmp_ptr < tmp_end_ptr) && (lex_class[str_pool[tmp_ptr]] == 1 /*white_space */ )) @@ -2474,23 +2487,21 @@ static bool scan_a_field_token_and_eat_white(void) while ((tmp_ptr < tmp_end_ptr)) { if (lex_class[str_pool[tmp_ptr]] != 1 /*white_space */ ) { - if (ex_buf_ptr == buf_size) { - bib_field_too_long_print(); - return false; - } else { - - ex_buf[ex_buf_ptr] = str_pool[tmp_ptr]; - ex_buf_ptr = ex_buf_ptr + 1; + if (ex_buf_ptr >= buf_size) { + ttstub_fprintf(log_file, "Field filled up at %ld, reallocating.\n", (long) str_pool[tmp_ptr]); + buffer_overflow(); } - } else if (ex_buf[ex_buf_ptr - 1] != 32 /*space */ ) { - if (ex_buf_ptr == buf_size) { - bib_field_too_long_print(); - return false; - } else { - ex_buf[ex_buf_ptr] = 32 /*space */ ; - ex_buf_ptr = ex_buf_ptr + 1; + ex_buf[ex_buf_ptr] = str_pool[tmp_ptr]; + ex_buf_ptr = ex_buf_ptr + 1; + } else if (ex_buf[ex_buf_ptr - 1] != 32 /*space */ ) { + if (ex_buf_ptr >= buf_size) { + ttstub_fprintf(log_file, "Field filled up at ' ', reallocating.\n"); + buffer_overflow(); } + + ex_buf[ex_buf_ptr] = 32 /*space */ ; + ex_buf_ptr = ex_buf_ptr + 1; } tmp_ptr = tmp_ptr + 1; } @@ -5411,7 +5422,7 @@ static void aux_input_command(void) } printf_log("A level-%ld auxiliary file: ", (long) aux_ptr); - print_aux_name(); + log_pr_aux_name(); aux_ln_stack[aux_ptr] = 0; } } diff --git a/tectonic/core-bridge.c b/tectonic/core-bridge.c index a170fb9e0d..c0c795124d 100644 --- a/tectonic/core-bridge.c +++ b/tectonic/core-bridge.c @@ -264,6 +264,12 @@ ttstub_input_get_size(rust_input_handle_t handle) return input_get_size(TGB->context, handle); } +time_t +ttstub_input_get_mtime (rust_input_handle_t handle) +{ + return input_get_mtime(TGB->context, handle); +} + size_t ttstub_input_seek(rust_input_handle_t handle, ssize_t offset, int whence) { diff --git a/tectonic/core-bridge.h b/tectonic/core-bridge.h index 0f50f7d311..9947e0df09 100644 --- a/tectonic/core-bridge.h +++ b/tectonic/core-bridge.h @@ -1,5 +1,5 @@ /* tectonic/core-bridge.h: declarations of C/C++ => Rust bridge API - Copyright 2016-2018 the Tectonic Project + Copyright 2016-2020 the Tectonic Project Licensed under the MIT License. */ @@ -9,6 +9,8 @@ #include "core-foundation.h" #include "core-bindgen.h" +#include /* time_t */ + /* Both XeTeX and bibtex use this enum: */ typedef enum { @@ -97,6 +99,7 @@ int ttstub_output_close (rust_output_handle_t handle); rust_input_handle_t ttstub_input_open (char const *path, tt_input_format_type format, int is_gz); rust_input_handle_t ttstub_input_open_primary (void); size_t ttstub_input_get_size (rust_input_handle_t handle); +time_t ttstub_input_get_mtime (rust_input_handle_t handle); size_t ttstub_input_seek (rust_input_handle_t handle, ssize_t offset, int whence); ssize_t ttstub_input_read (rust_input_handle_t handle, char *data, size_t len); int ttstub_input_getc (rust_input_handle_t handle); diff --git a/tectonic/dpx-agl.c b/tectonic/dpx-agl.c index 75041fb6ef..1da33280a5 100644 --- a/tectonic/dpx-agl.c +++ b/tectonic/dpx-agl.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -37,6 +37,7 @@ #include #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" /* Hash */ #include "dpx-dpxutil.h" @@ -48,14 +49,6 @@ static int agl_load_listfile (const char *filename, int format); -static int verbose = 0; - -void -agl_set_verbose (int level) -{ - verbose = level; -} - static agl_name * agl_new_name (void) { @@ -403,7 +396,7 @@ agl_load_listfile (const char *filename, int is_predef) return -1; } - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message("alternate = agln; } - if (verbose > 3) { + if (dpx_conf.verbose_level > 5) { if (agln->suffix) dpx_message("agl: %s [%s.%s] -->", name, agln->name, agln->suffix); else @@ -493,7 +486,7 @@ agl_load_listfile (const char *filename, int is_predef) ttstub_input_close(handle); - if (verbose) + if (dpx_conf.verbose_level) dpx_message(">"); return count; @@ -700,7 +693,7 @@ agl_sput_UTF16BE (const char *glyphstr, IS_PUA(agln1->unicodes[0]))) { agln0 = agl_normalized_name(name); if (agln0) { - if (verbose > 1 && agln0->suffix) { + if (dpx_conf.verbose_level > 1 && agln0->suffix) { dpx_warning("agl: fix %s --> %s.%s", name, agln0->name, agln0->suffix); } @@ -713,7 +706,7 @@ agl_sput_UTF16BE (const char *glyphstr, len += UC_UTF16BE_encode_char(agln1->unicodes[i], dstpp, limptr); } } else { - if (verbose) { + if (dpx_conf.verbose_level) { dpx_warning("No Unicode mapping for glyph name \"%s\" found.", name); } count++; @@ -790,7 +783,7 @@ agl_get_unicodes (const char *glyphstr, IS_PUA(agln1->unicodes[0]))) { agln0 = agl_normalized_name(name); if (agln0) { - if (verbose > 1 && agln0->suffix) { + if (dpx_conf.verbose_level > 1 && agln0->suffix) { dpx_warning("agl: fix %s --> %s.%s", name, agln0->name, agln0->suffix); } @@ -807,7 +800,7 @@ agl_get_unicodes (const char *glyphstr, unicodes[count++] = agln1->unicodes[i]; } } else { - if (verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_warning("No Unicode mapping for glyph name \"%s\" found.", name); free(name); return -1; diff --git a/tectonic/dpx-agl.h b/tectonic/dpx-agl.h index bf587291a9..4c23e49397 100644 --- a/tectonic/dpx-agl.h +++ b/tectonic/dpx-agl.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -59,7 +59,6 @@ const char *agl_suffix_to_otltag (const char *suffix); agl_name *agl_lookup_list (const char *glyphname); -void agl_set_verbose (int level); void agl_init_map (void); void agl_close_map (void); diff --git a/tectonic/dpx-bmpimage.c b/tectonic/dpx-bmpimage.c index 3fd9388f0a..3bcb2950ab 100644 --- a/tectonic/dpx-bmpimage.c +++ b/tectonic/dpx-bmpimage.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -31,6 +31,7 @@ #include #include +#include "dpx-dpxconf.h" #include "dpx-error.h" #include "dpx-mem.h" #include "dpx-numbers.h" @@ -85,7 +86,9 @@ check_for_bmp (rust_input_handle_t handle) static void get_density (double *xdensity, double *ydensity, struct hdr_info *hdr) { - if (hdr->x_pix_per_meter > 0 && hdr->y_pix_per_meter > 0) { /* 0 for undefined. FIXME */ + if (dpx_conf.compat_mode == dpx_mode_compat_mode) + *xdensity = *ydensity = 72.0 / 100.0; + else if (hdr->x_pix_per_meter > 0 && hdr->y_pix_per_meter > 0) { /* 0 for undefined. FIXME */ *xdensity = 72.0 / (hdr->x_pix_per_meter * 0.0254); *ydensity = 72.0 / (hdr->y_pix_per_meter * 0.0254); } else { diff --git a/tectonic/dpx-cid.c b/tectonic/dpx-cid.c index 7d2ac6b9ca..12c04686ba 100644 --- a/tectonic/dpx-cid.c +++ b/tectonic/dpx-cid.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -38,6 +38,7 @@ #include "dpx-cid_p.h" #include "dpx-cidtype0.h" #include "dpx-cidtype2.h" +#include "dpx-dpxconf.h" #include "dpx-dpxutil.h" #include "dpx-error.h" #include "dpx-mem.h" @@ -61,15 +62,22 @@ static struct { /* Heighest Supplement values supported by PDF-1.0, 1.1, ...; see * also http://partners.adobe.com/public/developer/font/index.html#ckf */ - int supplement[16]; + int supplement[21]; } CIDFont_stdcc_def[] = { - {"Adobe", "UCS", {-1, -1, 0, 0, 0, 0, 0, 0}}, - {"Adobe", "GB1", {-1, -1, 0, 2, 4, 4, 4, 4}}, - {"Adobe", "CNS1", {-1, -1, 0, 0, 3, 4, 4, 4}}, - {"Adobe", "Japan1", {-1, -1, 2, 2, 4, 5, 6, 6}}, - {"Adobe", "Korea1", {-1, -1, 1, 1, 2, 2, 2, 2}}, - {"Adobe", "Identity", {-1, -1, 0, 0, 0, 0, 0, 0}}, - {NULL, NULL, { 0, 0, 0, 0, 0, 0, 0, 0}} + {"Adobe", "UCS", {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0}}, + {"Adobe", "GB1", {-1, -1, 0, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4}}, + {"Adobe", "CNS1", {-1, -1, 0, 0, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4}}, + {"Adobe", "Japan1", {-1, -1, 2, 2, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6}}, + {"Adobe", "Korea1", {-1, -1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2}}, + {"Adobe", "Identity", {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0}}, + {NULL, NULL, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0}} }; #define UCS_CC 0 #define ACC_START 1 @@ -107,16 +115,7 @@ static struct { static void release_opt (cid_opt *opt); static CIDSysInfo *get_cidsysinfo (const char *map_name, fontmap_opt *fmap_opt); -static int __verbose = 0; -static int cidoptflags = 0; - -void -CIDFont_set_verbose (int level) -{ - CIDFont_type0_set_verbose(level); - CIDFont_type2_set_verbose(level); - __verbose = level; -} +static int cidoptflags = 0; static CIDFont * CIDFont_new (void) @@ -324,16 +323,16 @@ CIDFont_dofont (CIDFont *font) if (!font || !font->indirect) return; - if (__verbose) + if (dpx_conf.verbose_level > 0) dpx_message(":%s", font->ident); - if (__verbose > 1) { + if (dpx_conf.verbose_level > 1) { if (font->fontname) dpx_message("[%s]", font->fontname); } switch (font->subtype) { case CIDFONT_TYPE0: - if(__verbose) + if(dpx_conf.verbose_level > 0) dpx_message("[CIDFontType0]"); if (CIDFont_get_flag(font, CIDFONT_FLAG_TYPE1)) CIDFont_type0_t1dofont(font); @@ -343,7 +342,7 @@ CIDFont_dofont (CIDFont *font) CIDFont_type0_dofont(font); break; case CIDFONT_TYPE2: - if(__verbose) + if(dpx_conf.verbose_level > 0) dpx_message("[CIDFontType2]"); CIDFont_type2_dofont(font); break; @@ -552,7 +551,6 @@ CIDFont_cache_find (const char *map_name, opt->name = NULL; opt->csi = get_cidsysinfo(map_name, fmap_opt); opt->stemv = fmap_opt->stemv; - opt->cff_charsets = NULL; if (!opt->csi && cmap_csi) { /* @@ -633,8 +631,6 @@ CIDFont_cache_find (const char *map_name, font->options = opt; __cache->fonts[font_id] = font; (__cache->num)++; - - fmap_opt->cff_charsets = opt->cff_charsets; } } else if (opt) { release_opt(opt); @@ -655,7 +651,7 @@ CIDFont_cache_close (void) font = __cache->fonts[font_id]; - if (__verbose) + if (dpx_conf.verbose_level > 0) dpx_message("(CID"); CIDFont_dofont (font); @@ -664,7 +660,7 @@ CIDFont_cache_close (void) free(font); - if (__verbose) + if (dpx_conf.verbose_level > 0) dpx_message(")"); } free(__cache->fonts); @@ -687,8 +683,6 @@ release_opt (cid_opt *opt) free(opt->csi->registry); free(opt->csi->ordering); free(opt->csi); - if (opt->cff_charsets) - cff_release_charsets((cff_charsets *) opt->cff_charsets); } free(opt); } @@ -697,11 +691,11 @@ static CIDSysInfo * get_cidsysinfo (const char *map_name, fontmap_opt *fmap_opt) { CIDSysInfo *csi = NULL; - int pdf_ver; + int sup_idx; int i, csi_idx = -1, m; size_t n; - pdf_ver = pdf_get_version(); + sup_idx = pdf_get_version() - 10; if (!fmap_opt || !fmap_opt->charcoll) return NULL; @@ -719,7 +713,7 @@ get_cidsysinfo (const char *map_name, fontmap_opt *fmap_opt) if (strlen(fmap_opt->charcoll) > n) { csi->supplement = (int) strtoul(&(fmap_opt->charcoll[n]), NULL, 10); } else { /* Use heighest supported value for current output PDF version. */ - csi->supplement = CIDFont_stdcc_def[csi_idx].supplement[pdf_ver]; + csi->supplement = CIDFont_stdcc_def[csi_idx].supplement[sup_idx]; } break; } @@ -771,11 +765,12 @@ get_cidsysinfo (const char *map_name, fontmap_opt *fmap_opt) } if (csi && csi_idx >= 0) { - if (csi->supplement > CIDFont_stdcc_def[csi_idx].supplement[pdf_ver] + if (csi->supplement > CIDFont_stdcc_def[csi_idx].supplement[sup_idx] && (fmap_opt->flags & FONTMAP_OPT_NOEMBED)) { - dpx_warning("%s: Heighest supplement number supported in PDF-1.%d for %s-%s is %d.", - CIDFONT_DEBUG_STR, pdf_ver, csi->registry, csi->ordering, - CIDFont_stdcc_def[csi_idx].supplement[pdf_ver]); + dpx_warning("%s: Heighest supplement number supported in PDF-%d.%d for %s-%s is %d.", + CIDFONT_DEBUG_STR, pdf_get_version_major(), pdf_get_version_minor(), + csi->registry, csi->ordering, + CIDFont_stdcc_def[csi_idx].supplement[sup_idx]); dpx_warning("%s: Some character may not shown without embedded font (--> %s).", CIDFONT_DEBUG_STR, map_name); } diff --git a/tectonic/dpx-cid.h b/tectonic/dpx-cid.h index 3df8e1e687..431ec2dbe4 100644 --- a/tectonic/dpx-cid.h +++ b/tectonic/dpx-cid.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -40,7 +40,6 @@ extern CIDSysInfo CSI_UNICODE; typedef struct CIDFont CIDFont; -void CIDFont_set_verbose (int level); void CIDFont_set_flags (int flags); #define CIDFONT_FORCE_FIXEDPITCH (1 << 1) diff --git a/tectonic/dpx-cid_p.h b/tectonic/dpx-cid_p.h index 61306d2c2a..da0bea3bf9 100644 --- a/tectonic/dpx-cid_p.h +++ b/tectonic/dpx-cid_p.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -44,7 +44,6 @@ typedef struct int style; int embed; int stemv; - void *cff_charsets; } cid_opt; struct CIDFont diff --git a/tectonic/dpx-cidtype0.c b/tectonic/dpx-cidtype0.c index 049788df51..960ebbec50 100644 --- a/tectonic/dpx-cidtype0.c +++ b/tectonic/dpx-cidtype0.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -45,6 +45,7 @@ #include "dpx-cmap.h" #include "dpx-cmap_write.h" #include "dpx-cs_type2.h" +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" #include "dpx-error.h" #include "dpx-mem.h" @@ -62,15 +63,8 @@ #include "dpx-tt_table.h" #include "dpx-type0.h" -static int verbose = 0; static int opt_flags = 0; -void -CIDFont_type0_set_verbose (int level) -{ - verbose = level; -} - void CIDFont_type0_set_flags (int flags) { @@ -765,7 +759,7 @@ CIDFont_type0_dofont (CIDFont *font) CIDFontInfo_close(&info); - if (verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_message("[%u/%u glyphs][%d bytes]", num_glyphs, cs_count, destlen); CIDFont_type0_add_CIDSet(font, used_chars, last_cid); @@ -838,12 +832,6 @@ CIDFont_type0_open (CIDFont *font, const char *name, ttstub_input_close(handle); return -1; } - - if (is_cid_font) { - cff_read_charsets(cffont); - opt->cff_charsets = cffont->charsets; - cffont->charsets = NULL; - } } else { if (!handle) return -1; @@ -880,7 +868,7 @@ CIDFont_type0_open (CIDFont *font, const char *name, _tt_abort("Inconsistent CMap specified for this font."); } if (csi->supplement < cmap_csi->supplement) { - dpx_warning("CMap have higher supplmement number."); + dpx_warning("CMap have higher supplement number."); dpx_warning("Some characters may not be displayed or printed."); } } @@ -1218,7 +1206,7 @@ CIDFont_type0_t1cdofont (CIDFont *font) CIDFontInfo_close(&info); - if (verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_message("[%u glyphs][%d bytes]", num_glyphs, destlen); CIDFont_type0_add_CIDSet(font, used_chars, last_cid); diff --git a/tectonic/dpx-cidtype0.h b/tectonic/dpx-cidtype0.h index 61126fe555..9841759e84 100644 --- a/tectonic/dpx-cidtype0.h +++ b/tectonic/dpx-cidtype0.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -27,7 +27,6 @@ #include "dpx-cid_p.h" #include "dpx-fontmap.h" -void CIDFont_type0_set_verbose (int level); void CIDFont_type0_set_flags (int flags); int CIDFont_type0_open (CIDFont *font, const char *name, diff --git a/tectonic/dpx-cidtype2.c b/tectonic/dpx-cidtype2.c index 07c456f179..add239d548 100644 --- a/tectonic/dpx-cidtype2.c +++ b/tectonic/dpx-cidtype2.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -24,6 +24,7 @@ */ #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" #include "dpx-error.h" #include "dpx-mem.h" @@ -58,15 +59,8 @@ #include "dpx-tt_table.h" #include "dpx-type0.h" -static int verbose = 0; static int opt_flags = 0; -void -CIDFont_type2_set_verbose (int level) -{ - verbose = level; -} - void CIDFont_type2_set_flags (int32_t flags) { @@ -789,7 +783,7 @@ CIDFont_type2_dofont (CIDFont *font) if (CIDFont_get_embedding(font)) { if (tt_build_tables(sfont, glyphs) < 0) _tt_abort("Could not created FontFile stream."); - if (verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_message("[%u glyphs (Max CID: %u)]", glyphs->num_glyphs, last_cid); } else { if (tt_get_metrics(sfont, glyphs) < 0) @@ -808,6 +802,26 @@ CIDFont_type2_dofont (CIDFont *font) add_TTCIDVMetrics(font->fontdict, glyphs, used_chars, last_cid); } + /* CIDSet + * NOTE: All glyphs including component glyph and dummy glyph must be + * listed in CIDSet. However, .notdef glyph should be ommitted. + */ + { + pdf_obj *cidset; + char *cidset_data; + + cidset_data = NEW(glyphs->last_gid/8 + 1, char); + memset(cidset_data, 0, glyphs->last_gid/8 + 1); + for (i = 1; i <= glyphs->last_gid; i++) + cidset_data[i/8] |= (1 << (7 - i % 8)); + cidset = pdf_new_stream(STREAM_COMPRESS); + pdf_add_stream(cidset, cidset_data, glyphs->last_gid/8 + 1); + free(cidset_data); + pdf_add_dict(font->descriptor, + pdf_new_name("CIDSet"), pdf_ref_obj(cidset)); + pdf_release_obj(cidset); + } + tt_build_finish(glyphs); /* Finish here if not embedded. */ @@ -841,7 +855,7 @@ CIDFont_type2_dofont (CIDFont *font) if (!fontfile) _tt_abort("Could not created FontFile stream for \"%s\".", font->ident); - if (verbose > 1) { + if (dpx_conf.verbose_level > 1) { dpx_message("[%d bytes]", pdf_stream_length(fontfile)); } @@ -850,20 +864,6 @@ CIDFont_type2_dofont (CIDFont *font) pdf_ref_obj (fontfile)); pdf_release_obj(fontfile); - /* - * CIDSet - */ - { - pdf_obj *cidset; - - cidset = pdf_new_stream(STREAM_COMPRESS); - pdf_add_stream(cidset, used_chars, last_cid/8 + 1); - pdf_add_dict(font->descriptor, - pdf_new_name("CIDSet"), - pdf_ref_obj(cidset)); - pdf_release_obj(cidset); - } - /* * CIDToGIDMap * Adobe's PDF Reference had been describing it as "optional" and @@ -1001,7 +1001,7 @@ CIDFont_type2_open (CIDFont *font, const char *name, _tt_abort("Incompatible CMap specified for this font."); } if (opt->csi->supplement < cmap_csi->supplement) { - dpx_warning("Supplmement value in CIDSystemInfo increased."); + dpx_warning("Supplement value in CIDSystemInfo increased."); dpx_warning("Some characters may not shown."); opt->csi->supplement = cmap_csi->supplement; } diff --git a/tectonic/dpx-cidtype2.h b/tectonic/dpx-cidtype2.h index 6e49372b8b..43220ba1f4 100644 --- a/tectonic/dpx-cidtype2.h +++ b/tectonic/dpx-cidtype2.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -26,7 +26,6 @@ #include "dpx-cid.h" #include "dpx-cid_p.h" -void CIDFont_type2_set_verbose (int level); void CIDFont_type2_set_flags (int flags); int CIDFont_type2_open (CIDFont *font, const char *name, diff --git a/tectonic/dpx-cmap.c b/tectonic/dpx-cmap.c index 651dce9ca7..61435d2bcb 100644 --- a/tectonic/dpx-cmap.c +++ b/tectonic/dpx-cmap.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -33,6 +33,7 @@ * * TODO: * Only cid(range|char) allowed for CODE_TO_CID and bf(range|char) for CID_TO_CODE ? + * */ #include "dpx-cmap.h" @@ -43,19 +44,13 @@ #include "core-bridge.h" #include "dpx-cmap_p.h" +#include "dpx-dpxconf.h" #include "dpx-dpxutil.h" #include "dpx-error.h" #include "dpx-mem.h" -static int __verbose = 0; static int __silent = 0; -void -CMap_set_verbose (int level) -{ - __verbose = level; -} - void CMap_set_silent (int value) { @@ -107,9 +102,6 @@ CMap_new (void) cmap->mapData->pos = 0; cmap->mapData->data = NEW(MEM_ALLOC_SIZE, unsigned char); - cmap->reverseMap = NEW(65536, int); - memset(cmap->reverseMap, 0, 65536 * sizeof(int)); - return cmap; } @@ -138,8 +130,6 @@ CMap_release (CMap *cmap) } } - free(cmap->reverseMap); - free(cmap); } @@ -349,14 +339,6 @@ CMap_decode (CMap *cmap, return count; } -int -CMap_reverse_decode(CMap *cmap, CID cid) { - int ch = cmap->reverseMap ? cmap->reverseMap[cid] : -1; - if (ch == 0 && cmap->useCMap) - return CMap_reverse_decode(cmap->useCMap, cid); - return ch; -} - char * CMap_get_name (CMap *cmap) { @@ -678,8 +660,6 @@ CMap_add_cidrange (CMap *cmap, for (v = 0, i = 0; i < srcdim - 1; i++) v = (v << 8) + srclo[i]; - cmap->reverseMap[base] = v; - for (c = srclo[srcdim-1]; c <= srchi[srcdim-1]; c++) { if (cur[c].flag != 0) { if (!__silent) @@ -690,8 +670,6 @@ CMap_add_cidrange (CMap *cmap, cur[c].code = get_mem(cmap, 2); cur[c].code[0] = base >> 8; cur[c].code[1] = base & 0xff; - - cmap->reverseMap[base] = (v << 8) + c; } if (base >= CID_MAX) dpx_warning("CID number too large."); @@ -930,7 +908,7 @@ CMap_cache_find (const char *cmap_name) return -1; } - if (__verbose) + if (dpx_conf.verbose_level > 0) dpx_message("(CMap:%s", cmap_name); if (__cache->num >= __cache->max) { @@ -947,7 +925,7 @@ CMap_cache_find (const char *cmap_name) ttstub_input_close(handle); - if (__verbose) + if (dpx_conf.verbose_level > 0) dpx_message(")"); return id; diff --git a/tectonic/dpx-cmap.h b/tectonic/dpx-cmap.h index 96bb0a2140..155dda9dcc 100644 --- a/tectonic/dpx-cmap.h +++ b/tectonic/dpx-cmap.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -61,7 +61,6 @@ typedef struct CMap CMap; /************************** CMAP_MAIN **************************/ -void CMap_set_verbose (int level); void CMap_set_silent (int value); CMap *CMap_new (void); @@ -111,8 +110,6 @@ size_t CMap_decode (CMap *cmap, const unsigned char **inbuf, size_t *inbytesleft, unsigned char **outbuf, size_t *outbytesleft); -int CMap_reverse_decode(CMap *cmap, CID cid); - void CMap_cache_init (void); CMap *CMap_cache_get (int id); int CMap_cache_find (const char *cmap_name); diff --git a/tectonic/dpx-cmap_p.h b/tectonic/dpx-cmap_p.h index f9f3ee5f02..4f49386412 100644 --- a/tectonic/dpx-cmap_p.h +++ b/tectonic/dpx-cmap_p.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -98,8 +98,6 @@ struct CMap { size_t minBytesOut; size_t maxBytesOut; } profile; - - int *reverseMap; }; #endif /* _CMAP_P_H_ */ diff --git a/tectonic/dpx-cmap_read.c b/tectonic/dpx-cmap_read.c index aaeff0633c..8e6d70b951 100644 --- a/tectonic/dpx-cmap_read.c +++ b/tectonic/dpx-cmap_read.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -30,13 +30,12 @@ #include "dpx-cid.h" #include "dpx-cmap.h" +#include "dpx-dpxconf.h" #include "dpx-dpxutil.h" #include "dpx-error.h" #include "dpx-mem.h" #include "dpx-pst.h" -static int __verbose = 0; - #define CMAP_PARSE_DEBUG_STR "CMap_parse:" #define CMAP_PARSE_DEBUG 3 @@ -88,8 +87,6 @@ ifreader_read (ifreader *reader, size_t size) assert(reader); bytesrem = (size_t) reader->endptr - (size_t) reader->cursor; if (size > reader->max) { - if (__verbose) - dpx_message("\nExtending buffer (%"PRIuZ" bytes)...\n", size); reader->buf = RENEW(reader->buf, size+1, unsigned char); reader->max = size; } @@ -102,8 +99,6 @@ ifreader_read (ifreader *reader, size_t size) _tt_abort("Reading file failed."); reader->endptr += bytesread; reader->unread -= bytesread; - if (__verbose) - dpx_message("Reading more %"PRIuZ" bytes (%"PRIuZ" bytes remains in buffer)...\n", bytesread, bytesrem); } *reader->endptr = 0; diff --git a/tectonic/dpx-cmap_write.c b/tectonic/dpx-cmap_write.c index ba9c47822e..ca405384de 100644 --- a/tectonic/dpx-cmap_write.c +++ b/tectonic/dpx-cmap_write.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -218,6 +218,74 @@ write_map (mapDef *mtab, size_t count, return count; } +/* duplicated from pdfobj.c */ +static void +write_string (char **outptr, char *endptr, const char *strptr) +{ + const char *s; + char *p; + int i, length; + + s = strptr; + length = strptr ? strlen(strptr) : 0; + p = *outptr; + + *p++ = '('; + for (i = 0; i < length; i++) { + unsigned char ch; + + ch = s[i]; + if (ch < 32 || ch > 126) { + p += sprintf(p, "\\%03o", ch); + } else { + switch (ch) { + case '(': case ')': case '\\': + *p++ = '\\'; + *p++ = ch; + break; + default: + *p++ = ch; + break; + } + } + } + *p++ = ')'; + + *outptr = p; +} + +static void +write_name (char **outptr, char *endptr, const char *name) +{ + const char *s; + char *p; + int i, length; + + s = name; + length = name ? strlen(name) : 0; + p = *outptr; +#ifndef is_delim + /* Avoid '{' and '}' for PostScript compatibility? */ +#define is_delim(c) ((c) == '(' || (c) == ')' || \ + (c) == '/' || \ + (c) == '<' || (c) == '>' || \ + (c) == '[' || (c) == ']' || \ + (c) == '{' || (c) == '}' || \ + (c) == '%') +#endif + *p++ = '/'; + for (i = 0; i < length; i++) { + if (s[i] < '!' || s[i] > '~' || s[i] == '#' || is_delim(s[i])) { + /* ^ "space" is here. */ + *p++ = '#'; + sputx(s[i], &p, endptr); + } else { + *p++ = s[i]; + } + } + *outptr = p; +} + #define CMAP_BEGIN "\ /CIDInit /ProcSet findresource begin\n\ 12 dict begin\n\ @@ -326,7 +394,7 @@ CMap_create_stream (CMap *cmap) } } -#define WBUF_SIZE 4096 +#define WBUF_SIZE 40960 wbuf.buf = NEW(WBUF_SIZE, char); codestr = NEW(cmap->profile.maxBytesIn, unsigned char); memset(codestr, 0, cmap->profile.maxBytesIn); @@ -338,7 +406,9 @@ CMap_create_stream (CMap *cmap) /* Start CMap */ pdf_add_stream(stream, (const void *) CMAP_BEGIN, strlen(CMAP_BEGIN)); - wbuf.curptr += sprintf(wbuf.curptr, "/CMapName /%s def\n", cmap->name); + wbuf.curptr += sprintf(wbuf.curptr, "/CMapName "); + write_name(&wbuf.curptr, wbuf.limptr, cmap->name); + wbuf.curptr += sprintf(wbuf.curptr, " def\n"); wbuf.curptr += sprintf(wbuf.curptr, "/CMapType %d def\n" , cmap->type); if (cmap->wmode != 0 && cmap->type != CMAP_TYPE_TO_UNICODE) @@ -349,8 +419,15 @@ CMap_create_stream (CMap *cmap) /Ordering (%s)\n\ /Supplement %d\n\ >> def\n" - wbuf.curptr += sprintf(wbuf.curptr, CMAP_CSI_FMT, - csi->registry, csi->ordering, csi->supplement); + wbuf.curptr += sprintf(wbuf.curptr, "/CIDSystemInfo <<\n"); + wbuf.curptr += sprintf(wbuf.curptr, " /Registry "); + write_string(&wbuf.curptr, wbuf.limptr, csi->registry); + wbuf.curptr += sprintf(wbuf.curptr, "\n"); + wbuf.curptr += sprintf(wbuf.curptr, " /Ordering "); + write_string(&wbuf.curptr, wbuf.limptr, csi->ordering); + wbuf.curptr += sprintf(wbuf.curptr, "\n"); + wbuf.curptr += sprintf(wbuf.curptr, " /Supplement %d\n>> def\n", + csi->supplement); pdf_add_stream(stream, wbuf.buf, (int)(wbuf.curptr - wbuf.buf)); wbuf.curptr = wbuf.buf; diff --git a/tectonic/dpx-dpxconf.c b/tectonic/dpx-dpxconf.c index 9c5f5495f2..de4b68def4 100644 --- a/tectonic/dpx-dpxconf.c +++ b/tectonic/dpx-dpxconf.c @@ -1,6 +1,6 @@ /* This is DVIPDFMx, an eXtended version of DVIPDFM by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -25,6 +25,8 @@ #include +struct _dpx_conf dpx_conf = {0, dpx_mode_normal_mode, 0, {0}}; + #ifndef HAVE_LIBPAPER const struct paper paperspecs[] = { {"letter", 612.00, 792.00}, diff --git a/tectonic/dpx-dpxconf.h b/tectonic/dpx-dpxconf.h index 3edacd8f1c..8223a1911b 100644 --- a/tectonic/dpx-dpxconf.h +++ b/tectonic/dpx-dpxconf.h @@ -1,6 +1,6 @@ /* This is DVIPDFMx, an eXtended version of DVIPDFM by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -26,6 +26,23 @@ #include "dpx-core.h" #include + +enum dpx_mode { + dpx_mode_normal_mode, + dpx_mode_compat_mode, + dpx_mode_xdv_mode, + dpx_mode_mpost_mode +}; + +extern struct _dpx_conf { + int verbose_level; + enum dpx_mode compat_mode; + int ignore_font_license; + struct { + int keep_cache; + } file; +} dpx_conf; + #ifdef HAVE_LIBPAPER #include #else diff --git a/tectonic/dpx-dpxfile.c b/tectonic/dpx-dpxfile.c index e4e875d431..7ecdafd4eb 100644 --- a/tectonic/dpx-dpxfile.c +++ b/tectonic/dpx-dpxfile.c @@ -1,5 +1,5 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -32,6 +32,7 @@ #include #endif +#include "dpx-dpxconf.h" #include "dpx-mem.h" #include "dpx-numbers.h" #include "dpx-system.h" @@ -41,17 +42,6 @@ #include #include -static int verbose = 0; -int keep_cache = 0; - -void -dpx_file_set_verbose (int level) -{ - verbose = level; -} - - - static char _sbuf[128]; /* * SFNT type sigs: @@ -353,7 +343,7 @@ dpx_delete_old_cache (int life) * it would have been annoying to port to Windows. */ if (life == -2) - keep_cache = -1; + dpx_conf.file.keep_cache = -1; } void @@ -361,7 +351,7 @@ dpx_delete_temp_file (char *tmp, int force) { if (!tmp) return; - if (force || keep_cache != 1) remove (tmp); + if (force || dpx_conf.file.keep_cache != 1) remove (tmp); free(tmp); return; @@ -376,8 +366,7 @@ dpx_delete_temp_file (char *tmp, int force) */ int dpx_file_apply_filter (const char *cmdtmpl, - const char *input, const char *output, - unsigned char version) + const char *input, const char *output, int version) { /* Tectonic: defused */ return -1; diff --git a/tectonic/dpx-dpxfile.h b/tectonic/dpx-dpxfile.h index 3b71cc234e..e4f94df549 100644 --- a/tectonic/dpx-dpxfile.h +++ b/tectonic/dpx-dpxfile.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -47,17 +47,13 @@ rust_input_handle_t dpx_open_truetype_file (const char *filename); rust_input_handle_t dpx_open_opentype_file (const char *filename); rust_input_handle_t dpx_open_dfont_file (const char *filename); -void dpx_file_set_verbose (int level); - int dpx_file_apply_filter (const char *cmdtmpl, const char *input, const char *output, - unsigned char version); + int version); char *dpx_create_temp_file (void); void dpx_delete_old_cache (int life); void dpx_delete_temp_file (char *tmp, int force); /* tmp freed here */ -extern int keep_cache; - /* Tectonic-enabled I/O alternatives */ rust_input_handle_t dpx_tt_open (const char *filename, const char *suffix, diff --git a/tectonic/dpx-dpxutil.c b/tectonic/dpx-dpxutil.c index 0ed3c2e660..c3faa16b62 100644 --- a/tectonic/dpx-dpxutil.c +++ b/tectonic/dpx-dpxutil.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -28,6 +28,7 @@ #include #include +#include "dpx-dvipdfmx.h" #include "dpx-error.h" #include "dpx-mem.h" @@ -67,6 +68,69 @@ max4 (double x1, double x2, double x3, double x4) } + +#if defined(_MSC_VER) +#define strtoll _strtoi64 +#endif + +/* If an environment variable SOURCE_DATE_EPOCH is correctly defined like + * SOURCE_DATE_EPOCH=1456304492, then returns this value, to be used as the + * 'current time', otherwise returns INVALID_EPOCH_VALUE (= (time_t)-1). + * In the case of Microsoft Visual Studio 2010, the value should be less + * than 32535291600. + */ + +time_t +dpx_util_get_unique_time_if_given(void) +{ + const char *source_date_epoch; + int64_t epoch; + char *endptr; + time_t ret = INVALID_EPOCH_VALUE; + + source_date_epoch = getenv("SOURCE_DATE_EPOCH"); + if (source_date_epoch) { + errno = 0; + epoch = strtoll(source_date_epoch, &endptr, 10); + if (!(epoch < 0 || *endptr != '\0' || errno != 0)) { + ret = (time_t) epoch; +#if defined(_MSC_VER) + if (ret > 32535291599ULL) + ret = 32535291599ULL; +#endif + } + } + return ret; +} + + +/* + * Docinfo + */ +int +dpx_util_format_asn_date (char *date_string, int need_timezone) +{ + int32_t tz_offset = 0; + struct tm *bd_time = gmtime(&source_date_epoch); + + if (need_timezone) { + if (bd_time->tm_isdst > 0) { + tz_offset += 3600; + } + sprintf(date_string, "D:%04d%02d%02d%02d%02d%02d%c%02d'%02d'", + bd_time->tm_year + 1900, bd_time->tm_mon + 1, bd_time->tm_mday, + bd_time->tm_hour, bd_time->tm_min, bd_time->tm_sec, + (tz_offset > 0) ? '+' : '-', abs(tz_offset) / 3600, + (abs(tz_offset) / 60) % 60); + } else { + sprintf(date_string, "D:%04d%02d%02d%02d%02d%02d", + bd_time->tm_year + 1900, bd_time->tm_mon + 1, bd_time->tm_mday, + bd_time->tm_hour, bd_time->tm_min, bd_time->tm_sec); + } + + return strlen(date_string); +} + void skip_white_spaces (unsigned char **s, unsigned char *endptr) { diff --git a/tectonic/dpx-dpxutil.h b/tectonic/dpx-dpxutil.h index 483ee77130..b5b0ce6e68 100644 --- a/tectonic/dpx-dpxutil.h +++ b/tectonic/dpx-dpxutil.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -25,6 +25,8 @@ #include "dpx-core.h" +#include + #undef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #undef MAX @@ -35,6 +37,10 @@ extern double min4(double v1, double v2, double v3, double v4); extern double max4(double v1, double v2, double v3, double v4); +#define INVALID_EPOCH_VALUE ((time_t)-1) +extern time_t dpx_util_get_unique_time_if_given (void); +extern int dpx_util_format_asn_date (char *date_string, int need_timezone); + #ifndef is_space #define is_space(c) ((c) == ' ' || (c) == '\t' || (c) == '\f' || \ (c) == '\r' || (c) == '\n' || (c) == '\0') diff --git a/tectonic/dpx-dvi.c b/tectonic/dpx-dvi.c index 868f8e3c9b..41d85c2525 100644 --- a/tectonic/dpx-dvi.c +++ b/tectonic/dpx-dvi.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2020 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 2012-2015 by Khaled Hosny @@ -37,7 +37,9 @@ #include "dpx-cff.h" #include "dpx-cff_dict.h" #include "dpx-cff_types.h" +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" +#include "dpx-dpxutil.h" #include "dpx-dvicodes.h" #include "dpx-dvipdfmx.h" #include "dpx-error.h" @@ -47,9 +49,10 @@ #include "dpx-pdfcolor.h" #include "dpx-pdfdev.h" #include "dpx-pdfdoc.h" -#include "dpx-pdfencrypt.h" +#include "dpx-pdfdraw.h" #include "dpx-pdfobj.h" #include "dpx-pdfparse.h" +#include "dpx-pdfresource.h" #include "dpx-sfnt.h" #include "dpx-specials.h" #include "dpx-subfont.h" @@ -136,6 +139,7 @@ static struct loaded_font spt_t size; int source; /* Source is either DVI or VF */ uint32_t rgba_color; + int xgs_id; /* Transparency ExtGState */ struct tt_longMetrics *hvmt; int ascent; int descent; @@ -184,7 +188,6 @@ static struct font_def static unsigned int num_def_fonts = 0, max_def_fonts = 0; static int compute_boxes = 0, link_annot = 1; -static int verbose = 0; #define DVI_PAGE_BUF_CHUNK 0x10000U /* 64K should be plenty for most pages */ @@ -294,16 +297,6 @@ get_buffered_unsigned_num(unsigned char num) #define skip_bufferd_bytes(n) dvi_page_buf_index += n -void -dvi_set_verbose (int level) -{ - verbose = level; - subfont_set_verbose(level); - tfm_set_verbose(level); - vf_set_verbose(level); - spc_set_verbose(level); -} - unsigned int dvi_npages (void) { @@ -328,7 +321,7 @@ check_id_bytes (void) { static void need_XeTeX (int c) { - if (!is_xdv) + if (dpx_conf.compat_mode != dpx_mode_xdv_mode) _tt_abort("DVI opcode %i only valid for XeTeX", c); } @@ -368,7 +361,8 @@ find_post (void) } post_id_byte = ch; - is_xdv = (ch == XDV_ID || ch == XDV_ID_OLD); + if (ch == XDV_ID || ch == XDV_ID_OLD) + dpx_conf.compat_mode = dpx_mode_xdv_mode; is_ptex = ch == DVIV_ID; /* Make sure post_post is really there */ @@ -414,7 +408,7 @@ get_page_info (int32_t post_location) if (num_pages == 0) { _tt_abort("Page count is 0!"); } - if (verbose > 2) { + if (dpx_conf.verbose_level > 2) { dpx_message("Page count:\t %4d\n", num_pages); } @@ -467,7 +461,7 @@ get_dvi_info (int32_t post_location) _tt_abort("Capacity exceeded."); } - if (verbose > 2) { + if (dpx_conf.verbose_level > 2) { dpx_message("DVI File Info\n"); dpx_message("Unit: %" PRIu32 " / %" PRIu32 "\n", dvi_info.unit_num, dvi_info.unit_den); dpx_message("Magnification: %" PRIu32 "\n", dvi_info.mag); @@ -609,7 +603,7 @@ get_dvi_fonts (int32_t post_location) _tt_abort(invalid_signature); } } - if (verbose > 2) { + if (dpx_conf.verbose_level > 2) { unsigned int i; dpx_message("\n"); @@ -635,7 +629,7 @@ static void get_comment (void) _tt_abort(invalid_signature); } dvi_info.comment[length] = '\0'; - if (verbose) { + if (dpx_conf.verbose_level > 0) { dpx_message("DVI Comment: %s\n", dvi_info.comment); } } @@ -749,7 +743,7 @@ dvi_do_special (const void *buffer, int32_t size) mag = dvi_tell_mag(); if (spc_exec_special(p, size, x_user, y_user, mag) < 0) { - if (verbose) { + if (dpx_conf.verbose_level > 0) { dump(p, p + size); } } @@ -772,7 +766,7 @@ dvi_locate_font (const char *tfm_name, spt_t ptsize) int subfont_id = -1, font_id; /* VF or device font ID */ fontmap_rec *mrec; - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message("<%s@%.2fpt", tfm_name, ptsize * dvi2pts); need_more_fonts(1); @@ -818,7 +812,7 @@ dvi_locate_font (const char *tfm_name, spt_t ptsize) if (font_id >= 0) { loaded_fonts[cur_id].type = VIRTUAL; loaded_fonts[cur_id].font_id = font_id; - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message("(VF)>"); return cur_id; } @@ -848,7 +842,7 @@ dvi_locate_font (const char *tfm_name, spt_t ptsize) else { loaded_fonts[cur_id].type = VIRTUAL; loaded_fonts[cur_id].font_id = font_id; - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message("(OVF)>"); return cur_id; } @@ -886,8 +880,15 @@ dvi_locate_font (const char *tfm_name, spt_t ptsize) dpx_warning(">> Please check if kpathsea library can find this font: %s", mrec1->font_name); } } else if (mrec && !mrec->map_name) { - dpx_warning(">> This font is mapped to a physical font \"%s\".", mrec->font_name); - dpx_warning(">> Please check if kpathsea library can find this font: %s", mrec->font_name); + char *finaldot = strrchr(mrec->font_name, '.'); + if (finaldot && strcasecmp(finaldot, ".pfa") == 0) { + /* type1 fonts with pfa format are not supported */ + dpx_warning("This font is mapped to a physical font \"%s\".", mrec->font_name); + _tt_abort("Sorry, pfa format not supported; please convert the font to pfb, e.g., with t1binary."); + } else { + dpx_warning(">> This font is mapped to a physical font \"%s\".", mrec->font_name); + dpx_warning(">> Please check if kpathsea library can find this font: %s", mrec->font_name); + } } else { dpx_warning(">> There are no valid font mapping entry for this font."); dpx_warning(">> Font file name \"%s\" was assumed but failed to locate that font.", tfm_name); @@ -897,7 +898,7 @@ dvi_locate_font (const char *tfm_name, spt_t ptsize) loaded_fonts[cur_id].type = PHYSICAL; loaded_fonts[cur_id].font_id = font_id; - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message(">"); return cur_id; @@ -918,7 +919,7 @@ dvi_locate_native_font (const char *filename, uint32_t index, struct tt_hhea_table *hhea; int is_dfont = 0, is_type1 = 0; - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message("<%s@%.2fpt", filename, ptsize * dvi2pts); if ((handle = dpx_open_dfont_file(filename)) != NULL) @@ -1015,7 +1016,7 @@ dvi_locate_native_font (const char *filename, uint32_t index, loaded_fonts[cur_id].slant = mrec->opt.slant; loaded_fonts[cur_id].embolden = mrec->opt.bold; - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message(">"); return cur_id; @@ -1248,7 +1249,7 @@ dvi_rule (int32_t width, int32_t height) void dvi_dirchg (unsigned char dir) { - if (verbose) + if (dpx_conf.verbose_level > 0) fprintf(stderr, " > dvi_dirchg %d\n", dir); dvi_state.d = dir; pdf_dev_set_dirmode(dvi_state.d); /* 0: horizontal, 1,3: vertical */ @@ -1429,6 +1430,20 @@ do_fnt (uint32_t tex_id) def_fonts[i].point_size); } loaded_fonts[font_id].rgba_color = def_fonts[i].rgba_color; + /* Opacity: 0xff is fully opaque. */ + if ((loaded_fonts[font_id].rgba_color & 0xff) == 0xff) { + loaded_fonts[font_id].xgs_id = -1; + } else { + pdf_obj *xgs_dict; + int a = loaded_fonts[font_id].rgba_color & 0xff; + + /* Inefficient but don't care as transparency is not expected to be frequently used. */ + xgs_dict = pdf_new_dict(); + pdf_add_dict(xgs_dict, pdf_new_name("Type"), pdf_new_name("ExtGState")); + pdf_add_dict(xgs_dict, pdf_new_name("ca"), pdf_new_number(a/255.0)); + pdf_add_dict(xgs_dict, pdf_new_name("CA"), pdf_new_number(a/255.0)); + loaded_fonts[font_id].xgs_id = pdf_defineresource("ExtGState", NULL, xgs_dict, 0); + } loaded_fonts[font_id].source = DVI; def_fonts[i].used = 1; def_fonts[i].font_id = font_id; @@ -1646,6 +1661,23 @@ do_glyphs (int do_actual_text) (double)((unsigned char)(font->rgba_color >> 16) & 0xff) / 255, (double)((unsigned char)(font->rgba_color >> 8) & 0xff) / 255); pdf_color_push(&color, &color); + /* Opacity: + * Enter graphics_mode and then enclose with save/resotre + * since pdf_color_pop() may not restore graphics state. + */ + if (font->xgs_id >= 0) { + pdf_obj *ref; + char resname[16]; + char content[22]; + + sprintf(resname, "Xtx_Gs_%08x", current_font); + ref = pdf_get_resource_reference(font->xgs_id); + pdf_doc_add_page_resource("ExtGState", resname, ref); + graphics_mode(); + pdf_dev_gsave(); + sprintf(content, " /%s gs ", resname); + pdf_doc_add_page_content(content, strlen(content)); + } } for (i = 0; i < slen; i++) { @@ -1694,6 +1726,10 @@ do_glyphs (int do_actual_text) } if (font->rgba_color != 0xffffffff) { + if (font->xgs_id >= 0) { + graphics_mode(); + pdf_dev_grestore(); + } pdf_color_pop(); } free(xloc); @@ -2121,12 +2157,114 @@ read_length (double *vp, double mag, const char **pp, const char *endptr) return error; } +#include "dpx-pdfencrypt.h" + +static int +scan_special_encrypt (int *key_bits, int32_t *permission, char *opassword, char *upassword, + const char **curptr, const char *endptr) +{ + int error = 0; + const char *p = *curptr; + + skip_white(&p, endptr); + + opassword[0] = '\0'; + upassword[0] = '\0'; + while (!error && p < endptr) { + char *kp = parse_c_ident(&p, endptr); + if (!kp) + break; + else { + pdf_obj *obj; + skip_white(&p, endptr); + if (!strcmp(kp, "ownerpw")) { + if ((obj = parse_pdf_string(&p, endptr))) { + if (pdf_string_value(obj)) { + int str_length = (MAX_PWD_LEN - 1 > pdf_string_length(obj) + ? pdf_string_length(obj) : MAX_PWD_LEN - 1); + strncpy(opassword, pdf_string_value(obj), str_length); + opassword[str_length] = '\0'; + } + pdf_release_obj(obj); + } else + error = -1; + } else if (!strcmp(kp, "userpw")) { + if ((obj = parse_pdf_string(&p, endptr))) { + if (pdf_string_value(obj)) { + int str_length = (MAX_PWD_LEN - 1 > pdf_string_length(obj) + ? pdf_string_length(obj) : MAX_PWD_LEN - 1); + strncpy(upassword, pdf_string_value(obj), str_length); + upassword[str_length] = '\0'; + } + pdf_release_obj(obj); + } else + error = -1; + } else if (!strcmp(kp, "length")) { + if ((obj = parse_pdf_number(&p, endptr)) && PDF_OBJ_NUMBERTYPE(obj)) { + *key_bits = (unsigned) pdf_number_value(obj); + } else + error = -1; + if (obj) + pdf_release_obj(obj); + } else if (!strcmp(kp, "perm")) { + if ((obj = parse_pdf_number(&p, endptr)) && PDF_OBJ_NUMBERTYPE(obj)) { + *permission = (unsigned) pdf_number_value(obj); + } else + error = -1; + if (obj) + pdf_release_obj(obj); + } else + error = -1; + free(kp); + } + skip_white(&p, endptr); + } + *curptr = p; + + return error; +} + +static int +scan_special_trailerid (unsigned char *id1, unsigned char *id2, + const char **curptr, const char *endptr) +{ + int error = 0; + pdf_obj *id_array; + const char *p = *curptr; + + skip_white(&p, endptr); + id_array = parse_pdf_array(&p, endptr, NULL); + if (id_array) { + if (pdf_array_length(id_array) == 2) { + pdf_obj *tmp1, *tmp2; + tmp1 = pdf_get_array(id_array, 0); + tmp2 = pdf_get_array(id_array, 1); + if (PDF_OBJ_STRINGTYPE(tmp1) && pdf_string_length(tmp1) == 16 && + PDF_OBJ_STRINGTYPE(tmp2) && pdf_string_length(tmp2) == 16) { + memcpy(id1, pdf_string_value(tmp1), 16); + memcpy(id2, pdf_string_value(tmp2), 16); + } else { + error = -1; + } + } else { + error = -1; + } + pdf_release_obj(id_array); + } else { + error = -1; + } + skip_white(&p, endptr); + *curptr = p; + + return error; +} static int scan_special (double *wd, double *ht, double *xo, double *yo, int *lm, int *majorversion, int *minorversion, - int *do_enc, int *key_bits, int32_t *permission, - char *owner_pw, char *user_pw, + int *enable_encryption, int *key_bits, int32_t *permission, + char *opassword, char *upassword, + int *has_id, unsigned char *id1, unsigned char *id2, const char *buf, uint32_t size) { char *q; @@ -2253,50 +2391,19 @@ scan_special (double *wd, double *ht, double *xo, double *yo, int *lm, *majorversion = (int)strtol(kv, NULL, 10); free(kv); } - } else if (ns_pdf && streq_ptr(q, "encrypt") && do_enc) { - *do_enc = 1; - *owner_pw = *user_pw = 0; - while (!error && p < endptr) { - char *kp = parse_c_ident(&p, endptr); - if (!kp) - break; - else { - pdf_obj *obj; - skip_white(&p, endptr); - if (streq_ptr(kp, "ownerpw")) { - if ((obj = parse_pdf_string(&p, endptr))) { - if (pdf_string_value(obj)) - strncpy(owner_pw, pdf_string_value(obj), MAX_PWD_LEN); - pdf_release_obj(obj); - } else - error = -1; - } else if (streq_ptr(kp, "userpw")) { - if ((obj = parse_pdf_string(&p, endptr))) { - if (pdf_string_value(obj)) - strncpy(user_pw, pdf_string_value(obj), MAX_PWD_LEN); - pdf_release_obj(obj); - } else - error = -1; - } else if (streq_ptr(kp, "length")) { - if ((obj = parse_pdf_number(&p, endptr)) && PDF_OBJ_NUMBERTYPE(obj)) { - *key_bits = (unsigned) pdf_number_value(obj); - } else - error = -1; - pdf_release_obj(obj); - } else if (streq_ptr(kp, "perm")) { - if ((obj = parse_pdf_number(&p, endptr)) && PDF_OBJ_NUMBERTYPE(obj)) { - *permission = (unsigned) pdf_number_value(obj); - } else - error = -1; - pdf_release_obj(obj); - } else - error = -1; - free(kp); - } - skip_white(&p, endptr); - } + } else if (enable_encryption && ns_pdf && streq_ptr(q, "encrypt")) { + *enable_encryption = 1; + error = scan_special_encrypt(key_bits, permission, opassword, upassword, &p, endptr); } else if (ns_dvipdfmx && streq_ptr(q, "config")) { dpx_warning("Tectonic does not support `config' special. Ignored."); + } else if (has_id && id1 && id2 && ns_pdf && !strcmp(q, "trailerid")) { + error = scan_special_trailerid(id1, id2, &p, endptr); + if (error) { + dpx_warning("Invalid argument for pdf:trailerid special."); + *has_id = 0; + } else { + *has_id = 1; + } } free(q); } @@ -2311,7 +2418,8 @@ dvi_scan_specials (int page_no, double *x_offset, double *y_offset, int *landscape, int *majorversion, int *minorversion, int *do_enc, int *key_bits, int32_t *permission, - char *owner_pw, char *user_pw) + char *owner_pw, char *user_pw, + int *has_id, unsigned char *id1, unsigned char *id2) { uint32_t offset; unsigned char opcode; @@ -2356,6 +2464,7 @@ dvi_scan_specials (int page_no, if (scan_special(page_width, page_height, x_offset, y_offset, landscape, majorversion, minorversion, do_enc, key_bits, permission, owner_pw, user_pw, + has_id, id1, id2, buf, size)) dpx_warning("Reading special command failed: \"%.*s\"", size, buf); #undef buf @@ -2449,7 +2558,6 @@ dvi_reset_global_state(void) max_def_fonts = 0; compute_boxes = 0; link_annot = 1; - verbose = 0; - - num_loaded_fonts = 0; max_loaded_fonts = 0; + num_loaded_fonts = 0; + max_loaded_fonts = 0; } diff --git a/tectonic/dpx-dvi.h b/tectonic/dpx-dvi.h index 3f34bc51fa..e62c2fdb8e 100644 --- a/tectonic/dpx-dvi.h +++ b/tectonic/dpx-dvi.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -40,7 +40,6 @@ extern int landscape_mode; double get_origin (int x); void dvi_reset_global_state (void); -void dvi_set_verbose (int level); /* returns scale (dvi2pts) */ double dvi_init (const char *dvi_filename, double mag); /* may append .dvi or .xdv to filename */ @@ -81,7 +80,7 @@ void dvi_scan_specials (int page_no, double *x_offset, double *y_offset, int *landscape, int *majorversion, int *minorversion, int *do_enc, int *keybits, int32_t *perm, - char *opasswd, char *upasswd); + char *opasswd, char *upasswd, int *has_id, unsigned char *id1, unsigned char *id2); unsigned int dvi_locate_font (const char *name, spt_t ptsize); /* link or nolink: diff --git a/tectonic/dpx-dvipdfmx.c b/tectonic/dpx-dvipdfmx.c index e3398903c5..76ec78fc9d 100644 --- a/tectonic/dpx-dvipdfmx.c +++ b/tectonic/dpx-dvipdfmx.c @@ -2,7 +2,7 @@ DVIPDFMx, an eXtended version of DVIPDFM by Mark A. Wicks. - Copyright (C) 2002-2017 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, + Copyright (C) 2002-2020 by Jin-Hwan Cho, Matthias Franz, Shunsaku Hirata, the DVIPDFMx project team. Copyright (c) 2006 SIL. (xdvipdfmx extensions for XeTeX support) @@ -36,12 +36,14 @@ #include "core-bridge.h" #include "dpx-cid.h" #include "dpx-dpxconf.h" +#include "dpx-dpxcrypt.h" #include "dpx-dpxfile.h" #include "dpx-dpxutil.h" #include "dpx-dvi.h" #include "dpx-error.h" #include "dpx-fontmap.h" #include "dpx-mem.h" +#include "dpx-mpost.h" #include "dpx-pdfdev.h" #include "dpx-pdfdoc.h" #include "dpx-pdfencrypt.h" @@ -49,6 +51,7 @@ #include "dpx-pdflimits.h" #include "dpx-pdfobj.h" #include "dpx-pdfparse.h" +#include "dpx-pdfximage.h" #include "dpx-spc_tpic.h" #include "dpx-specials.h" #include "dpx-tfm.h" @@ -61,8 +64,6 @@ typedef struct page_range int last; } PageRange; -int is_xdv = 0; -int translate_origin = 0; const XdvipdfmxConfig* dpx_config; #define OPT_TPIC_TRANSPARENT_FILL (1 << 1) @@ -72,11 +73,16 @@ const XdvipdfmxConfig* dpx_config; #define OPT_PDFOBJ_NO_PREDICTOR (1 << 5) #define OPT_PDFOBJ_NO_OBJSTM (1 << 6) +static int pdf_version_major = 1; +static int pdf_version_minor = 5; +static int compression_level = 9; + static char ignore_colors = 0; static double annot_grow = 0.0; static int bookmark_open = 0; static double mag = 1.0; static int font_dpi = 600; +static int enable_thumbnail = 0; /* * Precision is essentially limited to 0.01pt. @@ -89,6 +95,9 @@ static int pdfdecimaldigits = 3; /* -1 means erase all old images and also erase new images */ /* -2 means ignore image cache (default) */ static int image_cache_life = -2; +/* Image format conversion filter template */ +static char *filter_template = NULL; + /* Encryption */ static int do_encryption = 0; @@ -103,8 +112,8 @@ double paper_height = 842.0; static double x_offset = 72.0; static double y_offset = 72.0; int landscape_mode = 0; +static int translate_origin = 0; -int always_embed = 0; /* always embed fonts, regardless of licensing flags */ /* XXX: there are four quasi-redundant versions of this; grp for K_UNIT__PT */ static int @@ -203,15 +212,13 @@ select_paper (const char *paperspec) _tt_abort("Invalid paper size: %s (%.2fx%.2f)", paperspec, paper_width, paper_height); } +PageRange *page_ranges = NULL; +int num_page_ranges = 0; +int max_page_ranges = 0; + static void -select_pages ( - const char *pagespec, - PageRange **ret_page_ranges, - unsigned int *ret_num_page_ranges) +select_pages (const char *pagespec) { - PageRange *page_ranges = NULL; - unsigned int num_page_ranges = 0; - unsigned int max_page_ranges = 0; char *q; const char *p = pagespec; @@ -259,9 +266,6 @@ select_pages ( _tt_abort("Bad page range specification: %s", p); } } - - *ret_page_ranges = page_ranges; - *ret_num_page_ranges = num_page_ranges; } #define SWAP(v1,v2) do {\ @@ -271,7 +275,7 @@ select_pages ( } while (0) static void -do_dvi_pages (PageRange *page_ranges, unsigned int num_page_ranges) +do_dvi_pages (void) { int page_no, step; unsigned int page_count, i; @@ -281,6 +285,16 @@ do_dvi_pages (PageRange *page_ranges, unsigned int num_page_ranges) spc_exec_at_begin_document(); + if (num_page_ranges == 0) { + if (!page_ranges) { + page_ranges = NEW(1, struct page_range); + max_page_ranges = 1; + } + page_ranges[0].first = 0; + page_ranges[0].last = -1; /* last page */ + num_page_ranges = 1; + } + init_paper_width = page_width = paper_width; init_paper_height = page_height = paper_height; page_count = 0; @@ -308,8 +322,10 @@ do_dvi_pages (PageRange *page_ranges, unsigned int num_page_ranges) page_width = paper_width; page_height = paper_height; w = page_width; h = page_height; lm = landscape_mode; xo = x_offset; yo = y_offset; - dvi_scan_specials(page_no, &w, &h, &xo, &yo, &lm, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - if (lm != landscape_mode) { + dvi_scan_specials(page_no, + &w, &h, &xo, &yo, &lm, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + if (lm != landscape_mode) { /* already swapped for the first page */ SWAP(w, h); landscape_mode = lm; } @@ -353,6 +369,25 @@ do_dvi_pages (PageRange *page_ranges, unsigned int num_page_ranges) spc_exec_at_end_document(); } +static void +compute_id_string (unsigned char *id, const char *producer, + const char *dviname, const char *pdfname) +{ + char datestr[32]; + MD5_CONTEXT md5; + + MD5_init(&md5); + /* Don't use timezone for compatibility */ + dpx_util_format_asn_date(datestr, 0); + MD5_write(&md5, (const unsigned char *)datestr, strlen(datestr)); + if (producer) + MD5_write(&md5, (const unsigned char *)producer, strlen(producer)); + if (dviname) + MD5_write(&md5, (const unsigned char *)dviname, strlen(dviname)); + if (pdfname) + MD5_write(&md5, (const unsigned char *)pdfname, strlen(pdfname)); + MD5_final(id, &md5); +} int dvipdfmx_main ( @@ -367,18 +402,24 @@ dvipdfmx_main ( unsigned int verbose, time_t build_date) { - bool enable_object_stream = true; double dvi2pts; - unsigned int num_page_ranges = 0; - PageRange *page_ranges = NULL; + const char *creator = NULL; + char oplain[128] = "", uplain[128] = ""; + int has_id = 0; + unsigned char id1[16], id2[16]; + struct pdf_setting settings; assert(pdf_filename); assert(dvi_filename); translate_origin = translate; + page_ranges = NULL; + num_page_ranges = 0; + max_page_ranges = 0; dvi_reset_global_state(); + mps_reset_global_state(); tfm_reset_global_state(); vf_reset_global_state(); pdf_dev_reset_global_state(); @@ -388,18 +429,9 @@ dvipdfmx_main ( if (quiet) { shut_up(2); } else { - - dvi_set_verbose(verbose); - pdf_dev_set_verbose(verbose); - pdf_doc_set_verbose(verbose); - pdf_enc_set_verbose(verbose); - pdf_obj_set_verbose(verbose); - pdf_fontmap_set_verbose(verbose); - dpx_file_set_verbose(verbose); - tt_aux_set_verbose(verbose); + dpx_conf.verbose_level = verbose; } - pdf_set_compression(compress ? 9 : 0); pdf_font_set_deterministic_unique_tags(deterministic_tags ? 1 : 0); pdf_init_fontmaps(); /* This must come before parsing options... */ @@ -423,15 +455,7 @@ dvipdfmx_main ( pdf_load_fontmap_file("ckx.map", FONTMAP_RMODE_APPEND); if (pagespec) { - select_pages(pagespec, &page_ranges, &num_page_ranges); - } - if (!page_ranges) { - page_ranges = NEW(1, PageRange); - } - if (num_page_ranges == 0) { - page_ranges[0].first = 0; - page_ranges[0].last = -1; /* last page */ - num_page_ranges = 1; + select_pages(pagespec); } /*kpse_init_prog("", font_dpi, NULL, NULL); @@ -439,76 +463,93 @@ dvipdfmx_main ( pdf_font_set_dpi(font_dpi); dpx_delete_old_cache(image_cache_life); - pdf_enc_compute_id_string(dvi_filename, pdf_filename); - { - int ver_major = 0, ver_minor = 0; - char owner_pw[MAX_PWD_LEN], user_pw[MAX_PWD_LEN]; /* Dependency between DVI and PDF side is rather complicated... */ dvi2pts = dvi_init(dvi_filename, mag); if (dvi2pts == 0.0) _tt_abort("dvi_init() failed!"); - pdf_doc_set_creator(dvi_comment()); - + creator = dvi_comment(); /* Set PDF Creator entry */ dvi_scan_specials(0, &paper_width, &paper_height, &x_offset, &y_offset, &landscape_mode, - &ver_major, &ver_minor, - &do_encryption, &key_bits, &permission, owner_pw, user_pw); - if (ver_minor >= PDF_VERSION_MIN && ver_minor <= PDF_VERSION_MAX) { - pdf_set_version(ver_minor); - } - if (do_encryption) { - if (!(key_bits >= 40 && key_bits <= 128 && (key_bits % 8 == 0)) && - key_bits != 256) - _tt_abort("Invalid encryption key length specified: %u", key_bits); - else if (key_bits > 40 && pdf_get_version() < 4) - _tt_abort("Chosen key length requires at least PDF 1.4. " \ - "Use \"-V 4\" to change."); - do_encryption = 1; - pdf_enc_set_passwd(key_bits, permission, owner_pw, user_pw); - } - if (landscape_mode) { - SWAP(paper_width, paper_height); - } + &pdf_version_major, &pdf_version_minor, + &do_encryption, &key_bits, &permission, oplain, uplain, + &has_id, id1, id2); } - pdf_files_init(); + /* Encryption and Other Settings */ + { + memset(&settings.encrypt, 0, sizeof(struct pdf_enc_setting)); + settings.enable_encrypt = do_encryption; + settings.encrypt.use_aes = 1; + settings.encrypt.encrypt_metadata = 1; + settings.encrypt.key_size = key_bits; + settings.encrypt.permission = permission; + settings.encrypt.uplain = uplain; + settings.encrypt.oplain = oplain; + } - if (opt_flags & OPT_PDFOBJ_NO_OBJSTM) - enable_object_stream = false; + if (opt_flags & OPT_PDFOBJ_NO_OBJSTM) { + settings.object.enable_objstm = 0; + } else { + settings.object.enable_objstm = 1; + } + if (opt_flags & OPT_PDFOBJ_NO_PREDICTOR) { + settings.object.enable_predictor = 0; + } else { + settings.object.enable_predictor = 1; + } /* Set default paper size here so that all page's can inherite it. * annot_grow: Margin of annotation. * bookmark_open: Miximal depth of open bookmarks. */ - pdf_open_document(pdf_filename, do_encryption, enable_object_stream, - paper_width, paper_height, annot_grow, bookmark_open, - !(opt_flags & OPT_PDFDOC_NO_DEST_REMOVE)); - - /* Ignore_colors placed here since - * they are considered as device's capacity. + if (landscape_mode) { + SWAP(paper_width, paper_height); + } + settings.media_width = paper_width; + settings.media_height = paper_height; + settings.annot_grow_amount = annot_grow; + settings.outline_open_depth = bookmark_open; + settings.check_gotos = !(opt_flags & OPT_PDFDOC_NO_DEST_REMOVE); + + settings.device.dvi2pts = dvi2pts; + settings.device.precision = pdfdecimaldigits; + settings.device.ignore_colors = ignore_colors; + + set_distiller_template(filter_template); + /* This must come before pdf_open_document where initialization + * of pdf_enc takes place. */ pdf_init_device(dvi2pts, pdfdecimaldigits, ignore_colors); + { + int version = pdf_version_major * 10 + pdf_version_minor; + pdf_set_version(version); + } + pdf_set_compression(compress ? compression_level : 0); + if (enable_thumbnail) + pdf_doc_enable_manual_thumbnails(); + + if (!has_id) { + const char *producer = "xdvipdfmx-0.1, Copyright 2002-2015 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata"; + compute_id_string(id1, producer, dvi_filename, pdf_filename); + memcpy(id2, id1, 16); + } + + /* Initialize PDF document creation routine. */ + pdf_open_document(pdf_filename, creator, id1, id2, settings); if (opt_flags & OPT_CIDFONT_FIXEDPITCH) CIDFont_set_flags(CIDFONT_FORCE_FIXEDPITCH); - /* Please move this to spc_init_specials(). */ if (opt_flags & OPT_TPIC_TRANSPARENT_FILL) tpic_set_fill_mode(1); + if (translate_origin) + mps_set_translate_origin(1); - if (opt_flags & OPT_PDFOBJ_NO_PREDICTOR) - pdf_set_use_predictor(0); /* No prediction */ - - do_dvi_pages(page_ranges, num_page_ranges); - - pdf_files_close(); + do_dvi_pages(); - /* Order of close... */ - pdf_close_device (); - /* pdf_close_document flushes XObject (image) and other resources. */ pdf_close_document(); pdf_close_fontmaps(); /* pdf_font may depend on fontmap. */ diff --git a/tectonic/dpx-dvipdfmx.h b/tectonic/dpx-dvipdfmx.h index 7849600699..2605972c23 100644 --- a/tectonic/dpx-dvipdfmx.h +++ b/tectonic/dpx-dvipdfmx.h @@ -1,6 +1,6 @@ /* DVIPDFMx, an eXtended version of DVIPDFM by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, the DVIPDFMx project team. Copyright (c) 2006 SIL. (xdvipdfmx extensions for XeTeX support) @@ -31,8 +31,6 @@ #define DVIPDFMX_PROG_NAME "xdvipdfmx" -extern int is_xdv; -extern int translate_origin; extern time_t source_date_epoch; extern const XdvipdfmxConfig* dpx_config; diff --git a/tectonic/dpx-epdf.c b/tectonic/dpx-epdf.c index ec102779e6..d52a237991 100644 --- a/tectonic/dpx-epdf.c +++ b/tectonic/dpx-epdf.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -43,262 +43,8 @@ #include "dpx-pdfparse.h" #include "dpx-pdfximage.h" -static int rect_equal (pdf_obj *rect1, pdf_obj *rect2); -/* - * From PDFReference15_v6.pdf (p.119 and p.834) - * - * MediaBox rectangle (Required; inheritable) - * - * The media box defines the boundaries of the physical medium on which the - * page is to be printed. It may include any extended area surrounding the - * finished page for bleed, printing marks, or other such purposes. It may - * also include areas close to the edges of the medium that cannot be marked - * because of physical limitations of the output device. Content falling - * outside this boundary can safely be discarded without affecting the - * meaning of the PDF file. - * - * CropBox rectangle (Optional; inheritable) - * - * The crop box defines the region to which the contents of the page are to be - * clipped (cropped) when displayed or printed. Unlike the other boxes, the - * crop box has no defined meaning in terms of physical page geometry or - * intended use; it merely imposes clipping on the page contents. However, - * in the absence of additional information (such as imposition instructions - * specified in a JDF or PJTF job ticket), the crop box will determine how - * the page's contents are to be positioned on the output medium. The default - * value is the page's media box. - * - * BleedBox rectangle (Optional; PDF 1.3) - * - * The bleed box (PDF 1.3) defines the region to which the contents of the - * page should be clipped when output in a production environment. This may - * include any extra bleed area needed to accommodate the physical - * limitations of cutting, folding, and trimming equipment. The actual printed - * page may include printing marks that fall outside the bleed box. - * The default value is the page's crop box. - * - * TrimBox rectangle (Optional; PDF 1.3) - * - * The trim box (PDF 1.3) defines the intended dimensions of the finished page - * after trimming. It may be smaller than the media box, to allow for - * production-related content such as printing instructions, cut marks, or - * color bars. The default value is the page’s crop box. - * - * ArtBox rectangle (Optional; PDF 1.3) - * - * The art box (PDF 1.3) defines the extent of the page's meaningful content - * (including potential white space) as intended by the page's creator. - * The default value is the page's crop box. - * - * Rotate integer (Optional; inheritable) - * - * The number of degrees by which the page should be rotated clockwise when - * displayed or printed. The value must be a multiple of 90. Default value: 0. - */ - -static int -rect_equal (pdf_obj *rect1, pdf_obj *rect2) -{ - int i; - - if (!rect1 || !rect2) - return 0; - for (i = 0; i < 4; i++) { - if (pdf_number_value(pdf_get_array(rect1, i)) != - pdf_number_value(pdf_get_array(rect2, i))) - return 0; - } - - return 1; -} - static pdf_obj* -pdf_get_page_obj (pdf_file *pf, int page_no, - pdf_obj **ret_bbox, pdf_obj **ret_resources) -{ - pdf_obj *page_tree; - pdf_obj *bbox = NULL, *resources = NULL, *rotate = NULL; - int page_idx; - - /* - * Get Page Tree. - */ - page_tree = NULL; - { - pdf_obj *trailer, *catalog; - pdf_obj *markinfo, *tmp; - - trailer = pdf_file_get_trailer(pf); - - if (pdf_lookup_dict(trailer, "Encrypt")) { - dpx_warning("This PDF document is encrypted."); - pdf_release_obj(trailer); - return NULL; - } - - catalog = pdf_deref_obj(pdf_lookup_dict(trailer, "Root")); - if (!PDF_OBJ_DICTTYPE(catalog)) { - dpx_warning("Can't read document catalog."); - pdf_release_obj(trailer); - pdf_release_obj(catalog); - return NULL; - } - pdf_release_obj(trailer); - - markinfo = pdf_deref_obj(pdf_lookup_dict(catalog, "MarkInfo")); - if (markinfo) { - tmp = pdf_lookup_dict(markinfo, "Marked"); - if (PDF_OBJ_BOOLEANTYPE(tmp) && pdf_boolean_value(tmp)) - dpx_warning("PDF file is tagged... Ignoring tags."); - pdf_release_obj(markinfo); - } - - page_tree = pdf_deref_obj(pdf_lookup_dict(catalog, "Pages")); - pdf_release_obj(catalog); - } - if (!page_tree) { - dpx_warning("Page tree not found."); - return NULL; - } - - /* - * Negative page numbers are counted from the back. - */ - { - int count = pdf_number_value(pdf_lookup_dict(page_tree, "Count")); - page_idx = page_no + (page_no >= 0 ? -1 : count); - if (page_idx < 0 || page_idx >= count) { - dpx_warning("Page %d does not exist.", page_no); - pdf_release_obj(page_tree); - return NULL; - } - page_no = page_idx+1; - } - - /* - * Seek correct page. Get Media/Crop Box. - * Media box and resources can be inherited. - */ - { - pdf_obj *kids_ref, *kids; - pdf_obj *crop_box = NULL; - pdf_obj *tmp; - - tmp = pdf_lookup_dict(page_tree, "Resources"); - resources = tmp ? pdf_deref_obj(tmp) : pdf_new_dict(); - - while (1) { - int kids_length, i; - - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "MediaBox")))) { - pdf_release_obj(bbox); - bbox = tmp; - } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "BleedBox")))) { - if (!rect_equal(tmp, bbox)) { - pdf_release_obj(bbox); - bbox = tmp; - } else { - pdf_release_obj(tmp); - } - } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "TrimBox")))) { - if (!rect_equal(tmp, bbox)) { - pdf_release_obj(bbox); - bbox = tmp; - } else { - pdf_release_obj(tmp); - } - } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "ArtBox")))) { - if (!rect_equal(tmp, bbox)) { - pdf_release_obj(bbox); - bbox = tmp; - } else { - pdf_release_obj(tmp); - } - } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "CropBox")))) { - pdf_release_obj(crop_box); - crop_box = tmp; - } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Rotate")))) { - pdf_release_obj(rotate); - rotate = tmp; - } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Resources")))) { - pdf_release_obj(resources); - resources = tmp; - } - - kids_ref = pdf_lookup_dict(page_tree, "Kids"); - if (!kids_ref) - break; - kids = pdf_deref_obj(kids_ref); - kids_length = pdf_array_length(kids); - - for (i = 0; i < kids_length; i++) { - int count; - - pdf_release_obj(page_tree); - page_tree = pdf_deref_obj(pdf_get_array(kids, i)); - - tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Count")); - if (tmp) { - /* Pages object */ - count = pdf_number_value(tmp); - pdf_release_obj(tmp); - } else { - /* Page object */ - count = 1; - } - if (page_idx < count) - break; - - page_idx -= count; - } - - pdf_release_obj(kids); - - if (i == kids_length) { - dpx_warning("Page %d not found! Broken PDF file?", page_no); - pdf_release_obj(bbox); - pdf_release_obj(crop_box); - pdf_release_obj(rotate); - pdf_release_obj(resources); - pdf_release_obj(page_tree); - return NULL; - } - } - if (crop_box) { - pdf_release_obj(bbox); - bbox = crop_box; - } - } - - if (!bbox) { - dpx_warning("No BoundingBox information available."); - pdf_release_obj(page_tree); - pdf_release_obj(resources); - pdf_release_obj(rotate); - return NULL; - } - - if (rotate) { - pdf_release_obj(rotate); - rotate = NULL; - } - - if (ret_bbox != NULL) - *ret_bbox = bbox; - if (ret_resources != NULL) - *ret_resources = resources; - - return page_tree; -} - -static pdf_obj* -pdf_get_page_content (pdf_obj* page) +get_page_content (pdf_file *pf, pdf_obj* page) { pdf_obj *contents, *content_new; @@ -306,7 +52,7 @@ pdf_get_page_content (pdf_obj* page) if (!contents) return NULL; - if (pdf_obj_typeof(contents) == PDF_NULL) { + if (PDF_OBJ_NULLTYPE(contents)) { /* empty page */ pdf_release_obj(contents); /* TODO: better don't include anything if the page is empty */ @@ -316,29 +62,25 @@ pdf_get_page_content (pdf_obj* page) * Concatenate all content streams. */ pdf_obj *content_seg; - int idx = 0; + int i; content_new = pdf_new_stream(STREAM_COMPRESS); - for (;;) { - content_seg = pdf_deref_obj(pdf_get_array(contents, idx)); - if (!content_seg) - break; - else if (PDF_OBJ_NULLTYPE(content_seg)) { - /* Silently ignore. */ - } else if (!PDF_OBJ_STREAMTYPE(content_seg)) { - dpx_warning("Page content not a stream object. Broken PDF file?"); - pdf_release_obj(content_seg); - pdf_release_obj(content_new); - pdf_release_obj(contents); + for (i = 0; i < pdf_array_length(contents); i++) { + content_seg = pdf_deref_obj(pdf_get_array(contents, i)); + if (!content_seg) { + dpx_warning("Could not read page content stream."); + pdf_release_obj(content_new); return NULL; - } else if (pdf_concat_stream(content_new, content_seg) < 0) { - dpx_warning("Could not handle content stream with multiple segments."); + } + if (PDF_OBJ_STREAMTYPE(content_seg)) { + pdf_concat_stream(content_new, content_seg); + } else if (!PDF_OBJ_NULLTYPE(content_seg)) { + dpx_warning("Page content not a stream object. Broken PDF file?"); pdf_release_obj(content_seg); pdf_release_obj(content_new); pdf_release_obj(contents); return NULL; } pdf_release_obj(content_seg); - idx++; } pdf_release_obj(contents); contents = content_new; @@ -350,12 +92,7 @@ pdf_get_page_content (pdf_obj* page) } /* Flate the contents if necessary. */ content_new = pdf_new_stream(STREAM_COMPRESS); - if (pdf_concat_stream(content_new, contents) < 0) { - dpx_warning("Could not handle a content stream."); - pdf_release_obj(contents); - pdf_release_obj(content_new); - return NULL; - } + pdf_concat_stream(content_new, contents); pdf_release_obj(contents); contents = content_new; } @@ -379,11 +116,6 @@ pdf_include_page (pdf_ximage *ximage, if (!pf) return -1; - if (pdf_file_get_version(pf) > pdf_get_version()) { - dpx_warning("Trying to include PDF file which has newer version number " \ - "than output PDF: 1.%d.", pdf_get_version()); - } - pdf_ximage_init_form_info(&info); if (options.page_no == 0) @@ -409,51 +141,12 @@ pdf_include_page (pdf_ximage *ximage, pdf_release_obj(tmp); } - contents = pdf_deref_obj(pdf_lookup_dict(page, "Contents")); - pdf_release_obj(page); - page = NULL; - /* * Handle page content stream. */ - { - pdf_obj *content_new; - - if (!contents) { - /* - * Empty page - */ - content_new = pdf_new_stream(0); - /* TODO: better don't include anything if the page is empty */ - } else if (PDF_OBJ_STREAMTYPE(contents)) { - /* - * We must import the stream because its dictionary - * may contain indirect references. - */ - content_new = pdf_import_object(contents); - } else if (PDF_OBJ_ARRAYTYPE(contents)) { - /* - * Concatenate all content streams. - */ - int idx, len = pdf_array_length(contents); - content_new = pdf_new_stream(STREAM_COMPRESS); - for (idx = 0; idx < len; idx++) { - pdf_obj *content_seg = pdf_deref_obj(pdf_get_array(contents, idx)); - if (!PDF_OBJ_STREAMTYPE(content_seg) || - pdf_concat_stream(content_new, content_seg) < 0) { - pdf_release_obj(content_seg); - pdf_release_obj(content_new); - goto error; - } - pdf_release_obj(content_seg); - } - } else { - goto error; - } - - pdf_release_obj(contents); - contents = content_new; - } + contents = get_page_content(pf, page); + pdf_release_obj(page); + page = NULL; /* * Add entries to contents stream dictionary. @@ -586,6 +279,8 @@ pdf_copy_clip (rust_input_handle_t image_file, int pageNo, double x_user, double char *save_path, *temp; pdf_tmatrix M; double stack[6]; + pdf_rect bbox; + pdf_tmatrix mtrx; pdf_file *pf; pf = pdf_open(NULL, image_file); @@ -595,13 +290,13 @@ pdf_copy_clip (rust_input_handle_t image_file, int pageNo, double x_user, double pdf_dev_currentmatrix(&M); pdf_invertmatrix(&M); M.e += x_user; M.f += y_user; - page_tree = pdf_get_page_obj (pf, pageNo, NULL, NULL); + + page_tree = pdf_doc_get_page(pf, pageNo, 0, &bbox, &mtrx, NULL); if (!page_tree) { pdf_close(pf); return -1; } - - contents = pdf_get_page_content(page_tree); + contents = get_page_content(pf, page_tree); pdf_release_obj(page_tree); if (!contents) { pdf_close(pf); diff --git a/tectonic/dpx-fontmap.c b/tectonic/dpx-fontmap.c index abdbba8e10..ea05227020 100644 --- a/tectonic/dpx-fontmap.c +++ b/tectonic/dpx-fontmap.c @@ -23,6 +23,7 @@ #include "dpx-fontmap.h" #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" #include "dpx-dpxutil.h" #include "dpx-error.h" @@ -33,14 +34,6 @@ /* CIDFont */ static char *strip_options (const char *map_name, fontmap_opt *opt); -static int verbose = 0; -void -pdf_fontmap_set_verbose (int level) -{ - verbose = level; -} - - void pdf_init_fontmap_record (fontmap_rec *mrec) { @@ -72,7 +65,7 @@ pdf_init_fontmap_record (fontmap_rec *mrec) mrec->opt.style = FONTMAP_STYLE_NONE; mrec->opt.stemv = -1; /* not given explicitly by an option */ - mrec->opt.cff_charsets = NULL; + mrec->opt.use_glyph_encoding = 0; } void @@ -131,7 +124,7 @@ pdf_copy_fontmap_record (fontmap_rec *dst, const fontmap_rec *src) dst->opt.style = src->opt.style; dst->opt.stemv = src->opt.stemv; - dst->opt.cff_charsets = src->opt.cff_charsets; + dst->opt.use_glyph_encoding = src->opt.use_glyph_encoding; } @@ -728,7 +721,7 @@ pdf_append_fontmap_record (const char *kp, const fontmap_rec *vp) return -1; } - if (verbose > 3) + if (dpx_conf.verbose_level > 3) dpx_message("fontmap>> append key=\"%s\"...", kp); fnt_name = chop_sfd_name(kp, &sfd_name); @@ -767,7 +760,7 @@ pdf_append_fontmap_record (const char *kp, const fontmap_rec *vp) } ht_insert_table(fontmap, kp, strlen(kp), mrec); } - if (verbose > 3) + if (dpx_conf.verbose_level > 3) dpx_message("\n"); return 0; @@ -781,7 +774,7 @@ pdf_remove_fontmap_record (const char *kp) if (!kp) return -1; - if (verbose > 3) + if (dpx_conf.verbose_level > 3) dpx_message("fontmap>> remove key=\"%s\"...", kp); fnt_name = chop_sfd_name(kp, &sfd_name); @@ -792,13 +785,13 @@ pdf_remove_fontmap_record (const char *kp) subfont_ids = sfd_get_subfont_ids(sfd_name, &n); if (!subfont_ids) return -1; - if (verbose > 3) + if (dpx_conf.verbose_level > 3) dpx_message("\nfontmap>> Expand @%s@:", sfd_name); while (n-- > 0) { tfm_name = make_subfont_name(kp, sfd_name, subfont_ids[n]); if (!tfm_name) continue; - if (verbose > 3) + if (dpx_conf.verbose_level > 3) dpx_message(" %s", tfm_name); ht_remove_table(fontmap, tfm_name, strlen(tfm_name)); free(tfm_name); @@ -809,7 +802,7 @@ pdf_remove_fontmap_record (const char *kp) ht_remove_table(fontmap, kp, strlen(kp)); - if (verbose > 3) + if (dpx_conf.verbose_level > 3) dpx_message("\n"); return 0; @@ -826,7 +819,7 @@ pdf_insert_fontmap_record (const char *kp, const fontmap_rec *vp) return NULL; } - if (verbose > 3) + if (dpx_conf.verbose_level > 3) dpx_message("fontmap>> insert key=\"%s\"...", kp); fnt_name = chop_sfd_name(kp, &sfd_name); @@ -841,13 +834,13 @@ pdf_insert_fontmap_record (const char *kp, const fontmap_rec *vp) free(sfd_name); return NULL; } - if (verbose > 3) + if (dpx_conf.verbose_level > 3) dpx_message("\nfontmap>> Expand @%s@:", sfd_name); while (n-- > 0) { tfm_name = make_subfont_name(kp, sfd_name, subfont_ids[n]); if (!tfm_name) continue; - if (verbose > 3) + if (dpx_conf.verbose_level > 3) dpx_message(" %s", tfm_name); mrec = NEW(1, fontmap_rec); pdf_init_fontmap_record(mrec); @@ -868,7 +861,7 @@ pdf_insert_fontmap_record (const char *kp, const fontmap_rec *vp) } ht_insert_table(fontmap, kp, strlen(kp), mrec); - if (verbose > 3) + if (dpx_conf.verbose_level > 3) dpx_message("\n"); return mrec; @@ -969,7 +962,7 @@ pdf_load_fontmap_file (const char *filename, int mode) assert(filename); assert(fontmap); - if (verbose) + if (dpx_conf.verbose_level) dpx_message(""); return error; @@ -1048,7 +1041,7 @@ pdf_insert_native_fontmap_record (const char *path, uint32_t index, fontmap_key = xmalloc(strlen(path) + 40); // CHECK sprintf(fontmap_key, "%s/%d/%c/%d/%d/%d", path, index, layout_dir == 0 ? 'H' : 'V', extend, slant, embolden); - if (verbose) + if (dpx_conf.verbose_level) dpx_message("opt.extend = extend / 65536.0; mrec->opt.slant = slant / 65536.0; mrec->opt.bold = embolden / 65536.0; + mrec->opt.use_glyph_encoding = 1; ret = pdf_insert_fontmap_record(mrec->map_name, mrec); pdf_clear_fontmap_record(mrec); free(mrec); - if (verbose) + if (dpx_conf.verbose_level) dpx_message(">"); return ret; diff --git a/tectonic/dpx-fontmap.h b/tectonic/dpx-fontmap.h index 1409e34167..6fd2e60f9e 100644 --- a/tectonic/dpx-fontmap.h +++ b/tectonic/dpx-fontmap.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -49,14 +49,13 @@ typedef struct fontmap_opt { char *otl_tags; /* currently unused */ char *tounicode; /* not implemented yet */ - void *cff_charsets; - double design_size; /* unused */ char *charcoll; /* Adobe-Japan1-4, etc. */ int index; /* TTC index */ int style; /* ,Bold, etc. */ int stemv; /* StemV value especially for CJK fonts */ + int use_glyph_encoding; /* XeTeX support */ } fontmap_opt; typedef struct fontmap_rec { @@ -76,8 +75,6 @@ typedef struct fontmap_rec { fontmap_opt opt; } fontmap_rec; -void pdf_fontmap_set_verbose (int level); - void pdf_init_fontmaps (void); void pdf_close_fontmaps (void); diff --git a/tectonic/dpx-jp2image.c b/tectonic/dpx-jp2image.c index b481e632b5..dcdbcfdc8e 100644 --- a/tectonic/dpx-jp2image.c +++ b/tectonic/dpx-jp2image.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Matthias Franz, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Matthias Franz, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -32,6 +32,7 @@ #include #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-error.h" #include "dpx-mfileio.h" #include "dpx-numbers.h" @@ -353,14 +354,12 @@ check_for_jp2 (FILE *fp) int jp2_include_image (pdf_ximage *ximage, FILE *fp) { - unsigned int pdf_version; int smask = 0; pdf_obj *stream, *stream_dict; ximage_info info; - pdf_version = pdf_get_version(); - if (pdf_version < 5) { - dpx_warning("JPEG 2000 support requires PDF version >= 1.5 (Current setting 1.%d)\n", pdf_version); + if (pdf_check_version(1, 5) < 0) { + dpx_warning("JPEG 2000 support requires PDF version >= 1.5 (Current setting %d.%d)\n", pdf_get_version_major(), pdf_get_version_minor()); return -1; } diff --git a/tectonic/dpx-jpegimage.c b/tectonic/dpx-jpegimage.c index 1fd13e5111..1b0a096632 100644 --- a/tectonic/dpx-jpegimage.c +++ b/tectonic/dpx-jpegimage.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -56,6 +56,7 @@ #include #include +#include "dpx-dpxconf.h" #include "dpx-error.h" #include "dpx-mem.h" #include "dpx-mfileio.h" @@ -269,7 +270,7 @@ jpeg_include_image (pdf_ximage *ximage, rust_input_handle_t handle) pdf_add_dict(stream_dict, pdf_new_name("Filter"), pdf_new_name("DCTDecode")); /* XMP Metadata */ - if (pdf_get_version() >= 4) { + if (pdf_check_version(1, 4) >= 0) { if (j_info.flags & HAVE_APPn_XMP) { pdf_obj *XMP_stream; @@ -943,6 +944,12 @@ JPEG_copy_stream (struct JPEG_info *j_info, pdf_obj *stream, rust_input_handle_t return (found_SOFn ? 0 : -1); } +/* Adobe Technical Note #5116 "Supporting the DCT Filters in PostScript Level 2" + * 6. "DCTDecode Filter Summary" + * ... APPn (application-specific) markers are skipped over harmlessly except + * for the Adobe reserved marker described later. + * + */ #define SET_SKIP(j,c) if ((c) < MAX_COUNT) { \ (j)->skipbits[(c) / 8] |= (1 << (7 - ((c) % 8))); \ } @@ -978,11 +985,17 @@ JPEG_scan_file (struct JPEG_info *j_info, rust_input_handle_t handle) return -1; length -= 5; if (!memcmp(app_sig, "JFIF\000", 5)) { + /* APP0 JFIF marker preserved */ j_info->flags |= HAVE_APPn_JFIF; length -= read_APP0_JFIF(j_info, handle); } else if (!memcmp(app_sig, "JFXX", 5)) { length -= read_APP0_JFXX(handle, length); + SET_SKIP(j_info, count); + } else { + SET_SKIP(j_info, count); } + } else { + SET_SKIP(j_info, count); } ttstub_input_seek(handle, length, SEEK_CUR); break; @@ -992,6 +1005,7 @@ JPEG_scan_file (struct JPEG_info *j_info, rust_input_handle_t handle) return -1; length -= 5; if (!memcmp(app_sig, "Exif\000", 5)) { + /* APP1 Exif marker preserved */ j_info->flags |= HAVE_APPn_Exif; length -= read_APP1_Exif(j_info, handle, length); } else if (!memcmp(app_sig, "http:", 5) && length > 24) { @@ -1001,9 +1015,11 @@ JPEG_scan_file (struct JPEG_info *j_info, rust_input_handle_t handle) if (!memcmp(app_sig, "//ns.adobe.com/xap/1.0/\000", 24)) { j_info->flags |= HAVE_APPn_XMP; length -= read_APP1_XMP(j_info, handle, length); - SET_SKIP(j_info, count); } + SET_SKIP(j_info, count); } + } else { + SET_SKIP(j_info, count); } ttstub_input_seek(handle, length, SEEK_CUR); break; @@ -1015,10 +1031,10 @@ JPEG_scan_file (struct JPEG_info *j_info, rust_input_handle_t handle) if (!memcmp(app_sig, "ICC_PROFILE\000", 12)) { j_info->flags |= HAVE_APPn_ICC; length -= read_APP2_ICC(j_info, handle, length); - SET_SKIP(j_info, count); } } ttstub_input_seek(handle, length, SEEK_CUR); + SET_SKIP(j_info, count); break; case JM_APP14: if (length > 5) { @@ -1026,11 +1042,14 @@ JPEG_scan_file (struct JPEG_info *j_info, rust_input_handle_t handle) return -1; length -= 5; if (!memcmp(app_sig, "Adobe", 5)) { + /* APP14 Adobe marker preserved */ j_info->flags |= HAVE_APPn_ADOBE; length -= read_APP14_Adobe(j_info, handle); } else { SET_SKIP(j_info, count); } + } else { + SET_SKIP(j_info, count); } ttstub_input_seek(handle, length, SEEK_CUR); break; diff --git a/tectonic/dpx-mem.h b/tectonic/dpx-mem.h index d99ab4c1dd..8a5ed5100c 100644 --- a/tectonic/dpx-mem.h +++ b/tectonic/dpx-mem.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -34,4 +34,13 @@ void *renew (void *p, uint32_t size); #define NEW(n,type) (type *) new(((uint32_t)(n))*sizeof(type)) #define RENEW(p,n,type) (type *) renew(p,((uint32_t)(n))*sizeof(type)) +/* + * mem.h is not suitable for the following, but it is the only common + * header file for dpxcrypt.c, pdfencrypt.c, and pdffont.c, which use + * the function rand(). + */ +void init_genrand(unsigned long long s); +long genrand_int31(void); +#define srand(x) init_genrand((x)) +#define rand() genrand_int31() #endif /* _MEM_H_ */ diff --git a/tectonic/dpx-mfileio.h b/tectonic/dpx-mfileio.h index a4f2d10726..b6d33472f7 100644 --- a/tectonic/dpx-mfileio.h +++ b/tectonic/dpx-mfileio.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks diff --git a/tectonic/dpx-mpost.c b/tectonic/dpx-mpost.c index 6ba14194f9..00fece727a 100644 --- a/tectonic/dpx-mpost.c +++ b/tectonic/dpx-mpost.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -49,6 +49,12 @@ */ static double Xorigin, Yorigin; +static int translate_origin = 0; + +void +mps_set_translate_origin (int v) { + translate_origin = v; +} /* * In PDF, current path is not a part of graphics state parameter. @@ -79,9 +85,24 @@ static struct mp_font } font_stack[PDF_GSAVE_MAX] = { {NULL, -1, -1, -1, 0} }; -static int currentfont = -1; +static int currentfont = 0; #define CURRENT_FONT() ((currentfont < 0) ? NULL : &font_stack[currentfont]) +#define FONT_DEFINED(f) ((f) && (f)->font_name && ((f)->font_id >= 0)) + +static void +clear_mp_font_struct (struct mp_font *font) +{ + assert(font); + + if (font->font_name) + free(font->font_name); + font->font_name = NULL; + font->font_id = -1; + font->tfm_id = -1; + font->subfont_id = -1; + font->pt_size = 0.0; +} /* Compatibility */ #define MP_CMODE_MPOST 0 @@ -99,17 +120,6 @@ mp_setfont (const char *font_name, double pt_size) font = CURRENT_FONT(); - if (font) { - if (streq_ptr(font->font_name, font_name) && - font->pt_size == pt_size) - return 0; - } else { /* No currentfont */ -/* ***TODO*** Here some problem exists! */ - font = &font_stack[0]; - font->font_name = NULL; - currentfont = 0; - } - mrec = pdf_lookup_fontmap_record(font_name); if (mrec && mrec->charmap.sfd_name && mrec->charmap.subfont_id) { subfont_id = sfd_load_record(mrec->charmap.sfd_name, mrec->charmap.subfont_id); @@ -143,23 +153,22 @@ save_font (void) { struct mp_font *current, *next; - if (currentfont < 0) { - font_stack[0].font_name = NEW(strlen("Courier") + 1, char); - strcpy(font_stack[0].font_name, "Courier"); - font_stack[0].pt_size = 1; - font_stack[0].tfm_id = 0; - font_stack[0].subfont_id = 0; - currentfont = 0; - } - current = &font_stack[currentfont++]; next = &font_stack[currentfont ]; - next->font_name = NEW(strlen(current->font_name)+1, char); - strcpy(next->font_name, current->font_name); - next->pt_size = current->pt_size; - - next->subfont_id = current->subfont_id; - next->tfm_id = current->tfm_id; + if (FONT_DEFINED(current)) { + next->font_name = NEW(strlen(current->font_name)+1, char); + strcpy(next->font_name, current->font_name); + next->font_id = current->font_id; + next->pt_size = current->pt_size; + next->subfont_id = current->subfont_id; + next->tfm_id = current->tfm_id; + } else { + next->font_name = NULL; + next->font_id = -1; + next->pt_size = 0.0; + next->subfont_id = -1; + next->tfm_id = -1; + } } static void @@ -169,21 +178,22 @@ restore_font (void) current = CURRENT_FONT(); if (current) { - current->font_name = mfree(current->font_name); - } else { - _tt_abort("No currentfont..."); + clear_mp_font_struct(current); } - currentfont--; + if (currentfont > 0) /* Tectonic safety fix */ + currentfont--; } static void clear_fonts (void) { while (currentfont >= 0) { - free(font_stack[currentfont].font_name); + clear_mp_font_struct(&font_stack[currentfont]); currentfont--; } + + currentfont = 0; /* Tectonic fix */ } static bool @@ -713,7 +723,7 @@ do_currentfont (void) pdf_obj *font_dict; font = CURRENT_FONT(); - if (!font) { + if (!FONT_DEFINED(font)) { dpx_warning("Currentfont undefined..."); return 1; } else { @@ -750,7 +760,7 @@ do_show (void) double text_width; font = CURRENT_FONT(); - if (!font) { + if (!FONT_DEFINED(font)) { dpx_warning("Currentfont not set."); /* Should not be error... */ return 1; } @@ -1538,3 +1548,17 @@ mps_do_page (FILE *image_file) */ return (error ? -1 : 0); } + +void +mps_reset_global_state(void) /* Tectonic */ +{ + translate_origin = 0; + currentfont = 0; + font_stack[0].font_name = NULL; + font_stack[0].font_id = -1; + font_stack[0].tfm_id = -1; + font_stack[0].subfont_id = -1; + font_stack[0].pt_size = 0.0; + mp_cmode = MP_CMODE_MPOST; + top_stack = 0; +} diff --git a/tectonic/dpx-mpost.h b/tectonic/dpx-mpost.h index 96d8859278..cac37c8a04 100644 --- a/tectonic/dpx-mpost.h +++ b/tectonic/dpx-mpost.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -31,6 +31,10 @@ #include "dpx-pdfdev.h" #include "dpx-pdfximage.h" +void mps_reset_global_state(void); /* Tectonic */ + +void mps_set_translate_origin (int boolean_value); + int mps_scan_bbox (const char **pp, const char *endptr, pdf_rect *bbox); int mps_exec_inline (const char **buffer, const char *endptr, diff --git a/tectonic/dpx-mt19937ar.c b/tectonic/dpx-mt19937ar.c new file mode 100644 index 0000000000..ff008b0f09 --- /dev/null +++ b/tectonic/dpx-mt19937ar.c @@ -0,0 +1,183 @@ +/* + A C-program for MT19937, with initialization improved 2002/1/26. + Coded by Takuji Nishimura and Makoto Matsumoto. + + Before using, initialize the state by using init_genrand(seed) + or init_by_array(init_key, key_length). + + Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The names of its contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + Any feedback is very welcome. + http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html + email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) +*/ + +/* Tectonic notes: + - These functions are exposed as aliases in dpx-mem.h +*/ + +#include + +/* Period parameters */ +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0dfUL /* constant vector a */ +#define UPPER_MASK 0x80000000UL /* most significant w-r bits */ +#define LOWER_MASK 0x7fffffffUL /* least significant r bits */ + +static unsigned long mt[N]; /* the array for the state vector */ +static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */ + +void init_genrand(unsigned long long s); +long genrand_int31(void); + +/* initializes mt[N] with a seed */ +/* void init_genrand(unsigned long s) */ +void init_genrand(unsigned long long s) +{ + mt[0]= s & 0xffffffffUL; + for (mti=1; mti> 30)) + mti); + /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ + /* In the previous versions, MSBs of the seed affect */ + /* only MSBs of the array mt[]. */ + /* 2002/01/09 modified by Makoto Matsumoto */ + mt[mti] &= 0xffffffffUL; + /* for >32 bit machines */ + } +} + +#if 0 /* unused in Tectonic: */ +/* initialize by an array with array-length */ +/* init_key is the array for initializing keys */ +/* key_length is its length */ +/* slight change for C++, 2004/2/26 */ +void init_by_array(unsigned long init_key[], int key_length) +{ + int i, j, k; + init_genrand(19650218UL); + i=1; j=0; + k = (N>key_length ? N : key_length); + for (; k; k--) { + mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL)) + + init_key[j] + j; /* non linear */ + mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ + i++; j++; + if (i>=N) { mt[0] = mt[N-1]; i=1; } + if (j>=key_length) j=0; + } + for (k=N-1; k; k--) { + mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) + - i; /* non linear */ + mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ + i++; + if (i>=N) { mt[0] = mt[N-1]; i=1; } + } + + mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ +} +#endif + +/* generates a random number on [0,0xffffffff]-interval */ +static unsigned long genrand_int32(void) +{ + unsigned long y; + static unsigned long mag01[2]={0x0UL, MATRIX_A}; + /* mag01[x] = x * MATRIX_A for x=0,1 */ + + if (mti >= N) { /* generate N words at one time */ + int kk; + + if (mti == N+1) /* if init_genrand() has not been called, */ + init_genrand(5489UL); /* a default initial seed is used */ + + for (kk=0;kk> 1) ^ mag01[y & 0x1UL]; + } + for (;kk> 1) ^ mag01[y & 0x1UL]; + } + y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); + mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; + + mti = 0; + } + + y = mt[mti++]; + + /* Tempering */ + y ^= (y >> 11); + y ^= (y << 7) & 0x9d2c5680UL; + y ^= (y << 15) & 0xefc60000UL; + y ^= (y >> 18); + + return y; +} + +/* generates a random number on [0,0x7fffffff]-interval */ +long genrand_int31(void) +{ + return (long)(genrand_int32()>>1); +} + +#if 0 /* unused in Tectonic */ +/* generates a random number on [0,1]-real-interval */ +double genrand_real1(void) +{ + return genrand_int32()*(1.0/4294967295.0); + /* divided by 2^32-1 */ +} + +/* generates a random number on [0,1)-real-interval */ +double genrand_real2(void) +{ + return genrand_int32()*(1.0/4294967296.0); + /* divided by 2^32 */ +} + +/* generates a random number on (0,1)-real-interval */ +double genrand_real3(void) +{ + return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0); + /* divided by 2^32 */ +} + +/* generates a random number on [0,1) with 53-bit resolution*/ +double genrand_res53(void) +{ + unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6; + return(a*67108864.0+b)*(1.0/9007199254740992.0); +} +#endif diff --git a/tectonic/dpx-numbers.c b/tectonic/dpx-numbers.c index 99e17e521f..8ecb7ffe74 100644 --- a/tectonic/dpx-numbers.c +++ b/tectonic/dpx-numbers.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks diff --git a/tectonic/dpx-numbers.h b/tectonic/dpx-numbers.h index 2dcb309b34..e1bc755097 100644 --- a/tectonic/dpx-numbers.h +++ b/tectonic/dpx-numbers.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks diff --git a/tectonic/dpx-pdfcolor.c b/tectonic/dpx-pdfcolor.c index 673be503d0..e1c96a923f 100644 --- a/tectonic/dpx-pdfcolor.c +++ b/tectonic/dpx-pdfcolor.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -32,18 +32,12 @@ #include #include +#include "dpx-dpxconf.h" #include "dpx-error.h" #include "dpx-mem.h" #include "dpx-numbers.h" #include "dpx-pdfdev.h" -static int verbose = 0; -void -pdf_color_set_verbose (int level) -{ - verbose = level; -} - /* This function returns PDF_COLORSPACE_TYPE_GRAY, * PDF_COLORSPACE_TYPE_RGB, PDF_COLORSPACE_TYPE_CMYK or * PDF_COLORSPACE_TYPE_SPOT. @@ -329,7 +323,7 @@ pdf_color_set (pdf_color *sc, pdf_color *fc) { pdf_color_copycolor(&color_stack.stroke[color_stack.current], sc); pdf_color_copycolor(&color_stack.fill[color_stack.current], fc); - pdf_dev_reset_color(0); + pdf_dev_reset_color(1); } void @@ -351,7 +345,7 @@ pdf_color_pop (void) dpx_warning("Color stack underflow. Just ignore."); } else { color_stack.current--; - pdf_dev_reset_color(0); + pdf_dev_reset_color(1); } return; } @@ -390,19 +384,22 @@ static struct {0x04, 0x00}, /* PDF-1.5 */ {0x04, 0x00}, /* PDF-1.6 */ {0x04, 0x20}, /* PDF-1.7 */ + {0x04, 0x20}, /* Dummy(1.8)*/ + {0x04, 0x20}, /* Dummy(1.9) */ + {0x04, 0x20} /* PDF-2.0 */ }; static int iccp_version_supported (int major, int minor) { - int pdf_ver; + int idx; - pdf_ver = pdf_get_version(); - if (pdf_ver < 8) { - if (icc_versions[pdf_ver].major < major) + idx = pdf_get_version() - 10; + if (idx < 11) { + if (icc_versions[idx].major < major) return 0; - else if (icc_versions[pdf_ver].major == major && - icc_versions[pdf_ver].minor < minor) + else if (icc_versions[idx].major == major && + icc_versions[idx].minor < minor) return 0; else { return 1; @@ -965,12 +962,12 @@ iccp_load_profile (const char *ident, cspc_id = pdf_colorspace_findresource(ident, PDF_COLORSPACE_TYPE_ICCBASED, cdata); if (cspc_id >= 0) { - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message("(ICCP:[id=%d])", cspc_id); release_iccbased_cdata(cdata); return cspc_id; } - if (verbose > 1) { + if (dpx_conf.verbose_level > 1) { print_iccp_header(&icch, checksum); } @@ -1113,9 +1110,9 @@ pdf_colorspace_defineresource (const char *ident, colorspace->cdata = cdata; colorspace->resource = resource; - if (verbose) { + if (dpx_conf.verbose_level > 0) { dpx_message("(ColorSpace:%s", ident); - if (verbose > 1) { + if (dpx_conf.verbose_level > 1) { switch (subtype) { case PDF_COLORSPACE_TYPE_ICCBASED: dpx_message("[ICCBased]"); diff --git a/tectonic/dpx-pdfcolor.h b/tectonic/dpx-pdfcolor.h index ebd15d296b..e5b3074f50 100644 --- a/tectonic/dpx-pdfcolor.h +++ b/tectonic/dpx-pdfcolor.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -53,8 +53,6 @@ typedef struct double values[PDF_COLOR_COMPONENT_MAX]; } pdf_color; -void pdf_color_set_verbose (int level); - int pdf_color_rgbcolor (pdf_color *color, double r, double g, double b); int pdf_color_cmykcolor (pdf_color *color, diff --git a/tectonic/dpx-pdfdev.c b/tectonic/dpx-pdfdev.c index d3ae62313c..18c07ad1ed 100644 --- a/tectonic/dpx-pdfdev.c +++ b/tectonic/dpx-pdfdev.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -32,6 +32,7 @@ #include "dpx-cff.h" #include "dpx-cff_types.h" #include "dpx-cmap.h" +#include "dpx-dpxconf.h" #include "dpx-dvi.h" #include "dpx-error.h" #include "dpx-fontmap.h" @@ -46,14 +47,6 @@ #include "dpx-pdfximage.h" #include "dpx-type0.h" -static int verbose = 0; - -void -pdf_dev_set_verbose (int level) -{ - verbose = level; -} - /* Not working yet... */ double pdf_dev_scale (void) @@ -492,8 +485,6 @@ struct dev_font { int ucs_plane; int is_unicode; - - cff_charsets *cff_charsets; }; static struct dev_font *dev_fonts = NULL; @@ -934,26 +925,8 @@ handle_multibyte_string (struct dev_font *font, p = *str_ptr; length = *str_len; - if (ctype == -1 && font->cff_charsets) { /* freetype glyph indexes */ - /* Convert freetype glyph indexes to CID. */ - const unsigned char *inbuf = p; - unsigned char *outbuf = sbuf0; - for (i = 0; i < length; i += 2) { - unsigned int gid; - gid = *inbuf++ << 8; - gid += *inbuf++; - - gid = cff_charsets_lookup_cid(font->cff_charsets, gid); - - *outbuf++ = gid >> 8; - *outbuf++ = gid & 0xff; - } - - p = sbuf0; - length = outbuf - sbuf0; - } /* _FIXME_ */ - else if (font->is_unicode) { /* UCS-4 */ + if (font->is_unicode) { /* UCS-4 */ if (ctype == 1) { if (length * 4 >= FORMAT_BUF_SIZE) { dpx_warning("Too long string..."); @@ -1016,7 +989,7 @@ handle_multibyte_string (struct dev_font *font, * encoding. * TODO: A character decomposed to multiple characters. */ - if (ctype != -1 && font->enc_id >= 0) { + if (font->enc_id >= 0) { const unsigned char *inbuf; unsigned char *outbuf; size_t inbytesleft, outbytesleft; @@ -1282,7 +1255,6 @@ pdf_close_device (void) pdf_release_obj(dev_fonts[i].resource); dev_fonts[i].tex_name = NULL; dev_fonts[i].resource = NULL; - dev_fonts[i].cff_charsets = NULL; } free(dev_fonts); } @@ -1440,16 +1412,13 @@ pdf_dev_locate_font (const char *font_name, spt_t ptsize) /* New font */ mrec = pdf_lookup_fontmap_record(font_name); - if (verbose > 1) + if (dpx_conf.verbose_level > 1) print_fontmap(font_name, mrec); font->font_id = pdf_font_findresource(font_name, ptsize * dev_unit.dvi2pts, mrec); if (font->font_id < 0) return -1; - if (mrec) - font->cff_charsets = mrec->opt.cff_charsets; - /* We found device font here. */ if (i < num_dev_fonts) { font->real_font_index = i; diff --git a/tectonic/dpx-pdfdev.h b/tectonic/dpx-pdfdev.h index 9e26353e41..3fc3785514 100644 --- a/tectonic/dpx-pdfdev.h +++ b/tectonic/dpx-pdfdev.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -76,8 +76,6 @@ typedef struct #define INFO_DO_HIDE (1 << 4) void transform_info_clear (transform_info *info); - -void pdf_dev_set_verbose (int level); void pdf_dev_reset_global_state (void); /* Not in spt_t. */ diff --git a/tectonic/dpx-pdfdoc.c b/tectonic/dpx-pdfdoc.c index 0ce6832f10..1356c5d380 100644 --- a/tectonic/dpx-pdfdoc.c +++ b/tectonic/dpx-pdfdoc.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2008-2017 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, + Copyright (C) 2008-2019 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -36,6 +36,7 @@ #include #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-dpxutil.h" #include "dpx-dvipdfmx.h" #include "dpx-error.h" @@ -58,8 +59,6 @@ #define PDFDOC_ARTICLE_ALLOC_SIZE 16 #define PDFDOC_BEAD_ALLOC_SIZE 16 -static int verbose = 0; - static char manual_thumb_enabled = 0; static char *thumb_basename = NULL; @@ -103,15 +102,6 @@ read_thumbnail (const char *thumb_filename) return image_ref; } -void -pdf_doc_set_verbose (int level) -{ - verbose = level; - pdf_font_set_verbose(level); - pdf_color_set_verbose(level); - pdf_ximage_set_verbose(level); -} - typedef struct pdf_form { char *ident; @@ -418,23 +408,6 @@ pdf_doc_set_eop_content (const char *content, unsigned int length) return; } -/* - * Docinfo - */ -static int -asn_date (char *date_string, time_t date) -{ - int32_t tz_offset = 0; - struct tm *bd_time = gmtime(&date); - sprintf(date_string, "D:%04d%02d%02d%02d%02d%02d%c%02d'%02d'", - bd_time->tm_year + 1900, bd_time->tm_mon + 1, bd_time->tm_mday, - bd_time->tm_hour, bd_time->tm_min, bd_time->tm_sec, - (tz_offset > 0) ? '+' : '-', abs(tz_offset) / 3600, - (abs(tz_offset) / 60) % 60); - - return strlen(date_string); -} - static void pdf_doc_init_docinfo (pdf_doc *p) { @@ -495,7 +468,7 @@ pdf_doc_close_docinfo (pdf_doc *p) if (!pdf_lookup_dict(docinfo, "CreationDate") && source_date_epoch) { char now[80]; - asn_date(now, source_date_epoch); + dpx_util_format_asn_date(now, 1); pdf_add_dict(docinfo, pdf_new_name ("CreationDate"), pdf_new_string(now, strlen(now))); @@ -536,6 +509,9 @@ pdf_doc_get_page_resources (pdf_doc *p, const char *category) if (!resources) { resources = pdf_new_dict(); pdf_add_dict(res_dict, pdf_new_name(category), resources); + } else if (pdf_obj_typeof(resources) == PDF_INDIRECT) { + resources = pdf_deref_obj(resources); /* FIXME: deref_obj increment link count */ + pdf_release_obj(resources); /* FIXME: just to decrement link count */ } return resources; @@ -549,10 +525,6 @@ pdf_doc_add_page_resource (const char *category, pdf_obj *resources; pdf_obj *duplicate; - if (!PDF_OBJ_INDIRECTTYPE(resource_ref)) { - dpx_warning("Passed non indirect reference..."); - resource_ref = pdf_ref_obj(resource_ref); /* leak */ - } resources = pdf_doc_get_page_resources(p, category); duplicate = pdf_lookup_dict(resources, resource_name); if (duplicate && pdf_compare_reference(duplicate, resource_ref)) { @@ -858,6 +830,184 @@ pdf_doc_get_page_count (pdf_file *pf) return count; } +static int +set_bounding_box (pdf_rect *bbox, enum pdf_page_boundary opt_bbox, + pdf_obj *media_box, pdf_obj *crop_box, + pdf_obj *art_box, pdf_obj *trim_box, pdf_obj *bleed_box) +{ + pdf_obj *box = NULL; + + if (!media_box) { + dpx_warning("MediaBox not found in included PDF..."); + return -1; + } +#define VALIDATE_BOX(o) if ((o)) {\ + if (!PDF_OBJ_ARRAYTYPE((o)) || pdf_array_length((o)) != 4) \ + return -1;\ +} + VALIDATE_BOX(media_box); + VALIDATE_BOX(crop_box); + VALIDATE_BOX(art_box); + VALIDATE_BOX(trim_box); + VALIDATE_BOX(bleed_box); + + if (opt_bbox == pdf_page_boundary__auto) { + if (crop_box) + box = pdf_link_obj(crop_box); + else if (art_box) + box = pdf_link_obj(art_box); + else if (trim_box) + box = pdf_link_obj(trim_box); + else if (bleed_box) + box = pdf_link_obj(bleed_box); + else { + box = pdf_link_obj(media_box); + } + } else { + if (!crop_box) { + crop_box = pdf_link_obj(media_box); + } + if (!art_box) { + art_box = pdf_link_obj(crop_box); + } + if (!trim_box) { + trim_box = pdf_link_obj(crop_box); + } + if (!bleed_box) { + bleed_box = pdf_link_obj(crop_box); + } + /* At this point all boxes must be defined. */ + switch (opt_bbox) { + case pdf_page_boundary_cropbox: + box = pdf_link_obj(crop_box); + break; + case pdf_page_boundary_mediabox: + box = pdf_link_obj(media_box); + break; + case pdf_page_boundary_artbox: + box = pdf_link_obj(art_box); + break; + case pdf_page_boundary_trimbox: + box = pdf_link_obj(trim_box); + break; + case pdf_page_boundary_bleedbox: + box = pdf_link_obj(bleed_box); + break; + default: + box = pdf_link_obj(crop_box); + break; + } + } + + if (!box) { + /* Impossible */ + dpx_warning("No appropriate page boudary box found???"); + return -1; + } else { + int i; + + for (i = 4; i--; ) { + double x; + pdf_obj *tmp = pdf_deref_obj(pdf_get_array(box, i)); + if (!PDF_OBJ_NUMBERTYPE(tmp)) { + pdf_release_obj(tmp); + pdf_release_obj(box); + return -1; + } + x = pdf_number_value(tmp); + switch (i) { + case 0: bbox->llx = x; break; + case 1: bbox->lly = x; break; + case 2: bbox->urx = x; break; + case 3: bbox->ury = x; break; + } + pdf_release_obj(tmp); + } + + /* New scheme only for XDV files */ + if (dpx_conf.compat_mode == dpx_mode_xdv_mode || + opt_bbox != pdf_page_boundary__auto) { + for (i = 4; i--; ) { + double x; + pdf_obj *tmp = pdf_deref_obj(pdf_get_array(media_box, i)); + if (!PDF_OBJ_NUMBERTYPE(tmp)) { + pdf_release_obj(tmp); + pdf_release_obj(box); + return -1; + } + x = pdf_number_value(tmp); + switch (i) { + case 0: if (bbox->llx < x) bbox->llx = x; break; + case 1: if (bbox->lly < x) bbox->lly = x; break; + case 2: if (bbox->urx > x) bbox->urx = x; break; + case 3: if (bbox->ury > x) bbox->ury = x; break; + } + pdf_release_obj(tmp); + } + } + } + pdf_release_obj(box); + + return 0; +} + +static int +set_transform_matrix (pdf_tmatrix *matrix, pdf_rect *bbox, pdf_obj *rotate) +{ + double deg; + int rot; + + matrix->a = matrix->d = 1.0; + matrix->b = matrix->c = 0.0; + matrix->e = matrix->f = 0.0; + /* Handle Rotate */ + if (rotate) { + if (!PDF_OBJ_NUMBERTYPE(rotate)) { + return -1; + } else { + deg = pdf_number_value(rotate); + if (deg - (int)deg != 0.0) { + dpx_warning("Invalid value specified for /Rotate: %f", deg); + return -1; + } else if (deg != 0.0) { + rot = (int) deg; + if (rot % 90 != 0.0) { + dpx_warning("Invalid value specified for /Rotate: %f", deg); + } else { + rot = rot % 360; + if (rot < 0) rot += 360; + switch (rot) { + case 90: + matrix->a = matrix->d = 0; + matrix->b = -1; + matrix->c = 1; + matrix->e = bbox->llx - bbox->lly; + matrix->f = bbox->lly + bbox->urx; + break; + case 180: + matrix->a = matrix->d = -1; + matrix->b = matrix->c = 0; + matrix->e = bbox->llx + bbox->urx; + matrix->f = bbox->lly + bbox->ury; + break; + case 270: + matrix->a = matrix->d = 0; + matrix->b = 1; + matrix->c = -1; + matrix->e = bbox->llx + bbox->ury; + matrix->f = bbox->lly - bbox->llx; + break; + default: + dpx_warning("Invalid value specified for /Rotate: %f", deg); + break; + } + } + } + } + } + return 0; +} + /* * From PDFReference15_v6.pdf (p.119 and p.834) * @@ -915,27 +1065,29 @@ pdf_doc_get_page_count (pdf_file *pf) */ pdf_obj * pdf_doc_get_page (pdf_file *pf, - int page_no, int options, /* load options */ + int page_no, enum pdf_page_boundary opt_bbox, /* load options */ pdf_rect *bbox, pdf_tmatrix *matrix, /* returned value */ pdf_obj **resources_p /* returned values */ ) { - pdf_obj *page_tree = NULL; - pdf_obj *resources = NULL, *box = NULL, *rotate = NULL, *medbox = NULL; - pdf_obj *catalog; + pdf_obj *catalog = NULL, *page_tree = NULL; + pdf_obj *resources = NULL, *rotate = NULL; + pdf_obj *art_box = NULL, *trim_box = NULL, *bleed_box = NULL; + pdf_obj *media_box = NULL, *crop_box = NULL; + int error = 0; catalog = pdf_file_get_catalog(pf); page_tree = pdf_deref_obj(pdf_lookup_dict(catalog, "Pages")); if (!PDF_OBJ_DICTTYPE(page_tree)) - goto error; + goto error_exit; { int count; pdf_obj *tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Count")); if (!PDF_OBJ_NUMBERTYPE(tmp)) { pdf_release_obj(tmp); - goto error; + goto error_exit; } count = pdf_number_value(tmp); pdf_release_obj(tmp); @@ -950,42 +1102,35 @@ pdf_doc_get_page (pdf_file *pf, * (Note that these entries can be inherited.) */ { - pdf_obj *art_box = NULL, *trim_box = NULL, *bleed_box = NULL; - pdf_obj *media_box = NULL, *crop_box = NULL, *kids, *tmp; - int depth = PDF_OBJ_MAX_DEPTH; - int page_idx = page_no-1, kids_length = 1, i = 0; + pdf_obj *kids, *tmp; + int depth = PDF_OBJ_MAX_DEPTH; + int page_idx = page_no - 1, kids_length = 1, i = 0; while (--depth && i != kids_length) { if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "MediaBox")))) { pdf_release_obj(media_box); media_box = tmp; } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "CropBox")))) { pdf_release_obj(crop_box); crop_box = tmp; } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "ArtBox")))) { pdf_release_obj(art_box); art_box = tmp; } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "TrimBox")))) { pdf_release_obj(trim_box); trim_box = tmp; } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "BleedBox")))) { pdf_release_obj(bleed_box); bleed_box = tmp; } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Rotate")))) { pdf_release_obj(rotate); rotate = tmp; } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Resources")))) { pdf_release_obj(resources); resources = tmp; @@ -996,7 +1141,7 @@ pdf_doc_get_page (pdf_file *pf, break; else if (!PDF_OBJ_ARRAYTYPE(kids)) { pdf_release_obj(kids); - goto error; + goto error_exit; } kids_length = pdf_array_length(kids); @@ -1006,7 +1151,7 @@ pdf_doc_get_page (pdf_file *pf, pdf_release_obj(page_tree); page_tree = pdf_deref_obj(pdf_get_array(kids, i)); if (!PDF_OBJ_DICTTYPE(page_tree)) - goto error; + goto error_exit; tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Count")); if (PDF_OBJ_NUMBERTYPE(tmp)) { @@ -1018,187 +1163,50 @@ pdf_doc_get_page (pdf_file *pf, count = 1; else { pdf_release_obj(tmp); - goto error; + goto error_exit; } - if (page_idx < count) break; - page_idx -= count; } - pdf_release_obj(kids); } - - if (!depth || kids_length == i) { - pdf_release_obj(media_box); - pdf_release_obj(crop_box); - goto error; - } - - /* Nasty BBox selection... */ - if (options == 0 || options == 1) { - if (crop_box) - box = crop_box; - else - if (!(box = media_box) && - !(box = bleed_box) && - !(box = trim_box) && - art_box) { - box = art_box; - } - } else if (options == 2) { - if (media_box) - box = media_box; - else - if (!(box = crop_box) && - !(box = bleed_box) && - !(box = trim_box) && - art_box) { - box = art_box; - } - } else if (options == 3) { - if (art_box) - box = art_box; - else - if (!(box = crop_box) && - !(box = media_box) && - !(box = bleed_box) && - trim_box) { - box = trim_box; - } - } else if (options == 4) { - if (trim_box) - box = trim_box; - else - if (!(box = crop_box) && - !(box = media_box) && - !(box = bleed_box) && - art_box) { - box = art_box; - } - } else if (options == 5) { - if (bleed_box) - box = bleed_box; - else - if (!(box = crop_box) && - !(box = media_box) && - !(box = trim_box) && - art_box) { - box = art_box; - } - } - medbox = media_box; - } - - if (!PDF_OBJ_ARRAYTYPE(box) || pdf_array_length(box) != 4 || - !PDF_OBJ_DICTTYPE(resources)) - goto error; - - { - int i; - - for (i = 4; i--; ) { - double x; - pdf_obj *tmp = pdf_deref_obj(pdf_get_array(box, i)); - if (!PDF_OBJ_NUMBERTYPE(tmp)) { - pdf_release_obj(tmp); - goto error; - } - x = pdf_number_value(tmp); - switch (i) { - case 0: bbox->llx = x; break; - case 1: bbox->lly = x; break; - case 2: bbox->urx = x; break; - case 3: bbox->ury = x; break; - } - pdf_release_obj(tmp); - } - - /* New scheme only for XDV files */ - if (medbox && (is_xdv || options)) { - for (i = 4; i--; ) { - double x; - pdf_obj *tmp = pdf_deref_obj(pdf_get_array(medbox, i)); - if (!PDF_OBJ_NUMBERTYPE(tmp)) { - pdf_release_obj(tmp); - goto error; - } - x = pdf_number_value(tmp); - switch (i) { - case 0: if (bbox->llx < x) bbox->llx = x; break; - case 1: if (bbox->lly < x) bbox->lly = x; break; - case 2: if (bbox->urx > x) bbox->urx = x; break; - case 3: if (bbox->ury > x) bbox->ury = x; break; - } - pdf_release_obj(tmp); - } - } - } - - pdf_release_obj(box); - - matrix->a = matrix->d = 1.0; - matrix->b = matrix->c = 0.0; - matrix->e = matrix->f = 0.0; - if (PDF_OBJ_NUMBERTYPE(rotate)) { - double deg = pdf_number_value(rotate); - if (deg - (int)deg != 0.0) - dpx_warning("Invalid value specified for /Rotate: %f", deg); - else if (deg != 0.0) { - int rot = (int) deg; - if (rot % 90 != 0.0) { - dpx_warning("Invalid value specified for /Rotate: %f", deg); - } else { - rot = rot % 360; - if (rot < 0) rot += 360; - switch (rot) { - case 90: - matrix->a = matrix->d = 0; - matrix->b = -1; - matrix->c = 1; - matrix->e = bbox->llx - bbox->lly; - matrix->f = bbox->lly + bbox->urx; - break; - case 180: - matrix->a = matrix->d = -1; - matrix->b = matrix->c = 0; - matrix->e = bbox->llx + bbox->urx; - matrix->f = bbox->lly + bbox->ury; - break; - case 270: - matrix->a = matrix->d = 0; - matrix->b = 1; - matrix->c = -1; - matrix->e = bbox->llx + bbox->ury; - matrix->f = bbox->lly - bbox->llx; - break; - } - } - } - pdf_release_obj(rotate); - rotate = NULL; - } else if (rotate) { - goto error; + if (!depth || kids_length == i) + goto error_exit; } + if (!PDF_OBJ_DICTTYPE(resources)) + goto error_exit; if (resources_p) - *resources_p = resources; - else { - pdf_release_obj(resources); - } + *resources_p = pdf_link_obj(resources); - return page_tree; + /* Select page boundary box */ + error = set_bounding_box(bbox, opt_bbox, media_box, crop_box, art_box, trim_box, bleed_box); + if (error) + goto error_exit; + /* Set transformation matrix */ + error = set_transform_matrix(matrix, bbox, rotate); + if (error) + goto error_exit; - error: - dpx_warning("Cannot parse document. Broken PDF file?"); + goto clean_exit; /* Success */ + + error_exit: + dpx_warning("Error found in including PDF image."); error_silent: - pdf_release_obj(box); + pdf_release_obj(page_tree); + page_tree = NULL; + +clean_exit: + pdf_release_obj(crop_box); + pdf_release_obj(bleed_box); + pdf_release_obj(trim_box); + pdf_release_obj(art_box); + pdf_release_obj(media_box); pdf_release_obj(rotate); pdf_release_obj(resources); - pdf_release_obj(page_tree); - return NULL; + return page_tree; } #ifndef BOOKMARKS_OPEN_DEFAULT @@ -1674,7 +1682,7 @@ pdf_doc_close_names (pdf_doc *p) else { name_tree = pdf_names_create_tree(data, &count, &pdoc.gotos); - if (verbose && count < data->count) + if (dpx_conf.verbose_level > 0 && count < data->count) dpx_message("\nRemoved %d unused PDF destinations\n", data->count-count); if (count < pdoc.gotos.count) @@ -1728,7 +1736,6 @@ pdf_doc_add_annot (unsigned page_no, const pdf_rect *rect, pdf_doc *p = &pdoc; pdf_page *page; pdf_obj *rect_array; - double annot_grow = p->opt.annot_grow; double xpos, ypos; pdf_rect annbox; @@ -1760,10 +1767,10 @@ pdf_doc_add_annot (unsigned page_no, const pdf_rect *rect, } rect_array = pdf_new_array(); - pdf_add_array(rect_array, pdf_new_number(ROUND(annbox.llx - annot_grow, 0.001))); - pdf_add_array(rect_array, pdf_new_number(ROUND(annbox.lly - annot_grow, 0.001))); - pdf_add_array(rect_array, pdf_new_number(ROUND(annbox.urx + annot_grow, 0.001))); - pdf_add_array(rect_array, pdf_new_number(ROUND(annbox.ury + annot_grow, 0.001))); + pdf_add_array(rect_array, pdf_new_number(ROUND(annbox.llx, 0.001))); + pdf_add_array(rect_array, pdf_new_number(ROUND(annbox.lly, 0.001))); + pdf_add_array(rect_array, pdf_new_number(ROUND(annbox.urx, 0.001))); + pdf_add_array(rect_array, pdf_new_number(ROUND(annbox.ury, 0.001))); pdf_add_dict (annot_dict, pdf_new_name("Rect"), rect_array); pdf_add_array(page->annots, pdf_ref_obj(annot_dict)); @@ -2432,23 +2439,24 @@ pdf_doc_add_page_content (const char *buffer, unsigned int length) return; } -static char *doccreator = NULL; /* Ugh */ - void pdf_open_document (const char *filename, - bool enable_encrypt, bool enable_object_stream, - double media_width, double media_height, - double annot_grow_amount, int bookmark_open_depth, - int check_gotos) + const char *creator, const unsigned char *id1, const unsigned char *id2, + struct pdf_setting settings) { pdf_doc *p = &pdoc; - pdf_out_init(filename, enable_encrypt, enable_object_stream); + if (settings.enable_encrypt) + pdf_init_encryption(settings.encrypt, id1); + + pdf_out_init(filename, settings.enable_encrypt, + settings.object.enable_objstm, settings.object.enable_predictor); + pdf_files_init(); pdf_doc_init_catalog(p); - p->opt.annot_grow = annot_grow_amount; - p->opt.outline_open_depth = bookmark_open_depth; + p->opt.annot_grow = settings.annot_grow_amount; + p->opt.outline_open_depth = settings.outline_open_depth; pdf_init_resources(); pdf_init_colors(); @@ -2457,26 +2465,31 @@ pdf_open_document (const char *filename, pdf_init_images(); pdf_doc_init_docinfo(p); - if (doccreator) { + if (creator) { pdf_add_dict(p->info, pdf_new_name("Creator"), - pdf_new_string(doccreator, strlen(doccreator))); - doccreator = mfree(doccreator); + pdf_new_string(creator, strlen(creator))); } - pdf_doc_init_bookmarks(p, bookmark_open_depth); + pdf_doc_init_bookmarks(p, settings.outline_open_depth); pdf_doc_init_articles (p); - pdf_doc_init_names (p, check_gotos); - pdf_doc_init_page_tree(p, media_width, media_height); + pdf_doc_init_names (p, settings.check_gotos); + pdf_doc_init_page_tree(p, settings.media_width, settings.media_height); pdf_doc_set_bgcolor(NULL); - if (enable_encrypt) { + if (settings.enable_encrypt) { pdf_obj *encrypt = pdf_encrypt_obj(); pdf_set_encrypt(encrypt); pdf_release_obj(encrypt); } - pdf_set_id(pdf_enc_id_array()); + if (id1 && id2) { + pdf_obj *id_obj = pdf_new_array(); + + pdf_add_array(id_obj, pdf_new_string(id1, 16)); + pdf_add_array(id_obj, pdf_new_string(id2, 16)); + pdf_set_id(id_obj); + } /* Create a default name for thumbnail image files */ if (manual_thumb_enabled) { @@ -2494,26 +2507,19 @@ pdf_open_document (const char *filename, p->pending_forms = NULL; - return; -} - -void -pdf_doc_set_creator (const char *creator) -{ - if (!creator || - creator[0] == '\0') - return; + pdf_init_device(settings.device.dvi2pts, settings.device.precision, + settings.device.ignore_colors); - doccreator = NEW(strlen(creator)+1, char); - strcpy(doccreator, creator); /* Ugh */ + return; } - void pdf_close_document (void) { pdf_doc *p = &pdoc; + pdf_close_device(); + /* * Following things were kept around so user can add dictionary items. */ @@ -2531,6 +2537,7 @@ pdf_close_document (void) pdf_close_resources(); /* Should be at last. */ + pdf_files_close(); pdf_out_flush(); free(thumb_basename); @@ -2744,13 +2751,22 @@ pdf_doc_end_annot (void) void pdf_doc_break_annot (void) { + pdf_doc *p = &pdoc; + double g = p->opt.annot_grow; + if (breaking_state.dirty) { pdf_obj *annot_dict; + pdf_rect rect; /* Copy dict */ annot_dict = pdf_new_dict(); pdf_merge_dict(annot_dict, breaking_state.annot_dict); - pdf_doc_add_annot(pdf_doc_current_page_number(), &(breaking_state.rect), + rect = breaking_state.rect; + rect.llx -= g; + rect.lly -= g; + rect.urx += g; + rect.ury += g; + pdf_doc_add_annot(pdf_doc_current_page_number(), &rect, annot_dict, !breaking_state.broken); pdf_release_obj(annot_dict); diff --git a/tectonic/dpx-pdfdoc.h b/tectonic/dpx-pdfdoc.h index 61ee5253fa..f3f3033759 100644 --- a/tectonic/dpx-pdfdoc.h +++ b/tectonic/dpx-pdfdoc.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -30,18 +30,55 @@ #include "dpx-pdfobj.h" #include "dpx-pdfdev.h" -#define PDF_DOC_GRABBING_NEST_MAX 4 +enum pdf_page_boundary +{ + /* Tectonic note: enum values must align with XeTeX notions */ + pdf_page_boundary__auto = 0, + pdf_page_boundary_mediabox = 2, + pdf_page_boundary_cropbox = 1, + pdf_page_boundary_artbox = 3, + pdf_page_boundary_trimbox = 4, + pdf_page_boundary_bleedbox = 5 +}; -void pdf_doc_set_verbose (int level); +#define PDF_DOC_GRABBING_NEST_MAX 4 -void pdf_open_document (const char *filename, - bool enable_encrypt, - bool enable_object_stream, - double media_width, double media_height, - double annot_grow_amount, - int bookmark_open_depth, - int check_gotos); -void pdf_close_document (void); +struct pdf_dev_setting { + double dvi2pts; /* conversion unit */ + int precision; /* number of decimal digits kept */ + int ignore_colors; /* 1 for black or white */ +}; + +struct pdf_enc_setting { + int key_size; + uint32_t permission; + const char *uplain, *oplain; /* password */ + int use_aes; + int encrypt_metadata; +}; + +struct pdf_obj_setting { + int enable_objstm; + int enable_predictor; +}; + +struct pdf_setting +{ + double media_width, media_height; + double annot_grow_amount; + int outline_open_depth; + int check_gotos; + int enable_encrypt; + struct pdf_enc_setting encrypt; + struct pdf_dev_setting device; + struct pdf_obj_setting object; +}; + +void pdf_open_document (const char *filename, + const char *creator, + const unsigned char *id1, const unsigned char *id2, + struct pdf_setting settings); +void pdf_close_document (void); /* PDF document metadata */ @@ -51,23 +88,23 @@ void pdf_doc_set_creator (const char *creator); /* They just return PDF dictionary object. * Callers are completely responsible for doing right thing... */ -pdf_obj *pdf_doc_get_dictionary (const char *category); -pdf_obj *pdf_doc_get_reference (const char *category); +pdf_obj *pdf_doc_get_dictionary(const char *category); +pdf_obj *pdf_doc_get_reference(const char *category); #define pdf_doc_page_tree() pdf_doc_get_dictionary("Pages") -#define pdf_doc_catalog() pdf_doc_get_dictionary("Catalog") -#define pdf_doc_docinfo() pdf_doc_get_dictionary("Info") -#define pdf_doc_names() pdf_doc_get_dictionary("Names") +#define pdf_doc_catalog() pdf_doc_get_dictionary("Catalog") +#define pdf_doc_docinfo() pdf_doc_get_dictionary("Info") +#define pdf_doc_names() pdf_doc_get_dictionary("Names") #define pdf_doc_this_page() pdf_doc_get_dictionary("@THISPAGE") -int pdf_doc_get_page_count (pdf_file *pf); -pdf_obj *pdf_doc_get_page (pdf_file *pf, int page_no, int options, +int pdf_doc_get_page_count (pdf_file *pf); +pdf_obj *pdf_doc_get_page (pdf_file *pf, int page_no, enum pdf_page_boundary opt_bbox, pdf_rect *bbox, pdf_tmatrix *matrix, pdf_obj **resources_p); -int pdf_doc_current_page_number (void); -pdf_obj *pdf_doc_current_page_resources (void); +int pdf_doc_current_page_number(void); +pdf_obj *pdf_doc_current_page_resources(void); -pdf_obj *pdf_doc_ref_page (unsigned page_no); +pdf_obj *pdf_doc_ref_page(unsigned page_no); #define pdf_doc_this_page_ref() pdf_doc_get_reference("@THISPAGE") #define pdf_doc_next_page_ref() pdf_doc_get_reference("@NEXTPAGE") #define pdf_doc_prev_page_ref() pdf_doc_get_reference("@PREVPAGE") diff --git a/tectonic/dpx-pdfdraw.c b/tectonic/dpx-pdfdraw.c index 87d025d335..839272ea3f 100644 --- a/tectonic/dpx-pdfdraw.c +++ b/tectonic/dpx-pdfdraw.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -28,6 +28,7 @@ #include #include +#include "dpx-dpxconf.h" #include "dpx-dpxutil.h" #include "dpx-error.h" #include "dpx-mem.h" diff --git a/tectonic/dpx-pdfencoding.c b/tectonic/dpx-pdfencoding.c index b0ee6c2473..3785716cff 100644 --- a/tectonic/dpx-pdfencoding.c +++ b/tectonic/dpx-pdfencoding.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2008-2016 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, + Copyright (C) 2008-2019 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -30,6 +30,7 @@ #include #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" #include "dpx-error.h" #include "dpx-mem.h" @@ -40,18 +41,10 @@ static bool is_similar_charset (char **encoding, const char **encoding2); static pdf_obj *make_encoding_differences (char **encoding, char **baseenc, const char *is_used); -static unsigned char verbose = 0; - static const char *MacRomanEncoding[256]; static const char *MacExpertEncoding[256]; static const char *WinAnsiEncoding[256]; -void -pdf_encoding_set_verbose (int level) -{ - verbose = level; -} - /* * ident: File name, e.g., 8a.enc. * name: Name of encoding, StandardEncoding, TeXBase1Encoding, ... @@ -268,7 +261,7 @@ load_encoding_file (const char *filename) if (!filename) return -1; - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message("(Encoding:%s", filename); handle = dpx_tt_open(filename, ".enc", TTIF_ENC); @@ -314,14 +307,14 @@ load_encoding_file (const char *filename) filename, enc_vec, NULL, 0); if (enc_name) { - if (verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_message("[%s]", pdf_name_value(enc_name)); pdf_release_obj(enc_name); } pdf_release_obj(encoding_array); - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message(")"); return enc_id; @@ -447,7 +440,7 @@ void pdf_encoding_complete (void) * we do use a base encodings for PDF versions >= 1.3. */ int with_base = !(encoding->flags & FLAG_USED_BY_TYPE3) - || pdf_get_version() >= 4; + || pdf_check_version(1, 4) >= 0; assert(!encoding->resource); encoding->resource = create_encoding_resource(encoding, with_base ? encoding->baseenc : NULL); @@ -615,6 +608,10 @@ pdf_encoding_get_tounicode (int encoding_id) * Note: The PDF 1.4 reference is not consistent: Section 5.9 describes * the Unicode mapping of PDF 1.3 and Section 9.7.2 (in the context of * Tagged PDF) the one of PDF 1.5. + * + * CHANGED: 20180906 + * Always create ToUnicode CMap unless there is missing mapping. + * Change made on rev.7557 broke ToUnicode CMap support. Now reverted. */ pdf_obj * pdf_create_ToUnicode_CMap (const char *enc_name, @@ -622,12 +619,15 @@ pdf_create_ToUnicode_CMap (const char *enc_name, { pdf_obj *stream; CMap *cmap; - int code, all_predef; + int code, count, total_fail; char *cmap_name; unsigned char *p, *endptr; assert(enc_name && enc_vec); + if (!is_used) + return NULL; + cmap_name = NEW(strlen(enc_name)+strlen("-UTF16")+1, char); sprintf(cmap_name, "%s-UTF16", enc_name); @@ -640,32 +640,33 @@ pdf_create_ToUnicode_CMap (const char *enc_name, CMap_add_codespacerange(cmap, range_min, range_max, 1); - all_predef = 1; + count = 0; + total_fail = 0; for (code = 0; code <= 0xff; code++) { if (is_used && !is_used[code]) continue; if (enc_vec[code]) { - int32_t len; + size_t len; int fail_count = 0; - agl_name *agln = agl_lookup_list(enc_vec[code]); - /* Adobe glyph naming conventions are not used by viewers, - * hence even ligatures (e.g, "f_i") must be explicitly defined - */ - if (pdf_get_version() < 5 || !agln || !agln->is_predef) { - wbuf[0] = (code & 0xff); - p = wbuf + 1; - endptr = wbuf + WBUF_SIZE; - len = agl_sput_UTF16BE(enc_vec[code], &p, endptr, &fail_count); - if (len >= 1 && !fail_count) { - CMap_add_bfchar(cmap, wbuf, 1, wbuf + 1, len); - all_predef &= agln && agln->is_predef; - } - } + wbuf[0] = (code & 0xff); + p = wbuf + 1; + endptr = wbuf + WBUF_SIZE; + len = agl_sput_UTF16BE(enc_vec[code], &p, endptr, &fail_count); + if (len < 1 && fail_count > 0) { + total_fail++; + } else { + CMap_add_bfchar(cmap, wbuf, 1, wbuf + 1, len); + count++; + } } } - stream = all_predef ? NULL : CMap_create_stream(cmap); + if (total_fail > 0) { + if (dpx_conf.verbose_level > 0) + dpx_warning("Glyphs with no Unicode mapping found. Removing ToUnicode CMap."); + } + stream = (count == 0 || total_fail > 0) ? NULL : CMap_create_stream(cmap); CMap_release(cmap); free(cmap_name); @@ -697,7 +698,7 @@ pdf_load_ToUnicode_stream (const char *ident) if (CMap_parse(cmap, handle) < 0) { dpx_warning("Reading CMap file \"%s\" failed.", ident); } else { - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message("(CMap:%s)", ident); stream = CMap_create_stream(cmap); diff --git a/tectonic/dpx-pdfencoding.h b/tectonic/dpx-pdfencoding.h index b987e98b32..204e6002b4 100644 --- a/tectonic/dpx-pdfencoding.h +++ b/tectonic/dpx-pdfencoding.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -27,8 +27,6 @@ #include "dpx-pdfobj.h" -void pdf_encoding_set_verbose (int level); - void pdf_init_encodings (void); void pdf_close_encodings (void); diff --git a/tectonic/dpx-pdfencrypt.c b/tectonic/dpx-pdfencrypt.c index c36c71cecf..e108fe2e5c 100644 --- a/tectonic/dpx-pdfencrypt.c +++ b/tectonic/dpx-pdfencrypt.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -26,7 +26,9 @@ #include #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-dpxcrypt.h" +#include "dpx-dpxutil.h" #include "dpx-dvipdfmx.h" #include "dpx-error.h" #include "dpx-mem.h" @@ -42,6 +44,9 @@ * TODO: Convert password to PDFDocEncoding. SASLPrep stringpref for AESV3. */ +static void pdf_enc_set_passwd (unsigned int bits, unsigned int perm, + const char *oplain, const char *uplain); + /* PDF-2.0 is not published yet. */ #define USE_ADOBE_EXTENSION 1 @@ -64,6 +69,7 @@ static struct pdf_sec { struct { int use_aes; int encrypt_metadata; + int need_adobe_extension; } setting; struct { @@ -79,57 +85,28 @@ static const unsigned char padding_bytes[32] = { 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a }; -static unsigned char verbose = 0; - -void pdf_enc_set_verbose (int level) -{ - verbose = level; -} - -static void -pdf_enc_init (int use_aes, int encrypt_metadata) +int +pdf_init_encryption (struct pdf_enc_setting settings, const unsigned char *trailer_id) { + time_t current_time; struct pdf_sec *p = &sec_data; - srand(source_date_epoch); /* For AES IV */ - p->setting.use_aes = use_aes; - p->setting.encrypt_metadata = encrypt_metadata; -} - -#define PRODUCER \ -"%s-%s, Copyright 2002-2015 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata" - -void -pdf_enc_compute_id_string (const char *dviname, const char *pdfname) -{ - struct pdf_sec *p = &sec_data; - char *date_string, *producer; - struct tm *bd_time; - MD5_CONTEXT md5; - - /* FIXME: This should be placed in main() or somewhere. */ - pdf_enc_init(1, 1); - - MD5_init(&md5); - - date_string = NEW(15, char); - bd_time = gmtime(&source_date_epoch); - sprintf(date_string, "%04d%02d%02d%02d%02d%02d", - bd_time->tm_year + 1900, bd_time->tm_mon + 1, bd_time->tm_mday, - bd_time->tm_hour, bd_time->tm_min, bd_time->tm_sec); - MD5_write(&md5, (unsigned char *)date_string, strlen(date_string)); - free(date_string); - - producer = NEW(strlen(PRODUCER)+strlen(DVIPDFMX_PROG_NAME)+strlen(DPX_VERSION), char); - sprintf(producer, PRODUCER, DVIPDFMX_PROG_NAME, DPX_VERSION); - MD5_write(&md5, (unsigned char *)producer, strlen(producer)); - free(producer); - - if (dviname) - MD5_write(&md5, (const unsigned char *) dviname, strlen(dviname)); - if (pdfname) - MD5_write(&md5, (const unsigned char *) pdfname, strlen(pdfname)); - MD5_final(p->ID, &md5); + if (trailer_id) { + memcpy(p->ID, trailer_id, 16); + } else { + memset(p->ID, 0, 16); + } + current_time = dpx_util_get_unique_time_if_given(); + if (current_time == INVALID_EPOCH_VALUE) + current_time = time(NULL); + srand(current_time); /* For AES IV */ + p->setting.use_aes = settings.use_aes; + p->setting.encrypt_metadata = settings.encrypt_metadata; + p->setting.need_adobe_extension = 0; + + pdf_enc_set_passwd(settings.key_size, settings.permission, + settings.oplain, settings.uplain); + return 0; } static void @@ -177,16 +154,16 @@ compute_owner_password (struct pdf_sec *p, ARC4(&arc4, 32, padded, tmp1); if (p->R >= 3) { - for (i = 1; i <= 19; i++) { + for (i = 1; i <= 19; i++) { memcpy(tmp2, tmp1, 32); for (j = 0; j < p->key_size; j++) key[j] = hash[j] ^ i; ARC4_set_key(&arc4, p->key_size, key); ARC4(&arc4, 32, tmp2, tmp1); + } } - } + memcpy(p->O, tmp1, 32); } - memcpy(p->O, hash, 32); } static void @@ -281,17 +258,20 @@ compute_hash_V5 (unsigned char *hash, const unsigned char *salt, const unsigned char *user_key, int R /* revision */) { - SHA256_CONTEXT sha; unsigned char K[64]; size_t K_len; int nround; - SHA256_init (&sha); - SHA256_write(&sha, (const unsigned char *)passwd, strlen(passwd)); - SHA256_write(&sha, salt, 8); - if (user_key) - SHA256_write(&sha, user_key, 48); - SHA256_final(hash, &sha); + { + SHA256_CONTEXT sha; + + SHA256_init (&sha); + SHA256_write(&sha, (const unsigned char *)passwd, strlen(passwd)); + SHA256_write(&sha, salt, 8); + if (user_key) + SHA256_write(&sha, user_key, 48); + SHA256_final(hash, &sha); + } assert( R ==5 || R == 6 ); @@ -415,17 +395,21 @@ compute_user_password_V5 (struct pdf_sec *p, const char *uplain) static void check_version (struct pdf_sec *p, int version) { - if (p->V > 2 && version < 4) { + if (p->V > 2 && version < 14) { dpx_warning("Current encryption setting requires PDF version >= 1.4."); p->V = 1; p->key_size = 5; - } else if (p->V == 4 && version < 5) { + } else if (p->V == 4 && version < 15) { dpx_warning("Current encryption setting requires PDF version >= 1.5."); p->V = 2; - } else if (p->V ==5 && version < 7) { + } else if (p->V ==5 && version < 17) { dpx_warning("Current encryption setting requires PDF version >= 1.7" \ " (plus Adobe Extension Level 3)."); p->V = 4; + p->key_size = 16; + } + if (p->V == 5 && version < 20) { + p->setting.need_adobe_extension = 1; } } @@ -499,16 +483,14 @@ preproc_password (const char *passwd, char *outbuf, int V) return error; } -void +static void pdf_enc_set_passwd (unsigned int bits, unsigned int perm, const char *oplain, const char *uplain) { struct pdf_sec *p = &sec_data; char opasswd[128], upasswd[128]; int version; - - assert(oplain); - assert(uplain); + char empty_passwd[1] = "\0"; version = pdf_get_version(); @@ -527,6 +509,9 @@ pdf_enc_set_passwd (unsigned int bits, unsigned int perm, check_version(p, version); p->P = (int32_t) (perm | 0xC0U); + /* Bit position 10 shall be always set to 1 for PDF >= 2.0. */ + if (version >= 20) + p->P |= (1 << 9); switch (p->V) { case 1: p->R = (p->P < 0x100L) ? 2 : 3; @@ -553,11 +538,19 @@ pdf_enc_set_passwd (unsigned int bits, unsigned int perm, memset(opasswd, 0, 128); memset(upasswd, 0, 128); /* Password must be preprocessed. */ - if (preproc_password(oplain, opasswd, p->V) < 0) - dpx_warning("Invaid UTF-8 string for password."); + if (oplain) { + if (preproc_password(oplain, opasswd, p->V) < 0) + dpx_warning("Invaid UTF-8 string for password."); + } else { + preproc_password(empty_passwd, opasswd, p->V); + } - if (preproc_password(uplain, upasswd, p->V) < 0) - dpx_warning("Invalid UTF-8 string for passowrd."); + if (uplain) { + if (preproc_password(uplain, upasswd, p->V) < 0) + dpx_warning("Invalid UTF-8 string for passowrd."); + } else { + preproc_password(empty_passwd, upasswd, p->V); + } if (p->R >= 3) p->P |= 0xFFFFF000U; @@ -715,7 +708,7 @@ pdf_encrypt_obj (void) } #ifdef USE_ADOBE_EXTENSION - if (p->R > 5) { + if (p->R > 5 && p->setting.need_adobe_extension != 0) { pdf_obj *catalog = pdf_doc_catalog(); pdf_obj *ext = pdf_new_dict(); pdf_obj *adbe = pdf_new_dict(); @@ -731,17 +724,6 @@ pdf_encrypt_obj (void) return doc_encrypt; } -pdf_obj *pdf_enc_id_array (void) -{ - struct pdf_sec *p = &sec_data; - pdf_obj *id = pdf_new_array(); - - pdf_add_array(id, pdf_new_string(p->ID, 16)); - pdf_add_array(id, pdf_new_string(p->ID, 16)); - - return id; -} - void pdf_enc_set_label (unsigned label) { struct pdf_sec *p = &sec_data; diff --git a/tectonic/dpx-pdfencrypt.h b/tectonic/dpx-pdfencrypt.h index d07cf7da25..65c1f76a69 100644 --- a/tectonic/dpx-pdfencrypt.h +++ b/tectonic/dpx-pdfencrypt.h @@ -2,7 +2,7 @@ This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -27,17 +27,14 @@ #include +#include "dpx-pdfdoc.h" #include "dpx-pdfobj.h" #define MAX_PWD_LEN 127 -void pdf_enc_set_verbose (int level); -pdf_obj *pdf_enc_id_array (void); -void pdf_enc_compute_id_string (const char *dviname, const char *pdfname); +int pdf_init_encryption(struct pdf_enc_setting, const unsigned char *trailer_id); void pdf_enc_set_label (unsigned label); void pdf_enc_set_generation (unsigned generation); -void pdf_enc_set_passwd (unsigned int size, unsigned int perm, - const char *owner, const char *user); void pdf_encrypt_data (const unsigned char *plain, size_t plain_len, unsigned char **cipher, size_t *cipher_len); pdf_obj *pdf_encrypt_obj (void); diff --git a/tectonic/dpx-pdffont.c b/tectonic/dpx-pdffont.c index 02c00429ac..19e003c84b 100644 --- a/tectonic/dpx-pdffont.c +++ b/tectonic/dpx-pdffont.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2008-2017 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, + Copyright (C) 2008-2018 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -33,13 +33,13 @@ #include #include #include -#include #include "core-bridge.h" #include "dpx-agl.h" #include "dpx-cid.h" #include "dpx-cidtype0.h" #include "dpx-cmap.h" +#include "dpx-dpxconf.h" #include "dpx-error.h" #include "dpx-mem.h" #include "dpx-pdfencoding.h" @@ -52,28 +52,8 @@ #include "dpx-type1.h" #include "dpx-type1c.h" -static int __verbose = 0; - #define MREC_HAS_TOUNICODE(m) ((m) && (m)->opt.tounicode) -void -pdf_font_set_verbose (int level) -{ - __verbose = level; - CMap_set_verbose(level); - Type0Font_set_verbose(level); - CIDFont_set_verbose(level); - pdf_encoding_set_verbose(level); - agl_set_verbose(level); - otf_cmap_set_verbose(level); -} - -int -pdf_font_get_verbose (void) -{ - return __verbose; -} - void pdf_font_set_dpi (int font_dpi) { @@ -436,7 +416,7 @@ try_load_ToUnicode_CMap (pdf_font *font) pdf_add_dict(fontdict, pdf_new_name("ToUnicode"), pdf_ref_obj (tounicode)); /* _FIXME_ */ - if (__verbose) + if (dpx_conf.verbose_level > 0) dpx_message("pdf_font>> ToUnicode CMap \"%s\" attached to font id=\"%s\".\n", cmap_name, font->map_name); } @@ -457,19 +437,19 @@ pdf_close_fonts (void) font = GET_FONT(font_id); - if (__verbose) { + if (dpx_conf.verbose_level > 0) { if (font->subtype != PDF_FONT_FONTTYPE_TYPE0) { dpx_message("(%s", pdf_font_get_ident(font)); - if (__verbose > 2 && + if (dpx_conf.verbose_level > 2 && !pdf_font_get_flag(font, PDF_FONT_FLAG_NOEMBED)) { dpx_message("[%s+%s]", pdf_font_get_uniqueTag(font), pdf_font_get_fontname(font)); - } else if (__verbose > 1) { + } else if (dpx_conf.verbose_level > 1) { dpx_message("[%s]", pdf_font_get_fontname(font)); } - if (__verbose > 1) { + if (dpx_conf.verbose_level > 1) { if (pdf_font_get_encoding(font) >= 0) { dpx_message("[%s]", pdf_encoding_get_name(pdf_font_get_encoding(font))); @@ -487,23 +467,23 @@ pdf_close_fonts (void) /* Type 0 is handled separately... */ switch (font->subtype) { case PDF_FONT_FONTTYPE_TYPE1: - if (__verbose) + if (dpx_conf.verbose_level > 0) dpx_message("[Type1]"); if (!pdf_font_get_flag(font, PDF_FONT_FLAG_BASEFONT)) pdf_font_load_type1(font); break; case PDF_FONT_FONTTYPE_TYPE1C: - if (__verbose) + if (dpx_conf.verbose_level > 0) dpx_message("[Type1C]"); pdf_font_load_type1c(font); break; case PDF_FONT_FONTTYPE_TRUETYPE: - if (__verbose) + if (dpx_conf.verbose_level > 0) dpx_message("[TrueType]"); pdf_font_load_truetype(font); break; case PDF_FONT_FONTTYPE_TYPE3: - if (__verbose) + if (dpx_conf.verbose_level > 0) dpx_message("[Type3/PK]"); pdf_font_load_pkfont (font); break; @@ -517,7 +497,7 @@ pdf_close_fonts (void) if (font->encoding_id >= 0 && font->subtype != PDF_FONT_FONTTYPE_TYPE0) pdf_encoding_add_usedchars(font->encoding_id, font->usedchars); - if (__verbose) { + if (dpx_conf.verbose_level > 0) { if (font->subtype != PDF_FONT_FONTTYPE_TYPE0) dpx_message(")"); } @@ -533,16 +513,20 @@ pdf_close_fonts (void) pdf_obj *tounicode; /* Predefined encodings (and those simplified to them) are embedded - as direct objects, but this is purely a matter of taste. */ + * as direct objects, but this is purely a matter of taste. + */ if (enc_obj) pdf_add_dict(font->resource, pdf_new_name("Encoding"), PDF_OBJ_NAMETYPE(enc_obj) ? pdf_link_obj(enc_obj) : pdf_ref_obj(enc_obj)); - + /* For built-in encoding, each font loader create ToUnicode CMap. */ if (!pdf_lookup_dict(font->resource, "ToUnicode") - && (tounicode = pdf_encoding_get_tounicode(font->encoding_id))) - pdf_add_dict(font->resource, - pdf_new_name("ToUnicode"), pdf_ref_obj(tounicode)); + && (tounicode = pdf_encoding_get_tounicode(font->encoding_id))) { + if (tounicode) { + pdf_add_dict(font->resource, + pdf_new_name("ToUnicode"), pdf_ref_obj(tounicode)); + } + } } else if (font->subtype == PDF_FONT_FONTTYPE_TRUETYPE) { /* encoding_id < 0 means MacRoman here (but not really) * We use MacRoman as "default" encoding. */ @@ -582,7 +566,35 @@ pdf_font_findresource (const char *tex_name, * point sizes would be looked up twice unecessarily.) */ fontname = mrec ? mrec->font_name : tex_name; - if (mrec && mrec->enc_name) { + /* XeTeX specific... + * First try loading GID-to-CID mapping from CFF CID-keyed OpenType font. + * There was a serious bug in xdv support... It was implemented with the wrong + * assumption that CID always equals to GID. + * TODO: There is a possibility that GID-to-CID mapping is not one-to-one. + * Use internal glyph ordering rather than map GID to CIDs. + */ + if (mrec && mrec->opt.use_glyph_encoding) { + int wmode = 0; + /* Should be always Identity-H or Identity-V for XeTeX output. */ + if (mrec->enc_name) { + if (!strcmp(mrec->enc_name, "Identity-V")) + wmode = 1; + else if (!strcmp(mrec->enc_name, "Identity-H")) + wmode = 0; + else { + dpx_warning("Unexpected encoding specified for xdv: %s", mrec->enc_name); + } + /* cmap_id < 0 is returned if ... + * Font is not a CFF font + * GID to CID mapping is identity mapping + * + * TODO: fontmap record still has Identity CMap assigned but actually different CMap + * can be attached to the font here. Should we fix mrec->enc_name here? + */ + cmap_id = otf_try_load_GID_to_CID_map(mrec->font_name, mrec->opt.index, wmode); + } + } + if (cmap_id < 0 && mrec && mrec->enc_name) { #define MAYBE_CMAP(s) (!strstr((s), ".enc") || strstr((s), ".cmap")) if (MAYBE_CMAP(mrec->enc_name)) { cmap_id = CMap_cache_find(mrec->enc_name); @@ -605,13 +617,14 @@ pdf_font_findresource (const char *tex_name, * Turn on map option. */ if (minbytes == 2 && mrec->opt.mapc < 0) { - if (__verbose) { + if (dpx_conf.verbose_level > 0) { dpx_message("\n"); dpx_message("pdf_font>> Input encoding \"%s\" requires at least 2 bytes.\n", CMap_get_name(cmap)); dpx_message("pdf_font>> The -m <00> option will be assumed for \"%s\".\n", mrec->font_name); } - mrec->opt.mapc = 0; /* _FIXME_ */ + /* FIXME: The following code modifies mrec. */ + mrec->opt.mapc = 0; } } else if (streq_ptr(mrec->enc_name, "unicode")) { cmap_id = otf_load_Unicode_CMap(mrec->font_name, @@ -631,7 +644,6 @@ pdf_font_findresource (const char *tex_name, _tt_abort("Could not find encoding file \"%s\".", mrec->enc_name); } } - if (mrec && cmap_id >= 0) { /* * Composite Font @@ -650,7 +662,7 @@ pdf_font_findresource (const char *tex_name, font->font_id == type0_id && font->encoding_id == cmap_id) { found = 1; - if (__verbose) { + if (dpx_conf.verbose_level > 0) { dpx_message("\npdf_font>> Type0 font \"%s\" (cmap_id=%d) found at font_id=%d.\n", mrec->font_name, cmap_id, font_id); } @@ -673,7 +685,7 @@ pdf_font_findresource (const char *tex_name, font_cache.count++; - if (__verbose) { + if (dpx_conf.verbose_level > 0) { dpx_message("\npdf_font>> Type0 font \"%s\"", fontname); dpx_message(" cmap_id=<%s,%d>", mrec->enc_name, font->encoding_id); dpx_message(" opened at font_id=<%s,%d>.\n", tex_name, font_id); @@ -724,7 +736,7 @@ pdf_font_findresource (const char *tex_name, } if (found) { - if (__verbose) { + if (dpx_conf.verbose_level > 0) { dpx_message("\npdf_font>> Simple font \"%s\" (enc_id=%d) found at id=%d.\n", fontname, encoding_id, font_id); } @@ -767,7 +779,7 @@ pdf_font_findresource (const char *tex_name, font_cache.count++; - if (__verbose) { + if (dpx_conf.verbose_level > 0) { dpx_message("\npdf_font>> Simple font \"%s\"", fontname); dpx_message(" enc_id=<%s,%d>", (mrec && mrec->enc_name) ? mrec->enc_name : "builtin", font->encoding_id); diff --git a/tectonic/dpx-pdffont.h b/tectonic/dpx-pdffont.h index 3519fd2a62..47b5c36d34 100644 --- a/tectonic/dpx-pdffont.h +++ b/tectonic/dpx-pdffont.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -38,9 +38,6 @@ #define PDF_FONT_FONTTYPE_TYPE0 4 -void pdf_font_set_verbose (int level); -int pdf_font_get_verbose (void); - void pdf_font_set_dpi (int font_dpi); #define PDF_FONT_FLAG_NOEMBED (1 << 0) diff --git a/tectonic/dpx-pdflimits.h b/tectonic/dpx-pdflimits.h index aac8160a35..89e49a5ce0 100644 --- a/tectonic/dpx-pdflimits.h +++ b/tectonic/dpx-pdflimits.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -30,9 +30,9 @@ * NOTE: Don't forget to update CIDFont_stdcc_def[] in cid.c * if you increase PDF_VERSION_MAX! */ -#define PDF_VERSION_MIN 3 -#define PDF_VERSION_MAX 7 -#define PDF_VERSION_DEFAULT 5 +#define PDF_VERSION_MIN 13 +#define PDF_VERSION_MAX 20 +#define PDF_VERSION_DEFAULT 15 /* * PDF_NAME_LEN_MAX: see, Appendix C of PDF Ref. v1.3, 2nd. ed. diff --git a/tectonic/dpx-pdfobj.c b/tectonic/dpx-pdfobj.c index f39d521626..936842ca81 100644 --- a/tectonic/dpx-pdfobj.c +++ b/tectonic/dpx-pdfobj.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2020 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -28,6 +28,7 @@ #include #include +#include "dpx-dpxconf.h" #include "dpx-dpxutil.h" #include "dpx-error.h" #include "dpx-mem.h" @@ -66,6 +67,7 @@ struct pdf_obj unsigned int refcount; /* Number of links to this object */ int flags; void *data; + /* Tectonic: not including PDFOBJ_DEBUG #ifdefs */ }; struct pdf_boolean @@ -200,7 +202,7 @@ static pdf_obj *xref_stream; /* Internal static routines */ -static int parse_pdf_version (rust_input_handle_t handle, unsigned int *ret_version); +static int check_for_pdf_version (rust_input_handle_t handle); static void pdf_flush_obj (pdf_obj *object, rust_output_handle_t handle); static void pdf_label_obj (pdf_obj *object); @@ -240,7 +242,6 @@ static void release_dict (pdf_dict *dict); static void write_stream (pdf_stream *stream, rust_output_handle_t handle); static void release_stream (pdf_stream *stream); -static int verbose = 0; static char compression_level = 9; static char compression_use_predictor = 1; @@ -264,16 +265,10 @@ pdf_set_compression (int level) return; } -void -pdf_set_use_predictor (int bval) -{ - compression_use_predictor = bval ? 1 : 0; -} - -static unsigned int pdf_version = PDF_VERSION_DEFAULT; +static int pdf_version = PDF_VERSION_DEFAULT; void -pdf_set_version (unsigned version) +pdf_set_version (int version) { /* Don't forget to update CIDFont_stdcc_def[] in cid.c too! */ if (version >= PDF_VERSION_MIN && version <= PDF_VERSION_MAX) { @@ -281,22 +276,28 @@ pdf_set_version (unsigned version) } } -unsigned int +int pdf_get_version (void) { return pdf_version; } int -pdf_obj_get_verbose(void) +pdf_get_version_major (void) { - return verbose; + return pdf_version/10; } -void -pdf_obj_set_verbose(int level) +int +pdf_get_version_minor (void) +{ + return pdf_version%10; +} + +int +pdf_check_version (int major, int minor) { - verbose = level; + return (pdf_version >= major*10+minor) ? 0 : -1; } static pdf_obj *current_objstm = NULL; @@ -319,7 +320,8 @@ add_xref_entry (unsigned label, unsigned char type, unsigned int field2, unsigne #define BINARY_MARKER "%\344\360\355\370\n" void -pdf_out_init (const char *filename, bool do_encryption, bool enable_object_stream) +pdf_out_init (const char *filename, + bool do_encryption, bool enable_objstm, bool enable_predictor) { char v; @@ -328,8 +330,8 @@ pdf_out_init (const char *filename, bool do_encryption, bool enable_object_strea add_xref_entry(0, 0, 0, 0xffff); next_label = 1; - if (pdf_version >= 5) { - if (enable_object_stream) { + if (pdf_version >= 15) { + if (enable_objstm) { xref_stream = pdf_new_stream(STREAM_COMPRESS); xref_stream->flags |= OBJ_NO_ENCRYPT; trailer_dict = pdf_stream_dict(xref_stream); @@ -358,14 +360,18 @@ pdf_out_init (const char *filename, bool do_encryption, bool enable_object_strea _tt_abort("Unable to open file."); } - pdf_out(pdf_output_handle, "%PDF-1.", strlen("%PDF-1.")); - v = '0' + pdf_version; + pdf_out(pdf_output_handle, "%PDF-", strlen("%PDF-")); + v = '0' + (pdf_version / 10); + pdf_out(pdf_output_handle, &v, 1); + pdf_out(pdf_output_handle, ".", 1); + v = '0' + (pdf_version % 10); pdf_out(pdf_output_handle, &v, 1); pdf_out(pdf_output_handle, "\n", 1); pdf_out(pdf_output_handle, BINARY_MARKER, strlen(BINARY_MARKER)); enc_mode = false; doc_enc_mode = do_encryption; + compression_use_predictor = enable_predictor; } static void @@ -493,14 +499,16 @@ pdf_out_flush (void) pdf_out(pdf_output_handle, format_buffer, length); pdf_out(pdf_output_handle, "%%EOF\n", 6); - if (verbose) { + if (dpx_conf.verbose_level > 0) { if (compression_level > 0) { dpx_message("Compression saved %d bytes%s\n", compression_saved, - pdf_version < 5 ? ". Try \"-V 5\" for better compression" : ""); + pdf_version < 15 ? ". Try \"-V 1.5\" for better compression" : ""); } } ttstub_output_close(pdf_output_handle); + pdf_output_file_position = 0; + pdf_output_line_position = 0; pdf_output_handle = NULL; } } @@ -872,20 +880,20 @@ pdf_new_string (const void *str, size_t length) pdf_obj *result; pdf_string *data; - assert(str); - result = pdf_new_obj(PDF_STRING); data = NEW(1, pdf_string); result->data = data; data->length = length; - if (length) { + if (str && length) { data->string = NEW(length+1, unsigned char); memcpy(data->string, str, length); /* Shouldn't assume NULL terminated. */ data->string[length] = '\0'; - } else + } else { data->string = NULL; + data->length = 0; + } return result; } @@ -1622,20 +1630,6 @@ filter_PNG15_apply_filter (unsigned char *raster, return dst; } -/* TIFF predictor filter support - * - * Many PDF viewers seems to have broken TIFF 2 predictor support? - * Ony GhostScript and MuPDF render 4bpc grayscale image with TIFF 2 predictor - * filter applied correctly. - * - * Acrobat Reader DC 2015.007.20033 NG - * Adobe Acrobat X 10.1.13 NG - * Foxit Reader 4.1.5.425 NG - * GhostScript 9.16 OK - * SumatraPDF(MuPDF) v3.0 OK - * Evince(poppler) 2.32.0.145 NG (1bit and 4bit broken) - */ - /* This modifies "raster" itself! */ static void apply_filter_TIFF2_1_2_4 (unsigned char *raster, @@ -1699,8 +1693,9 @@ apply_filter_TIFF2_1_2_4 (unsigned char *raster, } } - if (outbits > 0) + if (outbits > 0) { raster[k] = outbuf << (8 - outbits); + } } free(prev); @@ -2023,48 +2018,9 @@ pdf_add_stream (pdf_obj *stream, const void *stream_data, int length) #if HAVE_ZLIB #define WBUF_SIZE 4096 -int -pdf_add_stream_flate (pdf_obj *dst, const void *data, int len) -{ - z_stream z; - Bytef wbuf[WBUF_SIZE]; - - z.zalloc = Z_NULL; z.zfree = Z_NULL; z.opaque = Z_NULL; - - z.next_in = data; z.avail_in = len; - z.next_out = (Bytef *) wbuf; z.avail_out = WBUF_SIZE; - - if (inflateInit(&z) != Z_OK) { - dpx_warning("inflateInit() failed."); - return -1; - } - - for (;;) { - int status; - status = inflate(&z, Z_NO_FLUSH); - if (status == Z_STREAM_END) - break; - else if (status != Z_OK) { - dpx_warning("inflate() failed. Broken PDF file?"); - inflateEnd(&z); - return -1; - } - - if (z.avail_out == 0) { - pdf_add_stream(dst, wbuf, WBUF_SIZE); - z.next_out = wbuf; - z.avail_out = WBUF_SIZE; - } - } - - if (WBUF_SIZE - z.avail_out > 0) - pdf_add_stream(dst, wbuf, WBUF_SIZE - z.avail_out); - - return (inflateEnd(&z) == Z_OK ? 0 : -1); -} static int -get_decode_parms (struct decode_parms *parms, pdf_obj *dict) +filter_get_DecodeParms_FlateDecode (struct decode_parms *parms, pdf_obj *dict) { pdf_obj *tmp; @@ -2078,18 +2034,25 @@ get_decode_parms (struct decode_parms *parms, pdf_obj *dict) parms->columns = 1; tmp = pdf_deref_obj(pdf_lookup_dict(dict, "Predictor")); - if (tmp) + if (tmp) { parms->predictor = pdf_number_value(tmp); + pdf_release_obj(tmp); + } tmp = pdf_deref_obj(pdf_lookup_dict(dict, "Colors")); - if (tmp) + if (tmp) { parms->colors = pdf_number_value(tmp); + pdf_release_obj(tmp); + } tmp = pdf_deref_obj(pdf_lookup_dict(dict, "BitsPerComponent")); - if (tmp) + if (tmp) { parms->bits_per_component = pdf_number_value(tmp); + pdf_release_obj(tmp); + } tmp = pdf_deref_obj(pdf_lookup_dict(dict, "Columns")); - if (tmp) + if (tmp) { parms->columns = pdf_number_value(tmp); - + pdf_release_obj(tmp); + } if (parms->bits_per_component != 1 && parms->bits_per_component != 2 && parms->bits_per_component != 4 && @@ -2154,10 +2117,10 @@ filter_row_TIFF2 (unsigned char *dst, const unsigned char *src, * Especially, calling pdf_add_stream() for each 4 bytes append is highly * inefficient. */ -static int -filter_decoded (pdf_obj *dst, const void *src, int srclen, - struct decode_parms *parms) +static pdf_obj * +filter_stream_decode_Predictor (const void *src, size_t srclen, struct decode_parms *parms) { + pdf_obj *dst; const unsigned char *p = (const unsigned char *) src; const unsigned char *endptr = p + srclen; unsigned char *prev, *buf; @@ -2166,6 +2129,8 @@ filter_decoded (pdf_obj *dst, const void *src, int srclen, int length = (parms->columns * bits_per_pixel + 7) / 8; int i, error = 0; + dst = pdf_new_stream(0); + prev = NEW(length, unsigned char); buf = NEW(length, unsigned char); @@ -2291,16 +2256,21 @@ filter_decoded (pdf_obj *dst, const void *src, int srclen, free(prev); free(buf); - return error; + if (error) { + pdf_release_obj(dst); + dst = NULL; + } + + return dst; } -static int -pdf_add_stream_flate_filtered (pdf_obj *dst, const void *data, int len, struct decode_parms *parms) +static pdf_obj * +filter_stream_decode_FlateDecode (const void *data, size_t len, struct decode_parms *parms) { + pdf_obj *dst; pdf_obj *tmp; z_stream z; Bytef wbuf[WBUF_SIZE]; - int error; z.zalloc = Z_NULL; z.zfree = Z_NULL; z.opaque = Z_NULL; @@ -2309,19 +2279,22 @@ pdf_add_stream_flate_filtered (pdf_obj *dst, const void *data, int len, struct d if (inflateInit(&z) != Z_OK) { dpx_warning("inflateInit() failed."); - return -1; + return NULL; } tmp = pdf_new_stream(0); for (;;) { int status; status = inflate(&z, Z_NO_FLUSH); - if (status == Z_STREAM_END) + if (status == Z_STREAM_END) { break; - else if (status != Z_OK) { - dpx_warning("inflate() failed. Broken PDF file?"); + } else if (status == Z_DATA_ERROR && z.avail_in == 0) { + dpx_warning("Ignoring zlib error: status=%d, message=\"%s\"", status, z.msg); + } else if (status != Z_OK) { + dpx_warning("inflate() failed (status=%d, message=\"%s\"", status, z.msg); inflateEnd(&z); - return -1; + pdf_release_obj(tmp); + return NULL; } if (z.avail_out == 0) { @@ -2334,83 +2307,312 @@ pdf_add_stream_flate_filtered (pdf_obj *dst, const void *data, int len, struct d if (WBUF_SIZE - z.avail_out > 0) pdf_add_stream(tmp, wbuf, WBUF_SIZE - z.avail_out); - error = filter_decoded(dst, pdf_stream_dataptr(tmp), pdf_stream_length(tmp), parms); + if (inflateEnd(&z) == Z_OK) { + if (parms) { + dst = filter_stream_decode_Predictor(pdf_stream_dataptr(tmp), pdf_stream_length(tmp), parms); + } else { + dst = pdf_link_obj(tmp); + } + } else { + dst = NULL; + } pdf_release_obj(tmp); - return ((!error && inflateEnd(&z) == Z_OK) ? 0 : -1); + return dst; } #endif -int -pdf_concat_stream (pdf_obj *dst, pdf_obj *src) +static pdf_obj * +filter_stream_decode_ASCIIHexDecode (const void *data, size_t len) +{ + pdf_obj *dst; + int eod, error; + const char *p = (const char *) data; + const char *endptr = p + len; + unsigned char *buf, ch; + size_t pos, n; + + buf = NEW((len+1)/2, unsigned char); + skip_white(&p, endptr); + ch = 0; n = 0; pos = 0; eod = 0; error = 0; + while (p < endptr && !error && !eod) { + char c1, val; + c1 = p[0]; + if (c1 >= 'A' && c1 <= 'F') { + val = c1 - 'A' + 10; + } else if (c1 >= 'a' && c1 <= 'f') { + val = c1 - 'a' + 10; + } else if (c1 >= '0' && c1 <= '9') { + val = c1 - '0'; + } else if (c1 == '>') { + val = 0; + eod = 1; + if ((pos % 2) == 0) + break; + } else { + error = -1; + break; + } + if (pos % 2) { + buf[n] = ch + val; + n++; + ch = 0; + } else { + ch = val << 4; + } + pos++; p++; + skip_white(&p, endptr); + } + if (error || !eod) { + dpx_warning("Invalid ASCIIHex data seen: %s", error ? "Invalid character" : "No EOD marker"); + dst = NULL; + } else { + dst = pdf_new_stream(0); + pdf_add_stream(dst, buf, n); + } + free(buf); + + return dst; +} + +/* Percent sign is not start of comment here. + * We need this for reading Ascii85 encoded data. + */ +#define is_space(c) ((c) == ' ' || (c) == '\t' || (c) == '\f' || \ + (c) == '\r' || (c) == '\n' || (c) == '\0') +static void +skip_white_a85 (const char **p, const char *endptr) { + while (*p < endptr && (is_space(**p))) { + (*p)++; + } +} + +static pdf_obj * +filter_stream_decode_ASCII85Decode (const void *data, size_t len) +{ + pdf_obj *dst; + int eod, error; + const char *p = (const char *) data; + const char *endptr = p + len; + unsigned char *buf; + size_t n; + + buf = NEW(((len+4)/5)*4, unsigned char); + skip_white_a85(&p, endptr); + n = 0; eod = 0; error = 0; + while (p < endptr && !error && !eod) { + char q[5] = {'u', 'u', 'u', 'u', 'u'}; + int m; + char ch; + + ch = p[0]; + p++; + skip_white_a85(&p, endptr); + if (ch == 'z') { + memset(buf+n, 0, 4); + n += 4; + continue; + } else if (ch == '~') { + if (p < endptr && p[0] == '>') { + eod = 1; + p++; + } else { + error = -1; + } + break; + } + q[0] = ch; + for (m = 1; m < 5 && p < endptr; m++) { + ch = p[0]; + p++; + skip_white_a85(&p, endptr); + if (ch == '~') { + if (p < endptr && p[0] == '>') { + eod = 1; + p++; + } else { + error = -1; + } + break; + } else if (ch < '!' || ch > 'u') { + error = -1; + break; + } else { + q[m] = ch; + } + } + if (!error) { + uint32_t val = 0; + int i; + if (m <= 1) { + error = -1; + break; + } + val = 85*85*85*(q[0] - '!') + 85*85*(q[1] - '!') + + 85*(q[2] - '!') + (q[3] - '!'); + /* Check overflow */ + if (val > UINT32_MAX / 85) { + error = -1; + break; + } else { + val = 85 * val; + if (val > UINT32_MAX - (q[4] - '!')) { + error = -1; + break; + } + val += (q[4] - '!'); + } + if (!error) { + for (i = 3; i >= 0; i--) { + buf[n + i] = val & 0xff; + val /= 256; + } + n += m - 1; + } + } + } + + if (error) { + dpx_warning("Error in reading ASCII85 data."); + } else if (!eod) { + dpx_warning("Error in reading ASCII85 data: No EOD"); + dst = NULL; + } else { + dst = pdf_new_stream(0); + pdf_add_stream(dst, buf, n); + } + free(buf); + + return dst; +} + +static pdf_obj * +filter_stream_decode (const char *filter_name, pdf_obj *src, pdf_obj *parm) +{ + pdf_obj *dec; const char *stream_data; - int stream_length; - pdf_obj *stream_dict; - pdf_obj *filter; - int error = 0; + size_t stream_length; - if (!PDF_OBJ_STREAMTYPE(dst) || !PDF_OBJ_STREAMTYPE(src)) - _tt_abort("Invalid type."); + if (!filter_name) + return pdf_link_obj(src); stream_data = pdf_stream_dataptr(src); - stream_length = pdf_stream_length (src); - stream_dict = pdf_stream_dict (src); + stream_length = pdf_stream_length(src); - filter = pdf_lookup_dict(stream_dict, "Filter"); - if (!filter) { - pdf_add_stream(dst, stream_data, stream_length); - } + if (!strcmp(filter_name, "ASCIIHexDecode")) { + dec = filter_stream_decode_ASCIIHexDecode(stream_data, stream_length); + } else if (!strcmp(filter_name, "ASCII85Decode")) { + dec = filter_stream_decode_ASCII85Decode(stream_data, stream_length); #if HAVE_ZLIB - else { - struct decode_parms parms; - int have_parms = 0; + } else if (!strcmp(filter_name, "FlateDecode")) { + struct decode_parms decode_parm; + if (parm) + filter_get_DecodeParms_FlateDecode(&decode_parm, parm); + dec = filter_stream_decode_FlateDecode(stream_data, stream_length, parm ? &decode_parm : NULL); +#endif /* HAVE_ZLIB */ + } else { + dpx_warning("DecodeFilter \"%s\" not supported.", filter_name); + dec = NULL; + } - if (pdf_lookup_dict(stream_dict, "DecodeParms")) { - pdf_obj *tmp; + return dec; +} - /* Dictionary or array */ - tmp = pdf_deref_obj(pdf_lookup_dict(stream_dict, "DecodeParms")); - if (PDF_OBJ_ARRAYTYPE(tmp)) { - if (pdf_array_length(tmp) > 1) { - dpx_warning("Unexpected size for DecodeParms array."); - return -1; - } - tmp = pdf_deref_obj(pdf_get_array(tmp, 0)); - } - if (!PDF_OBJ_DICTTYPE(tmp)) { - dpx_warning("PDF dict expected for DecodeParms..."); - return -1; - } - error = get_decode_parms(&parms, tmp); - if (error) - _tt_abort("Invalid value(s) in DecodeParms dictionary."); - have_parms = 1; - } - if (PDF_OBJ_ARRAYTYPE(filter)) { - if (pdf_array_length(filter) > 1) { - dpx_warning("Multiple DecodeFilter not supported."); - return -1; - } - filter = pdf_get_array(filter, 0); - } - if (PDF_OBJ_NAMETYPE(filter)) { - char *filter_name = pdf_name_value(filter); - if (streq_ptr(filter_name, "FlateDecode")) { - if (have_parms) - error = pdf_add_stream_flate_filtered(dst, stream_data, stream_length, &parms); - else - error = pdf_add_stream_flate(dst, stream_data, stream_length); - } else { - dpx_warning("DecodeFilter \"%s\" not supported.", filter_name); - error = -1; - } - } else - _tt_abort("Broken PDF file?"); - } -#endif /* HAVE_ZLIB */ +int +pdf_concat_stream (pdf_obj *dst, pdf_obj *src) +{ + pdf_obj *filtered; + pdf_obj *stream_dict; + pdf_obj *filter, *parms; + int error = 0; - return error; + if (!PDF_OBJ_STREAMTYPE(dst) || !PDF_OBJ_STREAMTYPE(src)) { + dpx_warning("Passed invalid type in pdf_concat_stream()."); + return -1; + } + + stream_dict = pdf_stream_dict(src); + + filter = pdf_lookup_dict(stream_dict, "Filter"); + if (!filter) { + pdf_add_stream(dst, pdf_stream_dataptr(src), pdf_stream_length(src)); + return 0; + } + if (pdf_lookup_dict(stream_dict, "DecodeParms")) { + /* Dictionary or array */ + parms = pdf_deref_obj(pdf_lookup_dict(stream_dict, "DecodeParms")); + if (!parms) { + dpx_warning("Failed to deref DeocdeParms..."); + return -1; + } else if (!PDF_OBJ_ARRAYTYPE(parms) && !PDF_OBJ_DICTTYPE(parms)) { + dpx_warning("PDF dict or array expected for DecodeParms..."); + pdf_release_obj(parms); + return -1; + } + } else { + parms = NULL; + } + if (PDF_OBJ_ARRAYTYPE(filter)) { + int i, num; + pdf_obj *prev = NULL; + + num = pdf_array_length(filter); + if (parms) { + if (!PDF_OBJ_ARRAYTYPE(parms) || pdf_array_length(parms) != num) { + dpx_warning("Invalid DecodeParam object found."); + pdf_release_obj(parms); + return -1; + } + } + if (num == 0) { + filtered = pdf_link_obj(src); + } else { + filtered = NULL; + prev = pdf_link_obj(src); + for (i = 0; i < num && prev != NULL; i++) { + pdf_obj *tmp1, *tmp2; + + tmp1 = pdf_deref_obj(pdf_get_array(filter, i)); + if (parms) { + tmp2 = pdf_deref_obj(pdf_get_array(parms, i)); + } else { + tmp2 = NULL; + } + if (PDF_OBJ_NAMETYPE(tmp1)) { + filtered = filter_stream_decode(pdf_name_value(tmp1), prev, tmp2); + } else if (PDF_OBJ_NULLTYPE(tmp1)) { + filtered = pdf_link_obj(prev); + } else { + dpx_warning("Unexpected object found for /Filter..."); + filtered = NULL; + } + if (prev) + pdf_release_obj(prev); + if (tmp1) + pdf_release_obj(tmp1); + if (tmp2) + pdf_release_obj(tmp2); + prev = filtered; + } + } + } else if (PDF_OBJ_NAMETYPE(filter)) { + filtered = filter_stream_decode(pdf_name_value(filter), src, parms); + } else { + dpx_warning("Invalid value for /Filter found."); + filtered = NULL; + } + if (parms) + pdf_release_obj(parms); + if (filtered) { + pdf_add_stream(dst, pdf_stream_dataptr(filtered), pdf_stream_length(filtered)); + pdf_release_obj(filtered); + error = 0; + } else { + error = -1; + } + + return error; } static pdf_obj * @@ -3405,11 +3607,9 @@ parse_xref_stream (pdf_file *pf, int xref_pos, pdf_obj **trailer) while (i < index_len) { pdf_obj *first = pdf_get_array(index_obj, i++); size_obj = pdf_get_array(index_obj, i++); - if (!PDF_OBJ_NUMBERTYPE(first) || - !PDF_OBJ_NUMBERTYPE(size_obj) || + if (!PDF_OBJ_NUMBERTYPE(first) || !PDF_OBJ_NUMBERTYPE(size_obj) || parse_xrefstm_subsec(pf, &p, &length, W, wsum, - (int) pdf_number_value(first), - (int) pdf_number_value(size_obj))) + (int) pdf_number_value(first), (int) pdf_number_value(size_obj))) goto error; } } else if (parse_xrefstm_subsec(pf, &p, &length, W, wsum, 0, size)) @@ -3548,7 +3748,7 @@ pdf_files_init (void) ht_init_table(pdf_files, (void (*)(void *)) pdf_file_free); } -unsigned int +int pdf_file_get_version (pdf_file *pf) { assert(pf); @@ -3562,6 +3762,10 @@ pdf_file_get_trailer (pdf_file *pf) return pdf_link_obj(pf->trailer); } +/* FIXME: + * pdf_file_get_trailer() does pdf_link_obj() but + * pdf_file_get_catalog() does not. Why? + */ pdf_obj * pdf_file_get_catalog (pdf_file *pf) { @@ -3583,16 +3787,15 @@ pdf_open (const char *ident, rust_input_handle_t handle) pf->handle = handle; } else { pdf_obj *new_version; - unsigned int version = 0; - int r = parse_pdf_version(handle, &version); - - if (r < 0 || version < 1 || version > pdf_version) { - dpx_warning("pdf_open: Not a PDF 1.[1-%u] file.", pdf_version); -/* - Try to embed the PDF image, even if the PDF version is newer than - the setting. - return NULL; -*/ + int version = check_for_pdf_version(handle); + + if (version < 10) + dpx_warning("Unrecognized PDF version specified for input PDF file: %d.%d", + pdf_version/10, pdf_version%10); + else if (version > pdf_version) { + dpx_warning("Trying to include PDF file with version (%d.%d), which is " \ + "newer than current output PDF setting (%d.%d).", + version/10, version%10, pdf_version/10, pdf_version%10); } pf = pdf_file_new(handle); @@ -3614,17 +3817,17 @@ pdf_open (const char *ident, rust_input_handle_t handle) new_version = pdf_deref_obj(pdf_lookup_dict(pf->catalog, "Version")); if (new_version) { - unsigned int minor; + unsigned int major, minor; if (!PDF_OBJ_NAMETYPE(new_version) || - sscanf(pdf_name_value(new_version), "1.%u", &minor) != 1) { + sscanf(pdf_name_value(new_version), "%u.%u", &major, &minor) != 2) { pdf_release_obj(new_version); dpx_warning("Illegal Version entry in document catalog. Broken PDF file?"); goto error; } - if (pf->version < minor) - pf->version = minor; + if (pf->version < major*10+minor) + pf->version = major*10+minor; pdf_release_obj(new_version); } @@ -3656,37 +3859,33 @@ pdf_files_close (void) } static int -parse_pdf_version (rust_input_handle_t handle, unsigned int *ret_version) +check_for_pdf_version (rust_input_handle_t handle) { char buffer[10] = "\0\0\0\0\0\0\0\0\0"; - unsigned int minor; + unsigned int major, minor; ttstub_input_seek(handle, 0, SEEK_SET); if (ttstub_input_read(handle, buffer, sizeof(buffer) - 1) != sizeof(buffer) - 1) return -1; - if (sscanf(buffer, "%%PDF-1.%u", &minor) != 1) + if (sscanf(buffer, "%%PDF-%u.%u", &major, &minor) != 2) return -1; - *ret_version = minor; - - return 0; + return major*10+minor; } int check_for_pdf (rust_input_handle_t handle) { - int r; - unsigned int version; + int version; - r = parse_pdf_version(handle, &version); - if (r < 0) /* not a PDF file */ + version = check_for_pdf_version(handle); + if (version < 0) /* not a PDF file */ return 0; if (version <= pdf_version) return 1; - dpx_warning("Version of PDF file (1.%d) is newer than version limit specification.", version); return 1; } @@ -3707,15 +3906,12 @@ import_dict (pdf_obj *key, pdf_obj *value, void *pdata) return 0; } -static pdf_obj loop_marker = { PDF_OBJ_INVALID, 0, 0, 0, 0, NULL }; - static pdf_obj * pdf_import_indirect (pdf_obj *object) { pdf_file *pf = OBJ_FILE(object); unsigned int obj_num = OBJ_NUM(object); unsigned short obj_gen = OBJ_GEN(object); - pdf_obj *ref; assert(pf); @@ -3725,12 +3921,9 @@ pdf_import_indirect (pdf_obj *object) return pdf_new_null(); } - if ((ref = pf->xref_table[obj_num].indirect)) { - if (ref == &loop_marker) - _tt_abort("Loop in object hierarchy detected. Broken PDF file?"); - return pdf_link_obj(ref); - } else { - pdf_obj *obj, *tmp; + ref = pf->xref_table[obj_num].indirect; + if (!ref) { + pdf_obj *obj, *reserved, *imported; obj = pdf_get_object(pf, obj_num, obj_gen); if (!obj) { @@ -3738,18 +3931,35 @@ pdf_import_indirect (pdf_obj *object) return NULL; } - /* We mark the reference to be able to detect loops */ - pf->xref_table[obj_num].indirect = &loop_marker; - - tmp = pdf_import_object(obj); - - pf->xref_table[obj_num].indirect = ref = pdf_ref_obj(tmp); + /* Fix for circular reference issue + * + * Older version of dvipdfmx disallowed the following case of + * circular reference: + * obj #1 --> << /Kids [2 0 R] >> + * obj #2 --> << /Parents [1 0 R] >> + * The problem is in that dvipdfmx gives new labels to objects after they + * are completely read. + */ + reserved = pdf_new_null(); /* for reservation of label */ + pf->xref_table[obj_num].indirect = ref = pdf_new_ref(reserved); + imported = pdf_import_object(obj); + if (imported) { + if (imported->label) { + dpx_warning("Imported object already has a label: obj_id=%u", imported->label); + } + OBJ_OBJ(ref) = imported; + imported->label = reserved->label; + imported->generation = reserved->generation; + reserved->label = 0; + reserved->generation = 0; + pdf_release_obj(imported); + } - pdf_release_obj(tmp); + pdf_release_obj(reserved); pdf_release_obj(obj); - - return pdf_link_obj(ref); } + + return pdf_link_obj(ref); } /* diff --git a/tectonic/dpx-pdfobj.h b/tectonic/dpx-pdfobj.h index 7af4b112a7..88ba29d940 100644 --- a/tectonic/dpx-pdfobj.h +++ b/tectonic/dpx-pdfobj.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -59,17 +59,17 @@ typedef struct pdf_obj pdf_obj; typedef struct pdf_file pdf_file; /* External interface to pdf routines */ - -int pdf_obj_get_verbose (void); -void pdf_obj_set_verbose (int level); void pdf_obj_reset_global_state (void); void pdf_error_cleanup (void); void pdf_out_init (const char *filename, - bool enable_encrypt, bool enable_object_stream); + bool enable_encrypt, bool enable_objstm, + bool enable_predictor); void pdf_out_flush (void); -void pdf_set_version (unsigned version); -unsigned int pdf_get_version (void); +void pdf_set_version (int version); +int pdf_get_version (void); +int pdf_get_version_major (void); +int pdf_get_version_minor (void); void pdf_release_obj (pdf_obj *object); int pdf_obj_typeof (pdf_obj *object); @@ -148,11 +148,6 @@ pdf_obj *pdf_new_stream (int flags); void pdf_add_stream (pdf_obj *stream, const void *stream_data_ptr, int stream_data_len); -#if HAVE_ZLIB -int pdf_add_stream_flate (pdf_obj *stream, - const void *stream_data_ptr, - int stream_data_len); -#endif int pdf_concat_stream (pdf_obj *dst, pdf_obj *src); pdf_obj *pdf_stream_dict (pdf_obj *stream); int pdf_stream_length (pdf_obj *stream); @@ -169,7 +164,6 @@ int pdf_compare_reference (pdf_obj *ref1, pdf_obj *ref2); */ void pdf_set_compression (int level); -void pdf_set_use_predictor (int bval); void pdf_set_info (pdf_obj *obj); void pdf_set_root (pdf_obj *obj); @@ -182,8 +176,8 @@ int check_for_pdf (rust_input_handle_t handle); pdf_file *pdf_open (const char *ident, rust_input_handle_t handle); void pdf_close (pdf_file *pf); pdf_obj *pdf_file_get_trailer (pdf_file *pf); -unsigned int pdf_file_get_version (pdf_file *pf); pdf_obj *pdf_file_get_catalog (pdf_file *pf); +int pdf_file_get_version (pdf_file *pf); pdf_obj *pdf_deref_obj (pdf_obj *object); pdf_obj *pdf_import_object (pdf_obj *object); @@ -192,5 +186,6 @@ size_t pdfobj_escape_str (char *buffer, size_t size, const unsigned char *s, siz pdf_obj *pdf_new_indirect (pdf_file *pf, unsigned label, unsigned short generation); +int pdf_check_version (int major, int minor); #endif /* _PDFOBJ_H_ */ diff --git a/tectonic/dpx-pdfximage.c b/tectonic/dpx-pdfximage.c index 4ea807dee3..d87dc26eb3 100644 --- a/tectonic/dpx-pdfximage.c +++ b/tectonic/dpx-pdfximage.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -30,6 +30,7 @@ #include "core-bridge.h" #include "dpx-bmpimage.h" +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" #include "dpx-dpxutil.h" #include "dpx-epdf.h" @@ -87,19 +88,13 @@ struct pdf_ximage_ /* verbose, verbose, verbose... */ struct opt_ { - int verbose; char *cmdtmpl; }; static struct opt_ _opts = { - 0, NULL + NULL }; -void pdf_ximage_set_verbose (int level) { - _opts.verbose = level; -} - - struct ic_ { int count, capacity; @@ -172,7 +167,7 @@ pdf_close_images (void) * We also use this to convert a PS file only once if multiple * pages are imported from that file. */ - if (_opts.verbose > 1 && keep_cache != 1) + if (dpx_conf.verbose_level > 1 && dpx_conf.file.keep_cache != 1) dpx_message("pdf_image>> deleting temporary file \"%s\"\n", I->filename); dpx_delete_temp_file(I->filename, false); /* temporary filename freed here */ I->filename = NULL; @@ -247,14 +242,14 @@ load_image (const char *ident, const char *fullname, int format, rust_input_hand switch (format) { case IMAGE_TYPE_JPEG: - if (_opts.verbose) + if (dpx_conf.verbose_level > 0) dpx_message("[JPEG]"); if (jpeg_include_image(I, handle) < 0) goto error; I->subtype = PDF_XOBJECT_TYPE_IMAGE; break; case IMAGE_TYPE_JP2: - if (_opts.verbose) + if (dpx_conf.verbose_level > 0) dpx_message("[JP2]"); /*if (jp2_include_image(I, fp) < 0)*/ dpx_warning("Tectonic: JP2 not yet supported"); @@ -262,21 +257,21 @@ load_image (const char *ident, const char *fullname, int format, rust_input_hand /*I->subtype = PDF_XOBJECT_TYPE_IMAGE; break;*/ case IMAGE_TYPE_PNG: - if (_opts.verbose) + if (dpx_conf.verbose_level > 0) dpx_message("[PNG]"); if (png_include_image(I, handle) < 0) goto error; I->subtype = PDF_XOBJECT_TYPE_IMAGE; break; case IMAGE_TYPE_BMP: - if (_opts.verbose) + if (dpx_conf.verbose_level > 0) dpx_message("[BMP]"); if (bmp_include_image(I, handle) < 0) goto error; I->subtype = PDF_XOBJECT_TYPE_IMAGE; break; case IMAGE_TYPE_PDF: - if (_opts.verbose) + if (dpx_conf.verbose_level > 0) dpx_message("[PDF]"); { int result = pdf_include_page(I, handle, fullname, options); @@ -284,18 +279,18 @@ load_image (const char *ident, const char *fullname, int format, rust_input_hand if (result != 0) goto error; } - if (_opts.verbose) + if (dpx_conf.verbose_level > 0) dpx_message(",Page:%d", I->attr.page_no); I->subtype = PDF_XOBJECT_TYPE_FORM; break; case IMAGE_TYPE_EPS: - if (_opts.verbose) + if (dpx_conf.verbose_level > 0) dpx_message("[EPS]"); dpx_warning("sorry, PostScript images are not supported by Tectonic"); dpx_warning("for details, please see https://github.com/tectonic-typesetting/tectonic/issues/27"); goto error; default: - if (_opts.verbose) + if (dpx_conf.verbose_level > 0) dpx_message("[UNKNOWN]"); /* Tectonic: this used to try ps_include_page() */ goto error; @@ -320,7 +315,6 @@ load_image (const char *ident, const char *fullname, int format, rust_input_hand return -1; } - int pdf_ximage_findresource (const char *ident, load_options options) { @@ -361,7 +355,7 @@ pdf_ximage_findresource (const char *ident, load_options options) return -1; } - if (_opts.verbose) + if (dpx_conf.verbose_level > 0) dpx_message("(Image:%s", ident); format = source_image_type(handle); @@ -369,7 +363,7 @@ pdf_ximage_findresource (const char *ident, load_options options) ttstub_input_close(handle); - if (_opts.verbose) + if (dpx_conf.verbose_level > 0) dpx_message(")"); if (id < 0) @@ -496,7 +490,7 @@ pdf_ximage_set_form (pdf_ximage *I, void *form_info, pdf_obj *resource) */ p1.x = info->bbox.llx; p1.y = info->bbox.lly; pdf_dev_transform(&p1, &info->matrix); - p2.x = info->bbox.urx; p1.y = info->bbox.lly; + p2.x = info->bbox.urx; p2.y = info->bbox.lly; pdf_dev_transform(&p2, &info->matrix); p3.x = info->bbox.urx; p3.y = info->bbox.ury; pdf_dev_transform(&p3, &info->matrix); diff --git a/tectonic/dpx-pdfximage.h b/tectonic/dpx-pdfximage.h index 92719067fb..8a0e01dedd 100644 --- a/tectonic/dpx-pdfximage.h +++ b/tectonic/dpx-pdfximage.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -24,7 +24,7 @@ #define _PDFXIMAGE_H_ #include "dpx-core.h" - +#include "dpx-pdfdoc.h" #include "dpx-pdfdev.h" #include "dpx-pdfobj.h" @@ -54,14 +54,12 @@ typedef struct { typedef struct { int page_no; - int bbox_type; + enum pdf_page_boundary bbox_type; pdf_obj *dict; } load_options; typedef struct pdf_ximage_ pdf_ximage; -void pdf_ximage_set_verbose (int level); - void pdf_init_images (void); void pdf_close_images (void); diff --git a/tectonic/dpx-pkfont.c b/tectonic/dpx-pkfont.c index 11b30afb16..5cd79f1bd1 100644 --- a/tectonic/dpx-pkfont.c +++ b/tectonic/dpx-pkfont.c @@ -84,17 +84,10 @@ truedpi (const char *ident, double point_size, unsigned int bdpi) static FILE * dpx_open_pk_font_at (const char *ident, unsigned int dpi) { - FILE *fp; - char *fqpn; /*kpse_glyph_file_type kpse_file_info;*/ - - fqpn = NULL; /*kpse_find_glyph(ident, dpi, kpse_pk_format, &kpse_file_info);*/ - if (!fqpn) - return NULL; - fp = fopen(fqpn, FOPEN_RBIN_MODE); - free(fqpn); - - return fp; + /*char * fqpn = kpse_find_glyph(ident, dpi, kpse_pk_format, &kpse_file_info);*/ + dpx_warning("Tectonic unable to generate PK font \"%s\" (dpi %u) on-the-fly", ident, dpi); + return NULL; } diff --git a/tectonic/dpx-pngimage.c b/tectonic/dpx-pngimage.c index f598d4cd8c..9b037b9cbe 100644 --- a/tectonic/dpx-pngimage.c +++ b/tectonic/dpx-pngimage.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -32,6 +32,7 @@ * */ +#include "dpx-dpxconf.h" #include "dpx-error.h" #include "dpx-mem.h" #include "dpx-numbers.h" @@ -202,7 +203,7 @@ png_include_image (pdf_ximage *ximage, rust_input_handle_t handle) bpc = png_get_bit_depth (png_ptr, png_info_ptr); if (bpc > 8) { - if (pdf_get_version() < 5) { + if (pdf_check_version(1, 5) < 0) { /* Ask libpng to convert down to 8-bpc. */ dpx_warning("%s: 16-bpc PNG requires PDF version 1.5.", PNG_DEBUG_STR); png_set_strip_16(png_ptr); @@ -372,7 +373,7 @@ png_include_image (pdf_ximage *ximage, rust_input_handle_t handle) * flag of iTxt chunks. */ #if PNG_LIBPNG_VER >= 10614 - if (pdf_get_version() >= 4) { + if (pdf_check_version(1, 4) >= 0) { png_textp text_ptr; pdf_obj *XMP_stream, *XMP_stream_dict; int i, num_text; @@ -456,13 +457,11 @@ static int check_transparency (png_structp png_ptr, png_infop info_ptr) { int trans_type; - unsigned int pdf_version; png_byte color_type; png_color_16p trans_values; png_bytep trans; int num_trans; - pdf_version = pdf_get_version(); color_type = png_get_color_type(png_ptr, info_ptr); /* @@ -504,8 +503,8 @@ check_transparency (png_structp png_ptr, png_infop info_ptr) * We can convert alpha cahnnels to explicit mask via user supplied alpha- * threshold value. But I will not do that. */ - if (( pdf_version < 3 && trans_type != PDF_TRANS_TYPE_NONE ) || - ( pdf_version < 4 && trans_type == PDF_TRANS_TYPE_ALPHA )) { + if (( pdf_check_version(1, 3) < 0 && trans_type != PDF_TRANS_TYPE_NONE ) || + ( pdf_check_version(1, 4) < 0 && trans_type == PDF_TRANS_TYPE_ALPHA )) { /* * No transparency supported but PNG uses transparency, or Soft-Mask * required but no support for it is available in this version of PDF. @@ -522,9 +521,9 @@ check_transparency (png_structp png_ptr, png_infop info_ptr) bg.red = 255; bg.green = 255; bg.blue = 255; bg.gray = 255; bg.index = 0; png_set_background(png_ptr, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); dpx_warning("%s: Transparency will be ignored. (no support in PDF ver. < 1.3)", PNG_DEBUG_STR); - if (pdf_version < 3) + if (pdf_check_version(1, 3) < 0) dpx_warning("%s: Please use -V 3 option to enable binary transparency support.", PNG_DEBUG_STR); - if (pdf_version < 4) + if (pdf_check_version(1, 4) < 0) dpx_warning("%s: Please use -V 4 option to enable full alpha channel support.", PNG_DEBUG_STR); trans_type = PDF_TRANS_TYPE_NONE; } @@ -973,12 +972,16 @@ create_soft_mask (png_structp png_ptr, png_infop info_ptr, png_bytep trans; int num_trans; png_uint_32 i; + png_byte bpc, mask, shift; if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) || !png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL)) { dpx_warning("%s: PNG does not have valid tRNS chunk but tRNS is requested.", PNG_DEBUG_STR); return NULL; } + bpc = png_get_bit_depth(png_ptr, info_ptr); + mask = 0xff >> (8 - bpc); + shift = 8 - bpc; smask = pdf_new_stream(STREAM_COMPRESS); dict = pdf_stream_dict(smask); @@ -990,7 +993,8 @@ create_soft_mask (png_structp png_ptr, png_infop info_ptr, pdf_add_dict(dict, pdf_new_name("ColorSpace"), pdf_new_name("DeviceGray")); pdf_add_dict(dict, pdf_new_name("BitsPerComponent"), pdf_new_number(8)); for (i = 0; i < width*height; i++) { - png_byte idx = image_data_ptr[i]; + /* data is packed for 1/2/4 bpc formats, msb first */ + png_byte idx = (image_data_ptr[bpc * i / 8] >> (shift - bpc * i % 8)) & mask; smask_data_ptr[i] = (idx < num_trans) ? trans[idx] : 0xff; } pdf_add_stream(smask, (char *)smask_data_ptr, width*height); diff --git a/tectonic/dpx-spc_dvips.c b/tectonic/dpx-spc_dvips.c index 5f5af717f3..cf65a738f9 100644 --- a/tectonic/dpx-spc_dvips.c +++ b/tectonic/dpx-spc_dvips.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks diff --git a/tectonic/dpx-spc_pdfm.c b/tectonic/dpx-spc_pdfm.c index a6df8e6ff5..5145f36d81 100644 --- a/tectonic/dpx-spc_pdfm.c +++ b/tectonic/dpx-spc_pdfm.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2020 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -29,6 +29,7 @@ #include #include +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" #include "dpx-dpxutil.h" #include "dpx-dvipdfmx.h" @@ -66,13 +67,15 @@ struct spc_pdf_ int lowest_level; /* current min level of outlines */ struct ht_table *resourcemap; /* see remark below (somewhere) */ struct tounicode cd; /* For to-UTF16-BE conversion :( */ + pdf_obj *pageresources; /* Add to all page resource dict */ }; static struct spc_pdf_ _pdf_stat = { NULL, 255, NULL, - { -1, 0, NULL } + { -1, 0, NULL }, + NULL }; /* PLEASE REMOVE THIS */ @@ -139,6 +142,7 @@ spc_handler_pdfm__init (void *dp) pdf_add_array(sd->cd.taintkeys, pdf_new_name(default_taintkeys[i])); } + sd->pageresources = NULL; return 0; } @@ -162,6 +166,9 @@ spc_handler_pdfm__clean (void *dp) pdf_release_obj(sd->cd.taintkeys); sd->cd.taintkeys = NULL; + if (sd->pageresources) + pdf_release_obj(sd->pageresources); + sd->pageresources = NULL; return 0; } @@ -230,10 +237,6 @@ safeputresdent (pdf_obj *kp, pdf_obj *vp, void *dp) return 0; } -#ifndef pdf_obj_isaref -#define pdf_obj_isaref(o) (pdf_obj_typeof((o)) == PDF_INDIRECT) -#endif - static int safeputresdict (pdf_obj *kp, pdf_obj *vp, void *dp) { @@ -245,7 +248,7 @@ safeputresdict (pdf_obj *kp, pdf_obj *vp, void *dp) key = pdf_name_value(kp); dict = pdf_lookup_dict(dp, key); - if (pdf_obj_isaref(vp)) { + if (pdf_obj_typeof(vp) == PDF_INDIRECT) { pdf_add_dict(dp, pdf_new_name(key), pdf_link_obj(vp)); } else if (pdf_obj_typeof(vp) == PDF_DICT) { if (dict) @@ -261,6 +264,94 @@ safeputresdict (pdf_obj *kp, pdf_obj *vp, void *dp) return 0; } +static +int putpageresources (pdf_obj *kp, pdf_obj *vp, void *dp) +{ + char *resource_name; + + assert(kp && vp); + + resource_name = pdf_name_value(kp); + pdf_doc_add_page_resource(dp, resource_name, pdf_link_obj(vp)); + + return 0; +} + +static +int forallresourcecategory (pdf_obj *kp, pdf_obj *vp, void *dp) +{ + int r = -1; + char *category; + + assert(kp && vp); + + category = pdf_name_value(kp); + switch (pdf_obj_typeof(vp)) { + case PDF_DICT: + r = pdf_foreach_dict(vp, putpageresources, category); + break; + case PDF_INDIRECT: + { + /* In case pdf:pageresouces << /Category @res >> */ + pdf_obj *obj; + obj = pdf_deref_obj(vp); + if (!obj) { + dpx_warning("Can't deref object for page resource: %s", category); + r = -1; + } else if (pdf_obj_typeof(obj) != PDF_DICT) { + dpx_warning("Invalid object type for page resource: %s", category); + r = -1; + } else { + pdf_obj *res_dict, *dict; + + res_dict = pdf_doc_current_page_resources(); + dict = pdf_lookup_dict(res_dict, category); + if (!dict) { + pdf_add_dict(res_dict, pdf_new_name(category), pdf_link_obj(vp)); + } else { + if (pdf_obj_typeof(dict) == PDF_INDIRECT) { + dict = pdf_deref_obj(dict); + pdf_release_obj(dict); /* FIXME: jus to decrement link counter */ + } +#if 1 + /* This will leave garbage (object "res") since object "res" + * supplied as resource dictionary will have label but we copy the + * content of res here and never use reference to it. + */ + pdf_foreach_dict(obj, safeputresdent, dict); +#else + /* With the below code resource dictionary is replaced by user + * supplied one, @res. However, there is a problem that all + * resources including internally generated one may go into single + * dictionary referenced by @res, and will be visible from any + * subsequent pages. + */ + pdf_foreach_dict(dict, safeputresdent, obj); + pdf_add_dict(res_dict, pdf_new_name(category), pdf_link_obj(vp)); +#endif + } + pdf_release_obj(obj); + } + } + break; + default: + dpx_warning("Invalid object type for page resource specified for \"%s\"", category); + } + + return r; +} + +int +spc_pdfm_at_end_page (void) +{ + struct spc_pdf_ *sd = &_pdf_stat; + + if (sd->pageresources) { + pdf_foreach_dict(sd->pageresources, forallresourcecategory, NULL); + } + + return 0; +} /* Think what happens if you do * @@ -492,7 +583,7 @@ modstrings (pdf_obj *kp, pdf_obj *vp, void *dp) CMap *cmap = CMap_cache_get(cd->cmap_id); if (needreencode(kp, vp, cd)) r = reencodestring(cmap, vp); - } else if (is_xdv && cd && cd->taintkeys) { + } else if ((dpx_conf.compat_mode == dpx_mode_xdv_mode) && cd && cd->taintkeys) { /* Please fix this... PDF string object is not always a text string. * needreencode() is assumed to do a simple check if given string * object is actually a text string. @@ -520,7 +611,7 @@ parse_pdf_dict_with_tounicode (const char **pp, const char *endptr, struct touni pdf_obj *dict; /* disable this test for XDV files, as we do UTF8 reencoding with no cmap */ - if (!is_xdv && cd->cmap_id < 0) + if ((dpx_conf.compat_mode != dpx_mode_xdv_mode) && cd->cmap_id < 0) return parse_pdf_dict(pp, endptr, NULL); /* :( */ @@ -535,6 +626,7 @@ parse_pdf_dict_with_tounicode (const char **pp, const char *endptr, struct touni return dict; } +#define SPC_PDFM_SUPPORT_ANNOT_TRANS 1 static int spc_handler_pdfm_annot (struct spc_env *spe, struct spc_arg *args) { @@ -542,7 +634,6 @@ spc_handler_pdfm_annot (struct spc_env *spe, struct spc_arg *args) pdf_obj *annot_dict; pdf_rect rect; char *ident = NULL; - pdf_coord cp; transform_info ti; skip_white(&args->curptr, args->endptr); @@ -576,19 +667,96 @@ spc_handler_pdfm_annot (struct spc_env *spe, struct spc_arg *args) return -1; } - cp.x = spe->x_user; cp.y = spe->y_user; - pdf_dev_transform(&cp, NULL); - if (ti.flags & INFO_HAS_USER_BBOX) { - rect.llx = ti.bbox.llx + cp.x; - rect.lly = ti.bbox.lly + cp.y; - rect.urx = ti.bbox.urx + cp.x; - rect.ury = ti.bbox.ury + cp.y; - } else { - rect.llx = cp.x; - rect.lly = cp.y - spe->mag * ti.depth; - rect.urx = cp.x + spe->mag * ti.width; - rect.ury = cp.y + spe->mag * ti.height; +#ifdef SPC_PDFM_SUPPORT_ANNOT_TRANS + { + pdf_coord cp1, cp2, cp3, cp4; + /* QuadPoints not working? */ +#ifdef USE_QUADPOINTS + pdf_obj *qpoints; +#endif + if (ti.flags & INFO_HAS_USER_BBOX) { + cp1.x = spe->x_user + ti.bbox.llx; + cp1.y = spe->y_user + ti.bbox.lly; + cp2.x = spe->x_user + ti.bbox.urx; + cp2.y = spe->y_user + ti.bbox.lly; + cp3.x = spe->x_user + ti.bbox.urx; + cp3.y = spe->y_user + ti.bbox.ury; + cp4.x = spe->x_user + ti.bbox.llx; + cp4.y = spe->y_user + ti.bbox.ury; + } else { + cp1.x = spe->x_user; + cp1.y = spe->y_user - spe->mag * ti.depth; + cp2.x = spe->x_user + spe->mag * ti.width; + cp2.y = spe->y_user - spe->mag * ti.depth; + cp3.x = spe->x_user + spe->mag * ti.width; + cp3.y = spe->y_user + spe->mag * ti.height; + cp4.x = spe->x_user; + cp4.y = spe->y_user + spe->mag * ti.height; + } + pdf_dev_transform(&cp1, NULL); + pdf_dev_transform(&cp2, NULL); + pdf_dev_transform(&cp3, NULL); + pdf_dev_transform(&cp4, NULL); + rect.llx = cp1.x; + if (cp2.x < rect.llx) + rect.llx = cp2.x; + if (cp3.x < rect.llx) + rect.llx = cp3.x; + if (cp4.x < rect.llx) + rect.llx = cp4.x; + rect.urx = cp1.x; + if (cp2.x > rect.urx) + rect.urx = cp2.x; + if (cp3.x > rect.urx) + rect.urx = cp3.x; + if (cp4.x > rect.urx) + rect.urx = cp4.x; + rect.lly = cp1.y; + if (cp2.y < rect.lly) + rect.lly = cp2.y; + if (cp3.y < rect.lly) + rect.lly = cp3.y; + if (cp4.y < rect.lly) + rect.lly = cp4.y; + rect.ury = cp1.y; + if (cp2.y > rect.ury) + rect.ury = cp2.y; + if (cp3.y > rect.ury) + rect.ury = cp3.y; + if (cp4.y > rect.ury) + rect.ury = cp4.y; +#ifdef USE_QUADPOINTS + qpoints = pdf_new_array(); + pdf_add_array(qpoints, pdf_new_number(ROUND(cp1.x, 0.01))); + pdf_add_array(qpoints, pdf_new_number(ROUND(cp1.y, 0.01))); + pdf_add_array(qpoints, pdf_new_number(ROUND(cp2.x, 0.01))); + pdf_add_array(qpoints, pdf_new_number(ROUND(cp2.y, 0.01))); + pdf_add_array(qpoints, pdf_new_number(ROUND(cp3.x, 0.01))); + pdf_add_array(qpoints, pdf_new_number(ROUND(cp3.y, 0.01))); + pdf_add_array(qpoints, pdf_new_number(ROUND(cp4.x, 0.01))); + pdf_add_array(qpoints, pdf_new_number(ROUND(cp4.y, 0.01))); + pdf_add_dict(annot_dict, pdf_new_name("QuadPoints"), qpoints); +#endif + } +#else + { + pdf_coord cp; + + cp.x = spe->x_user; cp.y = spe->y_user; + pdf_dev_transform(&cp, NULL); + if (ti.flags & INFO_HAS_USER_BBOX) { + rect.llx = ti.bbox.llx + cp.x; + rect.lly = ti.bbox.lly + cp.y; + rect.urx = ti.bbox.urx + cp.x; + rect.ury = ti.bbox.ury + cp.y; + } else { + rect.llx = cp.x; + rect.lly = cp.y - spe->mag * ti.depth; + rect.urx = cp.x + spe->mag * ti.width; + rect.ury = cp.y + spe->mag * ti.height; + } } +#endif /* Order is important... */ if (ident) @@ -1407,8 +1575,7 @@ spc_handler_pdfm_stream_with_type (struct spc_env *spe, struct spc_arg *args, in break; case STRING_STREAM: fstream = pdf_new_stream(STREAM_COMPRESS); - if (instring) - pdf_add_stream(fstream, instring, strlen(instring)); + pdf_add_stream(fstream, pdf_string_value(tmp), pdf_string_length(tmp)); break; default: pdf_release_obj(tmp); @@ -1562,7 +1729,8 @@ spc_handler_pdfm_bform (struct spc_env *spe, struct spc_arg *args) static int spc_handler_pdfm_eform (struct spc_env *spe, struct spc_arg *args) { - pdf_obj *attrib = NULL; + pdf_obj *attrib = NULL; + struct spc_pdf_ *sd = &_pdf_stat; skip_white(&args->curptr, args->endptr); @@ -1573,6 +1741,10 @@ spc_handler_pdfm_eform (struct spc_env *spe, struct spc_arg *args) attrib = NULL; } } + /* pageresources here too */ + if (sd->pageresources) { + pdf_foreach_dict(sd->pageresources, forallresourcecategory, NULL); + } pdf_doc_end_grabbing(attrib); return 0; @@ -1687,15 +1859,17 @@ spc_handler_pdfm_bgcolor (struct spc_env *spe, struct spc_arg *args) return error; } +#define THEBUFFLENGTH 1024 static int spc_handler_pdfm_mapline (struct spc_env *spe, struct spc_arg *ap) { fontmap_rec *mrec; char *map_name, opchr; int error = 0; - static char buffer[1024]; + static char buffer[THEBUFFLENGTH]; const char *p; char *q; + int count; skip_white(&ap->curptr, ap->endptr); if (ap->curptr >= ap->endptr) { @@ -1723,8 +1897,16 @@ spc_handler_pdfm_mapline (struct spc_env *spe, struct spc_arg *ap) default: p = ap->curptr; q = buffer; - while (p < ap->endptr) + count = 0; + while (p < ap->endptr && count < THEBUFFLENGTH - 1) { *q++ = *p++; + count++; + } + if (count == THEBUFFLENGTH - 1) { + spc_warn(spe, "Invalid fontmap line: Too long a line."); + *q = 0; + return -1; + } *q = '\0'; mrec = NEW(1, fontmap_rec); pdf_init_fontmap_record(mrec); @@ -1787,6 +1969,7 @@ spc_handler_pdfm_tounicode (struct spc_env *spe, struct spc_arg *args) { struct spc_pdf_ *sd = &_pdf_stat; char *cmap_name; + pdf_obj *taint_keys; /* First clear */ sd->cd.cmap_id = -1; @@ -1827,9 +2010,70 @@ spc_handler_pdfm_tounicode (struct spc_env *spe, struct spc_arg *args) sd->cd.unescape_backslash = 1; } free(cmap_name); + + /* Additional "taint key" + * An array of PDF name objects can be supplied optionally. + * Dictionary entries specified by this option will be added to the list + * of dictionary keys to be treated as the target of "ToUnicode" conversion. + */ + skip_white(&args->curptr, args->endptr); + if (args->curptr < args->endptr) { + taint_keys = parse_pdf_object(&args->curptr, args->endptr, NULL); + if (taint_keys) { + if (PDF_OBJ_ARRAYTYPE(taint_keys)) { + int i; + for (i = 0; i < pdf_array_length(taint_keys); i++) { + pdf_obj *key; + + key = pdf_get_array(taint_keys, i); + if (PDF_OBJ_NAMETYPE(key)) + pdf_add_array(sd->cd.taintkeys, pdf_link_obj(key)); + else { + spc_warn(spe, "Invalid argument specified in pdf:tounicode special."); + } + } + } else { + spc_warn(spe, "Invalid argument specified in pdf:unicode special."); + } + pdf_release_obj(taint_keys); + } + } + return 0; } +static int +spc_handler_pdfm_pageresources (struct spc_env *spe, struct spc_arg *args) +{ + struct spc_pdf_ *sd = &_pdf_stat; + pdf_obj *dict; + + dict = parse_pdf_object(&args->curptr, args->endptr, NULL); + if (!dict) { + spc_warn(spe, "Dictionary object expected but not found."); + return -1; + } + + if (sd->pageresources) + pdf_release_obj(sd->pageresources); + sd->pageresources = dict; + + return 0; +} + +static int +spc_handler_pdft_compat_page (struct spc_env *spe, struct spc_arg *args) +{ + skip_white(&args->curptr, args->endptr); + if (args->curptr < args->endptr) { + pdf_doc_add_page_content(" ", 1); /* op: */ + pdf_doc_add_page_content(args->curptr, (int) (args->endptr - args->curptr)); /* op: ANY */ + } + + args->curptr = args->endptr; + + return 0; +} static struct spc_handler pdfm_handlers[] = { {"annotation", spc_handler_pdfm_annot}, @@ -1939,7 +2183,20 @@ static struct spc_handler pdfm_handlers[] = { {"code", spc_handler_pdfm_code}, {"minorversion", spc_handler_pdfm_do_nothing}, + {"majorversion", spc_handler_pdfm_do_nothing}, {"encrypt", spc_handler_pdfm_do_nothing}, + + {"pageresources", spc_handler_pdfm_pageresources}, + {"trailerid", spc_handler_pdfm_do_nothing}, +}; + +static struct spc_handler pdft_compat_handlers[] = { + /* Text supplied to "direct" command should go inside of BT/ET block + * but dvipdfmx currently can't be implemented so. + * Here, "direct" is for the moment just an alias of "page". + */ + {"direct", spc_handler_pdft_compat_page}, + {"page", spc_handler_pdft_compat_page}, }; bool @@ -1980,15 +2237,34 @@ spc_pdfm_setup_handler (struct spc_handler *sph, skip_white(&ap->curptr, ap->endptr); q = parse_c_ident(&ap->curptr, ap->endptr); if (q) { - for (i = 0; - i < sizeof(pdfm_handlers) / sizeof(struct spc_handler); i++) { - if (streq_ptr(q, pdfm_handlers[i].key)) { - ap->command = pdfm_handlers[i].key; - sph->key = "pdf:"; - sph->exec = pdfm_handlers[i].exec; - skip_white(&ap->curptr, ap->endptr); - error = 0; - break; + int is_pdft_compat = 0; + if (ap->curptr < ap->endptr) { + if (ap->curptr[0] == ':') { + is_pdft_compat = 1; + ap->curptr++; + } + } + if (is_pdft_compat) { + for (i = 0; i < sizeof(pdft_compat_handlers) / sizeof(struct spc_handler); i++) { + if (!strcmp(q, pdft_compat_handlers[i].key)) { + ap->command = pdft_compat_handlers[i].key; + sph->key = "pdf:"; + sph->exec = pdft_compat_handlers[i].exec; + skip_white(&ap->curptr, ap->endptr); + error = 0; + break; + } + } + } else { + for (i = 0; i < sizeof(pdfm_handlers) / sizeof(struct spc_handler); i++) { + if (!strcmp(q, pdfm_handlers[i].key)) { + ap->command = pdfm_handlers[i].key; + sph->key = "pdf:"; + sph->exec = pdfm_handlers[i].exec; + skip_white(&ap->curptr, ap->endptr); + error = 0; + break; + } } } free(q); diff --git a/tectonic/dpx-spc_pdfm.h b/tectonic/dpx-spc_pdfm.h index 409fdefc2e..2492afb89e 100644 --- a/tectonic/dpx-spc_pdfm.h +++ b/tectonic/dpx-spc_pdfm.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -32,6 +32,8 @@ int spc_pdfm_at_begin_document (void); int spc_pdfm_at_end_document (void); +int spc_pdfm_at_end_page (void); + bool spc_pdfm_check_special (const char *buffer, int size); int spc_pdfm_setup_handler (struct spc_handler *handle, struct spc_env *spe, struct spc_arg *args); diff --git a/tectonic/dpx-spc_tpic.c b/tectonic/dpx-spc_tpic.c index 5a4961baca..96672a01c5 100644 --- a/tectonic/dpx-spc_tpic.c +++ b/tectonic/dpx-spc_tpic.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -175,7 +175,7 @@ set_fillstyle (double g, double a, int f_ais) { pdf_obj *dict; char resname[32]; - char buf[38]; + char buf[256]; int alp, len = 0; if (a > 0.0) { @@ -758,7 +758,8 @@ spc_handler_tpic__init (struct spc_env *spe, void *dp) tp->num_points = 0; tp->max_points = 0; - if (tp->mode.fill != TPIC_MODE__FILL_SOLID && pdf_get_version() < 4) { + if (tp->mode.fill != TPIC_MODE__FILL_SOLID && + pdf_check_version(1, 4) < 0) { spc_warn(spe, "Tpic shading support requires PDF version 1.4."); tp->mode.fill = TPIC_MODE__FILL_SOLID; } @@ -949,7 +950,7 @@ spc_handler_tpic__setopts (struct spc_env *spe, error = pdf_foreach_dict(dict, tpic_filter_getopts, tp); if (!error) { if (tp->mode.fill != TPIC_MODE__FILL_SOLID && - pdf_get_version() < 4) { + pdf_check_version(1, 4) < 0) { spc_warn(spe, "Transparent fill mode requires PDF version 1.4."); tp->mode.fill = TPIC_MODE__FILL_SOLID; } diff --git a/tectonic/dpx-spc_util.c b/tectonic/dpx-spc_util.c index 61c44c269a..84983e4107 100644 --- a/tectonic/dpx-spc_util.c +++ b/tectonic/dpx-spc_util.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -30,6 +30,7 @@ #include "dpx-dpxutil.h" #include "dpx-pdfcolor.h" #include "dpx-pdfdev.h" +#include "dpx-pdfdoc.h" #include "dpx-pdfdraw.h" #include "dpx-pdfparse.h" #include "dpx-specials.h" @@ -716,7 +717,8 @@ spc_util_read_dimtrns (struct spc_env *spe, int spc_util_read_blahblah (struct spc_env *spe, - transform_info *p, int *page_no, int *bbox_type, + transform_info *p, int *page_no, + enum pdf_page_boundary *bbox_type, struct spc_arg *ap) { int has_scale, has_xscale, has_yscale, has_rotate, has_matrix; @@ -862,15 +864,15 @@ spc_util_read_blahblah (struct spc_env *spe, q = parse_c_ident (&ap->curptr, ap->endptr); if (q) { if (bbox_type) { - if (strcasecmp(q, "cropbox") == 0) *bbox_type = 1; - else if (strcasecmp(q, "mediabox") == 0) *bbox_type = 2; - else if (strcasecmp(q, "artbox") == 0) *bbox_type = 3; - else if (strcasecmp(q, "trimbox") == 0) *bbox_type = 4; - else if (strcasecmp(q, "bleedbox") == 0) *bbox_type = 5; + if (strcasecmp(q, "cropbox") == 0) *bbox_type = pdf_page_boundary_cropbox; + else if (strcasecmp(q, "mediabox") == 0) *bbox_type = pdf_page_boundary_mediabox; + else if (strcasecmp(q, "artbox") == 0) *bbox_type = pdf_page_boundary_artbox; + else if (strcasecmp(q, "trimbox") == 0) *bbox_type = pdf_page_boundary_trimbox; + else if (strcasecmp(q, "bleedbox") == 0) *bbox_type = pdf_page_boundary_bleedbox; } free(q); } else if (bbox_type) { - *bbox_type = 0; + *bbox_type = pdf_page_boundary__auto; } } break; diff --git a/tectonic/dpx-spc_util.h b/tectonic/dpx-spc_util.h index edf07c9e5a..b6fac9b5ae 100644 --- a/tectonic/dpx-spc_util.h +++ b/tectonic/dpx-spc_util.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -27,6 +27,7 @@ #include "dpx-pdfcolor.h" #include "dpx-pdfdev.h" +#include "dpx-pdfdoc.h" #include "dpx-specials.h" @@ -45,7 +46,7 @@ int spc_util_read_dimtrns (struct spc_env *spe, int spc_util_read_blahblah (struct spc_env *spe, transform_info *dimtrns, int *page_no, - int *bbox_type, + enum pdf_page_boundary *bbox_type, struct spc_arg *args); diff --git a/tectonic/dpx-spc_xtx.c b/tectonic/dpx-spc_xtx.c index 867d185d55..550ab40950 100644 --- a/tectonic/dpx-spc_xtx.c +++ b/tectonic/dpx-spc_xtx.c @@ -1,7 +1,7 @@ /* This is xdvipdfmx, an extended version of dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2013-2016 by the dvipdfmx project team. + Copyright (C) 2013-2019 by the dvipdfmx project team. Copyright (c) 2006 SIL International Originally written by Jonathan Kew @@ -185,15 +185,17 @@ spc_handler_xtx_backgroundcolor (struct spc_env *spe, struct spc_arg *args) } /* FIXME: xdv2pdf's x:fontmapline and x:fontmapfile may have slightly different syntax/semantics */ +#define THEBUFFLENGTH 1024 static int spc_handler_xtx_fontmapline (struct spc_env *spe, struct spc_arg *ap) { fontmap_rec *mrec; char *map_name, opchr; int error = 0; - static char buffer[1024]; + static char buffer[THEBUFFLENGTH]; const char *p; char *q; + int count; skip_white(&ap->curptr, ap->endptr); if (ap->curptr >= ap->endptr) { @@ -221,8 +223,16 @@ spc_handler_xtx_fontmapline (struct spc_env *spe, struct spc_arg *ap) default: p = ap->curptr; q = buffer; - while (p < ap->endptr) + count = 0; + while (p < ap->endptr && count < THEBUFFLENGTH - 1) { *q++ = *p++; + count++; + } + if (count == THEBUFFLENGTH - 1) { + spc_warn(spe, "Invalid fontmap line: Too long a line."); + *q = 0; + return -1; + } *q = '\0'; mrec = NEW(1, fontmap_rec); pdf_init_fontmap_record(mrec); diff --git a/tectonic/dpx-specials.c b/tectonic/dpx-specials.c index e99ae3a950..39c2395417 100644 --- a/tectonic/dpx-specials.c +++ b/tectonic/dpx-specials.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -31,6 +31,7 @@ #include #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-dvi.h" #include "dpx-error.h" #include "dpx-numbers.h" @@ -49,14 +50,6 @@ #include "dpx-spc_tpic.h" #include "dpx-spc_xtx.h" -static int verbose = 0; -void -spc_set_verbose (int level) -{ - verbose = level; -} - - void spc_warn (struct spc_env *spe, const char *fmt, ...) { @@ -65,7 +58,7 @@ spc_warn (struct spc_env *spe, const char *fmt, ...) va_start(ap, fmt); - vsprintf(buf, fmt, ap); + vsnprintf(buf, 1024, fmt, ap); dpx_warning("%s", buf); va_end(ap); @@ -168,12 +161,12 @@ spc_lookup_reference (const char *key) switch (k) { /* xpos and ypos must be position in device space here. */ case K_OBJ__XPOS: - cp.x = dvi_dev_xpos(); cp.y = 0.0; + cp.x = dvi_dev_xpos(); cp.y = dvi_dev_ypos(); pdf_dev_transform(&cp, NULL); value = pdf_new_number(ROUND(cp.x, .01)); break; case K_OBJ__YPOS: - cp.x = 0.0; cp.y = dvi_dev_ypos(); + cp.x = dvi_dev_xpos(); cp.y = dvi_dev_ypos(); pdf_dev_transform(&cp, NULL); value = pdf_new_number(ROUND(cp.y, .01)); break; @@ -232,12 +225,12 @@ spc_lookup_object (const char *key) for (k = 0; _rkeys[k] && strcmp(key, _rkeys[k]); k++); switch (k) { case K_OBJ__XPOS: - cp.x = dvi_dev_xpos(); cp.y = 0.0; + cp.x = dvi_dev_xpos(); cp.y = dvi_dev_ypos(); pdf_dev_transform(&cp, NULL); value = pdf_new_number(ROUND(cp.x, .01)); break; case K_OBJ__YPOS: - cp.x = 0.0; cp.y = dvi_dev_ypos(); + cp.x = dvi_dev_xpos(); cp.y = dvi_dev_ypos(); pdf_dev_transform(&cp, NULL); value = pdf_new_number(ROUND(cp.y, .01)); break; @@ -364,7 +357,7 @@ static struct { spc_pdfm_at_begin_document, spc_pdfm_at_end_document, NULL, - NULL, + spc_pdfm_at_end_page, spc_pdfm_check_special, spc_pdfm_setup_handler }, @@ -565,7 +558,8 @@ spc_exec_special (const char *buffer, int32_t size, struct spc_arg args; struct spc_handler special; - if (verbose > 3) { + if (dpx_conf.verbose_level > 3) { + dpx_message("Executing special command: "); dump(buffer, buffer + size); } @@ -589,4 +583,3 @@ spc_exec_special (const char *buffer, int32_t size, return error; } - diff --git a/tectonic/dpx-specials.h b/tectonic/dpx-specials.h index 608c4a7325..a9fb6e3787 100644 --- a/tectonic/dpx-specials.h +++ b/tectonic/dpx-specials.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -46,9 +46,6 @@ struct spc_handler { spc_handler_fn_ptr exec; }; -/* This should not use pdf_. */ -void spc_set_verbose (int level); - #include #include diff --git a/tectonic/dpx-subfont.c b/tectonic/dpx-subfont.c index 913189b56f..e1f662dcb8 100644 --- a/tectonic/dpx-subfont.c +++ b/tectonic/dpx-subfont.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -27,18 +27,12 @@ #include #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" #include "dpx-error.h" #include "dpx-mem.h" #include "dpx-mfileio.h" -static int verbose = 0; -void -subfont_set_verbose (int level) -{ - verbose = level; -} - /* Don't forget fontmap reading now requires information * from SFD files. You must initialize at least sfd_file_ * cache before starting loading of fontmaps. @@ -247,7 +241,7 @@ scan_sfd_file (struct sfd_file_ *sfd, rust_input_handle_t handle) assert( sfd && handle ); - if (verbose > 3) { + if (dpx_conf.verbose_level > 3) { dpx_message("\nsubfont>> Scanning SFD file \"%s\"...\n", sfd->ident); } @@ -269,7 +263,7 @@ scan_sfd_file (struct sfd_file_ *sfd, rust_input_handle_t handle) sfd->sub_id = RENEW(sfd->sub_id, sfd->max_subfonts, char *); } - if (verbose > 3) { + if (dpx_conf.verbose_level > 3) { dpx_message("subfont>> id=\"%s\" at line=\"%d\"\n", id, lpos); } sfd->sub_id[sfd->num_subfonts] = id; @@ -281,7 +275,7 @@ scan_sfd_file (struct sfd_file_ *sfd, rust_input_handle_t handle) sfd->rec_id[n] = -1; /* Not loaded yet. We do lazy loading of map definitions. */ } - if (verbose > 3) { + if (dpx_conf.verbose_level > 3) { dpx_message("subfont>> %d entries found in SFD file \"%s\".\n", sfd->num_subfonts, sfd->ident); } @@ -385,7 +379,7 @@ sfd_load_record (const char *sfd_name, const char *subfont_id) return sfd->rec_id[i]; } - if (verbose > 3) { + if (dpx_conf.verbose_level > 3) { dpx_message("\nsubfont>> Loading SFD mapping table for <%s,%s>...", sfd->ident, subfont_id); } @@ -428,7 +422,7 @@ sfd_load_record (const char *sfd_name, const char *subfont_id) sfd->rec_id[i] = rec_id; ttstub_input_close(handle); - if (verbose > 3) { + if (dpx_conf.verbose_level > 3) { int __i; if (rec_id >= 0) { dpx_message(" at id=\"%d\"", rec_id); diff --git a/tectonic/dpx-subfont.h b/tectonic/dpx-subfont.h index ce104cc02a..138307ce25 100644 --- a/tectonic/dpx-subfont.h +++ b/tectonic/dpx-subfont.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -23,8 +23,6 @@ #include "dpx-core.h" -void subfont_set_verbose (int level); - void release_sfd_record (void); unsigned short lookup_sfd_record(int rec_id, unsigned char code); diff --git a/tectonic/dpx-system.h b/tectonic/dpx-system.h index 2a36d91e27..ed8572a74c 100644 --- a/tectonic/dpx-system.h +++ b/tectonic/dpx-system.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks diff --git a/tectonic/dpx-t1_char.c b/tectonic/dpx-t1_char.c index dbf493b378..3dafcc078d 100644 --- a/tectonic/dpx-t1_char.c +++ b/tectonic/dpx-t1_char.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -869,7 +869,7 @@ do_operator2 (t1_chardesc *cd, card8 **data, card8 *endptr) * (See, Adobe Technical Note #5177, Appendix C) */ if (!(cd->flags & T1_CS_FLAG_USE_HINTMASK)) { - if (__verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_warning("Obsolete Type 1 charstring operator \"dotsection\" not supported."); } #endif diff --git a/tectonic/dpx-tfm.c b/tectonic/dpx-tfm.c index cbf7e9b07f..ab048a6c5a 100644 --- a/tectonic/dpx-tfm.c +++ b/tectonic/dpx-tfm.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -30,6 +30,7 @@ #include #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-dpxutil.h" #include "dpx-error.h" #include "dpx-mem.h" @@ -40,8 +41,6 @@ #define FWBASE ((double) (1<<20)) -static int verbose = 0; - #define CHARACTER_INDEX(i) ((i)) /* @@ -261,13 +260,6 @@ fms_need (unsigned n) } } -void -tfm_set_verbose (int level) -{ - verbose = level; -} - - static int fread_fwords (fixword *words, uint32_t nmemb, rust_input_handle_t handle) { @@ -742,7 +734,7 @@ tfm_open (const char *tfm_name, int must_exist) return -1; } - if (verbose) { + if (dpx_conf.verbose_level > 0) { if (format == TFM_FORMAT) dpx_message("(TFM:%s", tfm_name); else if (format == OFM_FORMAT) @@ -768,7 +760,7 @@ tfm_open (const char *tfm_name, int must_exist) fms[numfms].tex_name = NEW(strlen(tfm_name)+1, char); strcpy(fms[numfms].tex_name, tfm_name); - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message(")"); return numfms++; diff --git a/tectonic/dpx-tfm.h b/tectonic/dpx-tfm.h index 217a50a2a8..d4eacedc4d 100644 --- a/tectonic/dpx-tfm.h +++ b/tectonic/dpx-tfm.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -30,7 +30,6 @@ #include "dpx-numbers.h" -void tfm_set_verbose (int level); void tfm_reset_global_state(void); int tfm_open (const char * tex_name, int must_exist); diff --git a/tectonic/dpx-truetype.c b/tectonic/dpx-truetype.c index deb0911459..9e0f37196c 100644 --- a/tectonic/dpx-truetype.c +++ b/tectonic/dpx-truetype.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -28,6 +28,7 @@ #include "core-bridge.h" #include "dpx-agl.h" +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" #include "dpx-dpxutil.h" #include "dpx-error.h" @@ -122,18 +123,7 @@ pdf_font_open_truetype (pdf_font *font) length = tt_get_ps_fontname(sfont, fontname, 255); if (length < 1) { length = MIN(strlen(ident), 255); -/* Suppress some warnings on GCC. Clang supports the same warning control - * #pragmas (and #defines __GNUC__!), but not these particular warnings, which - * leads to a meta-warning if they're left unguarded. */ -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstringop-overflow" -#pragma GCC diagnostic ignored "-Wstringop-truncation" -#endif - strncpy(fontname, ident, length); -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic pop -#endif + memcpy(fontname, ident, length); } fontname[length] = '\0'; for (n = 0; n < length; n++) { @@ -275,8 +265,6 @@ do_widths (pdf_font *font, double *widths) return; } -static int verbose = 0; - #define PDFUNIT(v) ((double) (ROUND(1000.0*(v)/(glyphs->emsize), 1))) /* @@ -316,7 +304,7 @@ do_builtin_encoding (pdf_font *font, const char *usedchars, sfnt *sfont) glyphs = tt_build_init(); - if (verbose > 2) + if (dpx_conf.verbose_level > 2) dpx_message("[glyphs:/.notdef"); count = 1; /* .notdef */ @@ -324,7 +312,7 @@ do_builtin_encoding (pdf_font *font, const char *usedchars, sfnt *sfont) if (!usedchars[code]) continue; - if (verbose > 2) + if (dpx_conf.verbose_level > 2) dpx_message("/.c0x%02x", code); gid = tt_cmap_lookup(ttcm, code); @@ -342,7 +330,7 @@ do_builtin_encoding (pdf_font *font, const char *usedchars, sfnt *sfont) } tt_cmap_release(ttcm); - if (verbose > 2) + if (dpx_conf.verbose_level > 2) dpx_message("]"); if (tt_build_tables(sfont, glyphs) < 0) { @@ -362,7 +350,7 @@ do_builtin_encoding (pdf_font *font, const char *usedchars, sfnt *sfont) } do_widths(font, widths); - if (verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_message("[%d glyphs]", glyphs->num_glyphs); tt_build_finish(glyphs); @@ -426,7 +414,7 @@ select_gsub (const char *feat, struct glyph_mapper *gm) if (idx >= 0) return 0; - if (verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_message("\ntrutype>> Try loading OTL GSUB for \"*.*.%s\"...", feat); error = otl_gsub_add_feat(gm->gsub, "*", "*", feat, gm->sfont); if (!error) { @@ -643,11 +631,11 @@ findparanoiac (const char *glyphname, USHORT *gid, struct glyph_mapper *gm) if (agln->n_components == 1) idx = tt_cmap_lookup(gm->codetogid, agln->unicodes[0]); else if (agln->n_components > 1) { - if (verbose >= 0) /* give warning */ + if (dpx_conf.verbose_level >= 0) /* give warning */ dpx_warning("Glyph \"%s\" looks like a composite glyph...", agln->name); error = composeuchar(agln->unicodes, agln->n_components, NULL, gm, &idx); - if (verbose >= 0) { + if (dpx_conf.verbose_level >= 0) { if (error) dpx_warning("Not found..."); else { @@ -822,7 +810,7 @@ do_custom_encoding (pdf_font *font, dpx_warning("Glyph \"%s\" not available in font \"%s\".", encoding[code], pdf_font_get_ident(font)); } else { - if (verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_message("truetype>> Glyph glyph-name=\"%s\" found at glyph-id=\"%u\".\n", encoding[code], gid); } idx = tt_find_glyph(glyphs, gid); @@ -852,7 +840,7 @@ do_custom_encoding (pdf_font *font, } do_widths(font, widths); - if (verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_message("[%d glyphs]", glyphs->num_glyphs); tt_build_finish(glyphs); @@ -882,8 +870,6 @@ pdf_font_load_truetype (pdf_font *font) if (!pdf_font_is_in_use(font)) return 0; - verbose = pdf_font_get_verbose(); - handle = dpx_open_truetype_file(ident); if (handle == NULL) { handle = dpx_open_dfont_file(ident); @@ -969,7 +955,7 @@ pdf_font_load_truetype (pdf_font *font) sfnt_close(sfont); ttstub_input_close(handle); - if (verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_message("[%d bytes]", pdf_stream_length(fontfile)); pdf_add_dict(descriptor, diff --git a/tectonic/dpx-tt_aux.c b/tectonic/dpx-tt_aux.c index d5c506b7f4..2e7708cd01 100644 --- a/tectonic/dpx-tt_aux.c +++ b/tectonic/dpx-tt_aux.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -24,6 +24,7 @@ #include #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-error.h" #include "dpx-numbers.h" #include "dpx-pdfobj.h" @@ -31,13 +32,6 @@ #include "dpx-tt_post.h" #include "dpx-tt_table.h" -static int verbose = 0; - -void tt_aux_set_verbose(int level) -{ - verbose = level; -} - ULONG ttc_read_offset (sfnt *sfont, int ttc_idx) { ULONG offset = 0, num_dirs = 0; @@ -177,17 +171,17 @@ pdf_obj *tt_get_fontdesc (sfnt *sfont, int *embed, int stemv, int type, const ch /* the least restrictive license granted takes precedence. */ *embed = 1; } else if (os2->fsType & 0x0004) { - if (verbose > 0) + if (dpx_conf.verbose_level > 0) dpx_warning("Font \"%s\" permits \"Preview & Print\" embedding only **\n", fontname); *embed = 1; } else { - if (always_embed) { - if (verbose > 0) + if (dpx_conf.ignore_font_license) { + if (dpx_conf.verbose_level > 0) dpx_warning("Font \"%s\" may be subject to embedding restrictions **\n", fontname); *embed = 1; } else { - if (verbose > 0) + if (dpx_conf.verbose_level > 0) dpx_warning("Embedding of font \"%s\" disabled due to license restrictions", fontname); *embed = 0; } diff --git a/tectonic/dpx-tt_aux.h b/tectonic/dpx-tt_aux.h index e5557cc7c2..9151007861 100644 --- a/tectonic/dpx-tt_aux.h +++ b/tectonic/dpx-tt_aux.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -28,8 +28,6 @@ extern int always_embed; /* flag declared in dvipdfmx.c */ -void tt_aux_set_verbose(int level); - /* TTC (TrueType Collection) */ ULONG ttc_read_offset (sfnt *sfont, int ttc_idx); diff --git a/tectonic/dpx-tt_cmap.c b/tectonic/dpx-tt_cmap.c index 8dfce4cb97..1ab2b4abbc 100644 --- a/tectonic/dpx-tt_cmap.c +++ b/tectonic/dpx-tt_cmap.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -38,6 +38,7 @@ */ #include "dpx-cmap.h" #include "dpx-cmap_write.h" +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" /* Hash */ #include "dpx-dpxutil.h" @@ -52,13 +53,6 @@ #include "dpx-unicode.h" #define VERBOSE_LEVEL_MIN 0 -static int verbose = 0; -void -otf_cmap_set_verbose (int level) -{ - otl_gsub_set_verbose(level); - verbose = level; -} /* format 0: byte encoding table */ struct cmap0 @@ -72,11 +66,12 @@ read_cmap0 (sfnt *sfont, ULONG len) struct cmap0 *map; unsigned int i; - if (len < 256) - _tt_abort("invalid cmap subtable"); + if (len < 256) { + dpx_warning("invalid format 0 TT cmap subtable"); + return NULL; + } map = NEW(1, struct cmap0); - for (i = 0; i < 256; i++) map->glyphIndexArray[i] = sfnt_get_byte(sfont); @@ -117,20 +112,25 @@ read_cmap2 (sfnt *sfont, ULONG len) struct cmap2 *map; USHORT i, n; - if (len < 512) - _tt_abort("invalid cmap subtable"); + if (len < 512) { + dpx_warning("invalid fromt2 TT cmap subtable"); + return NULL; + } map = NEW(1, struct cmap2); - for (i = 0; i < 256; i++) map->subHeaderKeys[i] = sfnt_get_ushort(sfont); - for (n = 0, i = 0; i < 256; i++) { map->subHeaderKeys[i] /= 8; if (n < map->subHeaderKeys[i]) n = map->subHeaderKeys[i]; } n += 1; /* the number of subHeaders is one plus the max of subHeaderKeys */ + if (len < 512 + n * 8 ) { + dpx_warning("invalid/truncated format2 TT cmap subtable"); + free(map); + return NULL; + } map->subHeaders = NEW(n, struct SubHeader); for (i = 0; i < n; i++) { @@ -223,8 +223,10 @@ read_cmap4(sfnt *sfont, ULONG len) struct cmap4 *map; USHORT i, n, segCount; - if (len < 8) - _tt_abort("invalid cmap subtable"); + if (len < 8) { + dpx_warning("invalid format 4 TT cmap subtable"); + return NULL; + } map = NEW(1, struct cmap4); @@ -289,7 +291,7 @@ lookup_cmap4 (struct cmap4 *map, USHORT cc) * Last segment maps 0xffff to gid 0 (?) */ i = segCount = map->segCountX2 / 2; - while (i-- > 0 && cc <= map->endCount[i]) { + while (i-- > 0 && cc <= map->endCount[i]) { if (cc >= map->startCount[i]) { if (map->idRangeOffset[i] == 0) { gid = (cc + map->idDelta[i]) & 0xffff; @@ -324,14 +326,15 @@ read_cmap6 (sfnt *sfont, ULONG len) struct cmap6 *map; USHORT i; - if (len < 4) - _tt_abort("invalid cmap subtable"); + if (len < 4) { + dpx_warning("invalid foramt 6 TT cmap subtable"); + return NULL; + } map = NEW(1, struct cmap6); map->firstCode = sfnt_get_ushort(sfont); map->entryCount = sfnt_get_ushort(sfont); map->glyphIndexArray = NEW(map->entryCount, USHORT); - for (i = 0; i < map->entryCount; i++) map->glyphIndexArray[i] = sfnt_get_ushort(sfont); @@ -390,13 +393,14 @@ read_cmap12 (sfnt *sfont, ULONG len) struct cmap12 *map; ULONG i; - if (len < 4) - _tt_abort("invalid cmap subtable"); + if (len < 4) { + dpx_warning("invalid format 12 TT cmap subtable"); + return NULL; + } map = NEW(1, struct cmap12); map->nGroups = sfnt_get_ulong(sfont); map->groups = NEW(map->nGroups, struct charGroup); - for (i = 0; i < map->nGroups; i++) { map->groups[i].startCharCode = sfnt_get_ulong(sfont); map->groups[i].endCharCode = sfnt_get_ulong(sfont); @@ -525,7 +529,7 @@ tt_cmap_release (tt_cmap *cmap) if (cmap) { if (cmap->map) { - switch(cmap->format) { + switch (cmap->format) { case 0: release_cmap0(cmap->map); break; @@ -542,7 +546,8 @@ tt_cmap_release (tt_cmap *cmap) release_cmap12(cmap->map); break; default: - _tt_abort("Unrecognized OpenType/TrueType cmap format."); + dpx_warning("Unrecognized OpenType/TrueType cmap format: %d", cmap->format); + break; } } free(cmap); @@ -581,210 +586,58 @@ tt_cmap_lookup (tt_cmap *cmap, ULONG cc) gid = lookup_cmap12(cmap->map, (ULONG) cc); break; default: - _tt_abort("Unrecognized OpenType/TrueType cmap subtable format"); + dpx_warning("Unrecognized OpenType/TrueType cmap subtable format: %d", cmap->format); break; } return gid; } -/* Sorry for placing this here. - * We need to rewrite TrueType font support code... - */ - -#define WBUF_SIZE 1024 -static unsigned char wbuf[WBUF_SIZE]; - static unsigned char srange_min[2] = {0x00, 0x00}; static unsigned char srange_max[2] = {0xff, 0xff}; static unsigned char lrange_min[4] = {0x00, 0x00, 0x00, 0x00}; static unsigned char lrange_max[4] = {0x7f, 0xff, 0xff, 0xff}; -static void -load_cmap4 (struct cmap4 *map, - unsigned char *GIDToCIDMap, - otl_gsub *gsub_vert, otl_gsub *gsub_list, - CMap *cmap, CMap *tounicode_add) -{ - USHORT c0, c1, gid, cid; - USHORT j, d, segCount; - USHORT ch; - int i; - - segCount = map->segCountX2 / 2; - for (i = segCount - 1; i >= 0 ; i--) { - c0 = map->startCount[i]; - c1 = map->endCount[i]; - d = map->idRangeOffset[i] / 2 - (segCount - i); - for (j = 0; j <= c1 - c0; j++) { - ch = c0 + j; - if (map->idRangeOffset[i] == 0) { - gid = (ch + map->idDelta[i]) & 0xffff; - } else if (c0 == 0xffff && c1 == 0xffff && map->idRangeOffset[i] == 0xffff) { - /* this is for protection against some old broken fonts... */ - gid = 0; - } else { - gid = (map->glyphIndexArray[j+d] + map->idDelta[i]) & 0xffff; - } - if (gid != 0 && gid != 0xffff) { - if (gsub_list) - otl_gsub_apply_chain(gsub_list, &gid); - if (gsub_vert) - otl_gsub_apply(gsub_vert, &gid); - if (GIDToCIDMap) { - cid = ((GIDToCIDMap[2*gid] << 8)|GIDToCIDMap[2*gid+1]); - if (cid == 0) - dpx_warning("GID %u does not have corresponding CID %u.", gid, cid); - } else { - cid = gid; - } - wbuf[0] = 0; - wbuf[1] = 0; - wbuf[2] = (ch >> 8) & 0xff; - wbuf[3] = ch & 0xff; - wbuf[4] = (cid >> 8) & 0xff; - wbuf[5] = cid & 0xff; - CMap_add_cidchar(cmap, wbuf, 4, cid); - if (tounicode_add) { - unsigned char *p = wbuf + 6; - size_t uc_len; - uc_len = UC_UTF16BE_encode_char(ch, &p, wbuf + WBUF_SIZE - 1); - CMap_add_bfchar(tounicode_add, wbuf + 4, 2, wbuf + 6, uc_len); - } - } - } - } - - return; -} - -static void -load_cmap12 (struct cmap12 *map, - unsigned char *GIDToCIDMap, - otl_gsub *gsub_vert, otl_gsub *gsub_list, - CMap *cmap, CMap *tounicode_add) -{ - ULONG i, ch; /* LONG ? */ - USHORT gid, cid; - - for (i = 0; i < map->nGroups; i++) { - for (ch = map->groups[i].startCharCode; - ch <= map->groups[i].endCharCode; - ch++) { - int d = ch - map->groups[i].startCharCode; - gid = (USHORT) ((map->groups[i].startGlyphID + d) & 0xffff); - if (gsub_list) - otl_gsub_apply_chain(gsub_list, &gid); - if (gsub_vert) - otl_gsub_apply(gsub_vert, &gid); - if (GIDToCIDMap) { - cid = ((GIDToCIDMap[2*gid] << 8)|GIDToCIDMap[2*gid+1]); - if (cid == 0) - dpx_warning("GID %u does not have corresponding CID %u.", gid, cid); - } else { - cid = gid; - } - wbuf[0] = (ch >> 24) & 0xff; - wbuf[1] = (ch >> 16) & 0xff; - wbuf[2] = (ch >> 8) & 0xff; - wbuf[3] = ch & 0xff; - wbuf[4] = (cid >> 8) & 0xff; - wbuf[5] = cid & 0xff; - CMap_add_cidchar(cmap, wbuf, 4, cid); - if (tounicode_add) { - unsigned char *p = wbuf + 6; - size_t uc_len; - uc_len = UC_UTF16BE_encode_char(ch, &p, wbuf + WBUF_SIZE - 1); - CMap_add_bfchar(tounicode_add, wbuf + 4, 2, wbuf + 6, uc_len); - } - } - } - - return; -} - -#include "dpx-cff.h" -#include "dpx-cff_dict.h" -#include "dpx-cff_types.h" /* OpenType CIDFont: * * We don't use GID for them. OpenType cmap table is for * charcode to GID mapping rather than to-CID mapping. */ +#include "dpx-cff.h" +#include "dpx-cff_dict.h" +#include "dpx-cff_types.h" #include "dpx-cid.h" #include "dpx-tt_table.h" -static int -handle_CIDFont (sfnt *sfont, - unsigned char **GIDToCIDMap, CIDSysInfo *csi) +static void +create_GIDToCIDMap (uint16_t *GIDToCIDMap, uint16_t num_glyphs, cff_font *cffont) { - cff_font *cffont; - int offset, i; - card16 num_glyphs, gid; - cff_charsets *charset; - unsigned char *map; - struct tt_maxp_table *maxp; - - assert(csi); - - offset = sfnt_find_table_pos(sfont, "CFF "); - if (offset == 0) { - csi->registry = NULL; - csi->ordering = NULL; - *GIDToCIDMap = NULL; - return 0; - } - - maxp = tt_read_maxp_table(sfont); - num_glyphs = (card16) maxp->numGlyphs; - free(maxp); - if (num_glyphs < 1) - _tt_abort("No glyph contained in this font..."); + cff_charsets *charset; + uint16_t gid, i; - cffont = cff_open(sfont->handle, offset, 0); - if (!cffont) - _tt_abort("Could not open CFF font..."); + assert(GIDToCIDMap); + if (!cffont || !(cffont->flag & FONTTYPE_CIDFONT)) { + for (gid = 0; gid < num_glyphs; gid++) { + GIDToCIDMap[gid] = gid; + } - if (!(cffont->flag & FONTTYPE_CIDFONT)) { - cff_close(cffont); - csi->registry = NULL; - csi->ordering = NULL; - *GIDToCIDMap = NULL; - return 0; + return; } - if (!cff_dict_known(cffont->topdict, "ROS")) { - _tt_abort("No CIDSystemInfo???"); - } else { - card16 reg, ord; - - reg = (card16) cff_dict_get(cffont->topdict, "ROS", 0); - ord = (card16) cff_dict_get(cffont->topdict, "ROS", 1); - - csi->registry = cff_get_string(cffont, reg); - csi->ordering = cff_get_string(cffont, ord); - csi->supplement = (int) cff_dict_get(cffont->topdict, "ROS", 2); - } + memset(GIDToCIDMap, 0, num_glyphs*sizeof(uint16_t)); - cff_read_charsets(cffont); charset = cffont->charsets; - if (!charset) { - _tt_abort("No CFF charset data???"); - } - - map = NEW(num_glyphs * 2, unsigned char); - memset(map, 0, num_glyphs * 2); + if (!charset) + return; switch (charset->format) { case 0: { s_SID *cids; /* CID... */ cids = charset->data.glyphs; - for (gid = 1, i = 0; - i < charset->num_entries; i++) { - map[2*gid ] = (cids[i] >> 8) & 0xff; - map[2*gid+1] = cids[i] & 0xff; + for (gid = 1, i = 0; i < charset->num_entries; i++) { + GIDToCIDMap[gid] = cids[i]; gid++; } } @@ -795,15 +648,13 @@ handle_CIDFont (sfnt *sfont, card16 cid, count; ranges = charset->data.range1; - for (gid = 1, i = 0; - i < charset->num_entries; i++) { + for (gid = 1, i = 0; i < charset->num_entries; i++) { cid = ranges[i].first; count = ranges[i].n_left + 1; /* card8 */ - while (count-- > 0 && - gid <= num_glyphs) { - map[2*gid ] = (cid >> 8) & 0xff; - map[2*gid + 1] = cid & 0xff; - gid++; cid++; + while (count-- > 0 && gid <= num_glyphs) { + GIDToCIDMap[gid] = cid; + gid++; + cid++; } } } @@ -814,47 +665,47 @@ handle_CIDFont (sfnt *sfont, card16 cid, count; ranges = charset->data.range2; - if (charset->num_entries == 1 && - ranges[0].first == 1) { + if (charset->num_entries == 1 && ranges[0].first == 1) { /* "Complete" CIDFont */ - map = mfree(map); + for (gid = 0; gid < num_glyphs; gid++) { + GIDToCIDMap[gid] = gid; + } } else { /* Not trivial mapping */ - for (gid = 1, i = 0; - i < charset->num_entries; i++) { + for (gid = 1, i = 0; i < charset->num_entries; i++) { cid = ranges[i].first; count = ranges[i].n_left + 1; while (count-- > 0 && gid <= num_glyphs) { - map[2*gid] = (cid >> 8) & 0xff; - map[2*gid+1] = cid & 0xff; - gid++; cid++; + GIDToCIDMap[gid] = cid; + gid++; + cid++; } } - } } break; default: - map = mfree(map); - _tt_abort("Unknown CFF charset format...: %d", charset->format); + dpx_warning("Unknown CFF charset format...: %d", charset->format); break; } - cff_close(cffont); - *GIDToCIDMap = map; - return 1; + return; } static bool is_PUA_or_presentation (unsigned int uni) { - /* KANGXI RADICALs are commonly double encoded. */ - return ((uni >= 0x2F00 && uni <= 0x2FD5) || - (uni >= 0xE000 && uni <= 0xF8FF) || (uni >= 0xFB00 && uni <= 0xFB4F) || - (uni >= 0xF0000 && uni <= 0xFFFFD) || (uni >= 0x100000 && uni <= 0x10FFFD)); + /* Some of CJK Radicals Supplement and Kangxi Radicals + * are commonly double encoded, lower the priority. + * CJK Compatibility Ideographs & Supplement added. + */ + return ((uni >= 0x2E80 && uni <= 0x2EF3) || (uni >= 0x2F00 && uni <= 0x2FD5) || + (uni >= 0xE000 && uni <= 0xF8FF) || (uni >= 0xFB00 && uni <= 0xFB4F) || + (uni >= 0xF900 && uni <= 0xFAFF) || (uni >= 0x2F800 && uni <= 0x2FA1F) || + (uni >= 0xF0000 && uni <= 0xFFFFD) || (uni >= 0x100000 && uni <= 0x10FFFD)); } static char* -sfnt_get_glyphname(struct tt_post_table *post, cff_font *cffont, USHORT gid) +lookup_glyph_name(struct tt_post_table *post, cff_font *cffont, USHORT gid) { char* name = NULL; @@ -876,92 +727,82 @@ sfnt_get_glyphname(struct tt_post_table *post, cff_font *cffont, USHORT gid) #define is_used_char2(b,c) (((b)[(c)/8]) & (1 << (7-((c)%8)))) #endif -static USHORT -handle_subst_glyphs (CMap *cmap, - CMap *cmap_add, - const char *used_glyphs, - sfnt *sfont, - cff_font *cffont) +static int32_t +handle_subst_glyphs (CMap *cmap, CMap *cmap_add, char *used_chars) { - USHORT count; - USHORT i; - struct tt_post_table *post = NULL; + int32_t count = 0; + int32_t cid; - if (!cmap_add) - post = tt_read_post_table(sfont); + for (cid = 0; cid < 65536; cid++) { + if (!is_used_char2(used_chars, cid)) + continue; + else { + unsigned char buf[256]; + size_t inbytesleft = 2, outbytesleft = 254; + size_t len; + unsigned char *outbuf = buf + 2; + const unsigned char *inbuf = buf; + + buf[0] = (cid >> 8) & 0xff; + buf[1] = cid & 0xff; + CMap_decode(cmap_add, &inbuf, &inbytesleft, &outbuf, &outbytesleft); + if (inbytesleft == 0) { + len = 254 - outbytesleft; + CMap_add_bfchar(cmap, buf, 2, buf + 2, len); + used_chars[cid / 8] &= ~(1 << (7 - (cid % 8))); + count++; + } + } + } - for (count = 0, i = 0; i < 8192; i++) { - unsigned int j; - size_t len; - size_t inbytesleft, outbytesleft; - const unsigned char *inbuf; - unsigned char *outbuf; + return count; +} - if (used_glyphs[i] == 0) - continue; +static int32_t +add_ToUnicode_via_glyph_name (CMap *cmap, char *used_chars, USHORT num_glyphs, + uint16_t *GIDToCIDMap, + sfnt *sfont, cff_font *cffont) +{ + int32_t count = 0; + USHORT gid; + struct tt_post_table *post = NULL; - for (j = 0; j < 8; j++) { - USHORT gid = 8 * i + j; - - if (!is_used_char2(used_glyphs, gid)) - continue; - - if (!cmap_add) { -#define MAX_UNICODES 16 - /* try to look up Unicode values from the glyph name... */ - char* name; - int32_t unicodes[MAX_UNICODES]; - int unicode_count = -1; - name = sfnt_get_glyphname(post, cffont, gid); - if (name) { - unicode_count = agl_get_unicodes(name, unicodes, MAX_UNICODES); - } + post = tt_read_post_table(sfont); + if (!post && !cffont) + return count; + + for (gid = 0; gid < num_glyphs; gid++) { + uint16_t cid = GIDToCIDMap[gid]; + if (is_used_char2(used_chars, cid)) { +#define MAX_UNICODES 32 + char *name; + int32_t unicodes[MAX_UNICODES]; + int unicode_count = -1; + + name = lookup_glyph_name(post, cffont, gid); + if (name) { + unicode_count = agl_get_unicodes(name, unicodes, MAX_UNICODES); #undef MAX_UNICODES - if (unicode_count == -1) { - if (name) - dpx_message("No Unicode mapping available: GID=%u, name=%s\n", gid, name); - else - dpx_message("No Unicode mapping available: GID=%u\n", gid); - } else { - /* the Unicode characters go into wbuf[2] and following, in UTF16BE */ - /* we rely on WBUF_SIZE being more than adequate for MAX_UNICODES */ - unsigned char* p = wbuf + 2; - int k; - len = 0; + free(name); + if (unicode_count > 0) { + unsigned char *buf; + unsigned char *p, *endptr; + int k; + size_t len = 0; + + buf = NEW(unicode_count*4+2, unsigned char); + p = buf + 2; + endptr = buf + (unicode_count * 4 + 2); for (k = 0; k < unicode_count; ++k) { - len += UC_UTF16BE_encode_char(unicodes[k], &p, wbuf+WBUF_SIZE); + len += UC_UTF16BE_encode_char(unicodes[k], &p, endptr); } - wbuf[0] = (gid >> 8) & 0xff; - wbuf[1] = gid & 0xff; - CMap_add_bfchar(cmap, wbuf, 2, wbuf + 2, len); - } - free(name); - } else { - wbuf[0] = (gid >> 8) & 0xff; - wbuf[1] = gid & 0xff; - - inbuf = wbuf; - inbytesleft = 2; - outbuf = wbuf + 2; - outbytesleft = WBUF_SIZE - 2; - CMap_decode(cmap_add, &inbuf, &inbytesleft, &outbuf, &outbytesleft); - - if (inbytesleft != 0) { - dpx_warning("CMap conversion failed..."); - } else { - len = WBUF_SIZE - 2 - outbytesleft; - CMap_add_bfchar(cmap, wbuf, 2, wbuf + 2, len); + buf[0] = (cid >> 8) & 0xff; + buf[1] = cid & 0xff; + CMap_add_bfchar(cmap, buf, 2, buf + 2, len); + used_chars[cid / 8] &= ~(1 << (7 - (cid % 8))); count++; - if (verbose > VERBOSE_LEVEL_MIN) { - size_t _i; - - dpx_message("otf_cmap>> Additional ToUnicode mapping: <%04X> <", gid); - for (_i = 0; _i < len; _i++) { - dpx_message("%02X", wbuf[2 + _i]); - } - dpx_message(">\n"); - } + free(buf); } } } @@ -973,198 +814,221 @@ handle_subst_glyphs (CMap *cmap, return count; } -static cff_font * -prepare_CIDFont_from_sfnt(sfnt* sfont) +static void +create_inverse_cmap4 (int32_t *map_base, int32_t *map_sub, USHORT num_glyphs, + struct cmap4 *map) { - cff_font *cffont; - unsigned int offset = 0; - - if (sfont->type != SFNT_TYPE_POSTSCRIPT || - sfnt_read_table_directory(sfont, 0) < 0 || - (offset = sfnt_find_table_pos(sfont, "CFF ")) == 0) { - return NULL; + USHORT segCount = map->segCountX2 / 2; + USHORT i, j; + + for (i = 0; i < segCount; i++) { + USHORT c0 = map->startCount[i]; + USHORT c1 = map->endCount[i]; + USHORT d = map->idRangeOffset[i] / 2 - (segCount - i); + for (j = 0; j <= c1 - c0; j++) { + USHORT ch = c0 + j; + USHORT gid; + + if (map->idRangeOffset[i] == 0) { + gid = (ch + map->idDelta[i]) & 0xffff; + } else if (c0 == 0xffff && c1 == 0xffff && map->idRangeOffset[i] == 0xffff) { + /* this is for protection against some old broken fonts... */ + gid = 0; + } else { + gid = (map->glyphIndexArray[j + d] + map->idDelta[i]) & 0xffff; + } + if (is_PUA_or_presentation(ch)) { + map_sub[gid] = ch; + } else { + map_base[gid] = ch; + } } - - cffont = cff_open(sfont->handle, offset, 0); - if (!cffont) - return NULL; - - cff_read_charsets(cffont); - return cffont; + } } -static USHORT -add_to_cmap_if_used (CMap *cmap, - cff_font *cffont, - char *used_chars, - USHORT gid, - ULONG ch) +static void +create_inverse_cmap12 (int32_t *map_base, int32_t *map_sub, USHORT num_glyphs, + struct cmap12 *map) { - USHORT count = 0; - USHORT cid = cffont ? cff_charsets_lookup_inverse(cffont, gid) : gid; - - /* Skip PUA characters and alphabetic presentation forms, allowing - * handle_subst_glyphs() as it might find better mapping. Fixes the - * mapping of ligatures encoded in PUA in fonts like Linux Libertine - * and old Adobe fonts. - */ - if (is_used_char2(used_chars, cid) && !is_PUA_or_presentation(ch)) { - int len; - unsigned char *p = wbuf + 2; - - count++; - - wbuf[0] = (cid >> 8) & 0xff; - wbuf[1] = (cid & 0xff); - len = UC_UTF16BE_encode_char((int32_t) ch, &p, wbuf + WBUF_SIZE); - CMap_add_bfchar(cmap, wbuf, 2, wbuf + 2, len); - - /* Avoid duplicate entry - * There are problem when two Unicode code is mapped to - * single glyph... - */ - used_chars[cid / 8] &= ~(1 << (7 - (cid % 8))); + ULONG i, ch; + + for (i = 0; i < map->nGroups; i++) { + for (ch = map->groups[i].startCharCode; + ch <= map->groups[i].endCharCode; ch++) { + int d = ch - map->groups[i].startCharCode; + USHORT gid = (USHORT) ((map->groups[i].startGlyphID + d) & 0xffff); + if (is_PUA_or_presentation(ch)) { + map_sub[gid] = ch; + } else { + map_base[gid] = ch; + } } - - return count; + } } -static USHORT -create_ToUnicode_cmap4 (CMap *cmap, - struct cmap4 *map, - char *used_chars, - cff_font *cffont) +/* NOTE: Reverse mapping code which had been placed here is removed since: + * - Implementation of reserve CMap mapping itself is imcomplete. + * - It is wrong to assume that all CMap passed here is Unicode to CID mapping. + * Especially, the second one causes problems. + */ +static pdf_obj * +create_ToUnicode_cmap (tt_cmap *ttcmap, + const char *cmap_name, + CMap *cmap_add, + const char *used_chars, + sfnt *sfont) { - USHORT count = 0, segCount = map->segCountX2 / 2; - USHORT i, j; + pdf_obj *stream = NULL; + int32_t *map_base = NULL, *map_sub = NULL; + USHORT gid, num_glyphs = 0; - for (i = 0; i < segCount; i++) { - USHORT c0 = map->startCount[i]; - USHORT c1 = map->endCount[i]; - USHORT d = map->idRangeOffset[i] / 2 - (segCount - i); - for (j = 0; j <= c1 - c0; j++) { - USHORT ch = c0 + j; - USHORT gid; + assert(ttcmap); - if (map->idRangeOffset[i] == 0) { - gid = (ch + map->idDelta[i]) & 0xffff; - } else if (c0 == 0xffff && c1 == 0xffff && map->idRangeOffset[i] == 0xffff) { - /* this is for protection against some old broken fonts... */ - gid = 0; - } else { - gid = (map->glyphIndexArray[j + d] + map->idDelta[i]) & 0xffff; - } + /* Get num_glyphs from maxp talbe */ + { + struct tt_maxp_table *maxp; - count += add_to_cmap_if_used(cmap, cffont, used_chars, gid, ch); + maxp = tt_read_maxp_table(sfont); + if (maxp) { + num_glyphs = maxp->numGlyphs; + free(maxp); } } - return count; -} + /* Initialize GID to Unicode mapping table */ + map_base = NEW(num_glyphs, int32_t); + map_sub = NEW(num_glyphs, int32_t); + for (gid = 0; gid < num_glyphs; gid++) { + map_base[gid] = -1; + map_sub [gid] = -1; + } -static USHORT -create_ToUnicode_cmap12 (CMap *cmap, - struct cmap12 *map, - char *used_chars, - cff_font *cffont) -{ - ULONG i, ch, count = 0; + /* Create "base" mapping from inverse mapping of OpenType cmap */ + switch (ttcmap->format) { + case 4: + create_inverse_cmap4(map_base, map_sub, num_glyphs, ttcmap->map); + break; + case 12: + create_inverse_cmap12(map_base, map_sub, num_glyphs, ttcmap->map); + break; + } - for (i = 0; i < map->nGroups; i++) { - for (ch = map->groups[i].startCharCode; - ch <= map->groups[i].endCharCode; ch++) { - int d = ch - map->groups[i].startCharCode; - USHORT gid = (USHORT) ((map->groups[i].startGlyphID + d) & 0xffff); - count += add_to_cmap_if_used(cmap, cffont, used_chars, gid, ch); + /* Now create ToUnicode CMap stream */ + { + CMap *cmap; + int32_t count; + cff_font *cffont = NULL; + char is_cidfont = 0; + uint16_t *GIDToCIDMap = NULL; + char *used_chars_copy = NULL; + + if (sfont->type == SFNT_TYPE_POSTSCRIPT) { + ULONG offset; + offset = sfnt_find_table_pos(sfont, "CFF "); + cffont = cff_open(sfont->handle, offset, 0); + cff_read_charsets(cffont); } - } + is_cidfont = cffont && (cffont->flag & FONTTYPE_CIDFONT); - return count; -} + /* GIT to CID mapping info. */ + GIDToCIDMap = NEW(num_glyphs, uint16_t); + if (is_cidfont) { + create_GIDToCIDMap(GIDToCIDMap, num_glyphs, cffont); + } else { + for (gid = 0; gid < num_glyphs; gid++) { + GIDToCIDMap[gid] = gid; + } + } + cmap = CMap_new(); + CMap_set_name (cmap, cmap_name); + CMap_set_wmode(cmap, 0); + CMap_set_type (cmap, CMAP_TYPE_TO_UNICODE); + CMap_set_CIDSysInfo(cmap, &CSI_UNICODE); + CMap_add_codespacerange(cmap, srange_min, srange_max, 2); -static pdf_obj * -create_ToUnicode_cmap (tt_cmap *ttcmap, - const char *cmap_name, - CMap *cmap_add, - const char *used_chars, - sfnt *sfont, - CMap *code_to_cid_cmap) -{ - pdf_obj *stream = NULL; - CMap *cmap; - USHORT count = 0; - cff_font *cffont = prepare_CIDFont_from_sfnt(sfont); - char is_cidfont = cffont && (cffont->flag & FONTTYPE_CIDFONT); - - cmap = CMap_new(); - CMap_set_name (cmap, cmap_name); - CMap_set_wmode(cmap, 0); - CMap_set_type (cmap, CMAP_TYPE_TO_UNICODE); - CMap_set_CIDSysInfo(cmap, &CSI_UNICODE); - CMap_add_codespacerange(cmap, srange_min, srange_max, 2); - - /* cmap_add here stores information about all unencoded glyphs which can be - * accessed only through OT Layout GSUB table. - */ - if (code_to_cid_cmap && cffont && is_cidfont && !cmap_add) { - USHORT i; - for (i = 0; i < 8192; i++) { - int j; - - if (used_chars[i] == 0) - continue; - - for (j = 0; j < 8; j++) { - USHORT cid = 8 * i + j; - int ch; - - if (!is_used_char2(used_chars, cid)) - continue; - - ch = CMap_reverse_decode(code_to_cid_cmap, cid); - if (ch >= 0) { - int len; - unsigned char *p = wbuf + 2; - wbuf[0] = (cid >> 8) & 0xff; - wbuf[1] = cid & 0xff; - len = UC_UTF16BE_encode_char(ch, &p, wbuf + WBUF_SIZE); - CMap_add_bfchar(cmap, wbuf, 2, wbuf + 2, len); + count = 0; + used_chars_copy = NEW(8192, char); + memcpy(used_chars_copy, used_chars, 8192); + for (gid = 0; gid < num_glyphs; gid++) { + uint16_t cid = GIDToCIDMap[gid]; + if (is_used_char2(used_chars_copy, cid)) { + int32_t ch; + unsigned char src[2], dst[4]; + unsigned char *p = dst, *endptr = dst + 4; + size_t len; + + ch = map_base[gid]; + if (UC_is_valid(ch)) { + src[0] = (cid >> 8) & 0xff; + src[1] = cid & 0xff; + len = UC_UTF16BE_encode_char(ch, &p, endptr); + CMap_add_bfchar(cmap, src, 2, dst, len); + used_chars_copy[cid / 8] &= ~(1 << (7 - (cid % 8))); count++; } } } - } else { - char used_chars_copy[8192]; - memcpy(used_chars_copy, used_chars, 8192); - /* For create_ToUnicode_cmap{4,12}(), cffont is for GID -> CID lookup, - * so it is only needed for CID fonts. */ - switch (ttcmap->format) { - case 4: - count = create_ToUnicode_cmap4(cmap, ttcmap->map, used_chars_copy, - is_cidfont ? cffont : NULL); - break; - case 12: - count = create_ToUnicode_cmap12(cmap, ttcmap->map, used_chars_copy, - is_cidfont ? cffont : NULL); - break; + /* cmap_add here stores information about all unencoded glyphs which can be + * accessed only through OT Layout GSUB table. + * This is only availabel when encoding is "unicode". + */ + if (cmap_add) { + count += handle_subst_glyphs(cmap, cmap_add, used_chars_copy); + } else { + /* Else, try gathering information from GSUB tables */ + count += otl_gsub_add_ToUnicode(cmap, used_chars_copy, + map_base, map_sub, num_glyphs, + GIDToCIDMap, sfont); + } + /* Find Unicode mapping via PostScript glyph names... */ + count += add_ToUnicode_via_glyph_name(cmap, used_chars_copy, num_glyphs, + GIDToCIDMap, sfont, is_cidfont ? NULL : cffont); + if (cffont) + cff_close(cffont); + + /* Finaly, PUA and presentation forms... */ + for (gid = 0; gid < num_glyphs; gid++) { + uint16_t cid = GIDToCIDMap[gid]; + if (is_used_char2(used_chars_copy, cid)) { + int32_t ch; + unsigned char src[2], dst[4]; + unsigned char *p = dst, *endptr = dst + 4; + size_t len; + + ch = map_sub[gid]; + if (UC_is_valid(ch)) { + src[0] = (cid >> 8) & 0xff; + src[1] = cid & 0xff; + len = UC_UTF16BE_encode_char(ch, &p, endptr); + CMap_add_bfchar(cmap, src, 2, dst, len); + used_chars_copy[cid / 8] &= ~(1 << (7 - (cid % 8))); + count++; + } + } } - /* For handle_subst_glyphs(), cffont is for GID -> glyph name lookup, so - * it is only needed for non-CID fonts. */ - count += handle_subst_glyphs(cmap, cmap_add, used_chars_copy, sfont, - is_cidfont ? NULL : cffont); - } + /* Check for missing mapping */ + if (dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { + for (gid = 0; gid < num_glyphs; gid++) { + uint16_t cid = GIDToCIDMap[gid]; + if (is_used_char2(used_chars_copy, cid)) { + dpx_warning("Unable to find ToUnicode mapping for glyph CID=%u (GID=%u)", cid, gid); + } + } + } + free(GIDToCIDMap); + free(used_chars_copy); - if (count < 1) - stream = NULL; - else { - stream = CMap_create_stream(cmap); + if (count < 1) + stream = NULL; + else { + stream = CMap_create_stream(cmap); + } + CMap_release(cmap); } - CMap_release(cmap); - - if (cffont) - cff_close(cffont); + free(map_base); + free(map_sub); return stream; } @@ -1185,46 +1049,30 @@ static cmap_plat_enc_rec cmap_plat_encs[] = { pdf_obj * otf_create_ToUnicode_stream (const char *font_name, int ttc_index, /* 0 for non-TTC */ - const char *used_chars, - int cmap_id) + const char *basefont, + const char *used_chars) { - pdf_obj *cmap_ref = NULL; - int res_id; - pdf_obj *cmap_obj = NULL; - CMap *cmap_add, *code_to_cid_cmap; - int cmap_add_id; - tt_cmap *ttcmap; - char *normalized_font_name; - char *cmap_name, *cmap_add_name; + pdf_obj *cmap_ref = NULL; /* returned value */ + CMap *cmap_add; + char *cmap_name; rust_input_handle_t handle = NULL; sfnt *sfont; ULONG offset = 0; - int cmap_type; + tt_cmap *ttcmap; + int cmap_id, cmap_add_id; size_t i; - /* replace slash in map name with dash to make the output cmap name valid, - * happens when XeTeX embeds full font path - * https://sourceforge.net/p/xetex/bugs/52/ - */ - normalized_font_name = NEW(strlen(font_name)+1, char); - strcpy(normalized_font_name, font_name); - for (i = 0; i < strlen(font_name); ++i) { - if (normalized_font_name[i] == '/') - normalized_font_name[i] = '-'; - } - - cmap_name = NEW(strlen(font_name)+strlen("-UTF16")+5, char); - sprintf(cmap_name, "%s,%03d-UTF16", normalized_font_name, ttc_index); - free(normalized_font_name); + cmap_name = NEW(strlen(basefont)+strlen("-UTF16")+1, char); + sprintf(cmap_name, "%s-UTF16", basefont); - res_id = pdf_findresource("CMap", cmap_name); - if (res_id >= 0) { + cmap_id = pdf_findresource("CMap", cmap_name); + if (cmap_id >= 0) { free(cmap_name); - cmap_ref = pdf_get_resource_reference(res_id); + cmap_ref = pdf_get_resource_reference(cmap_id); return cmap_ref; } - if (verbose > VERBOSE_LEVEL_MIN) { + if (dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("\n"); dpx_message("otf_cmap>> Creating ToUnicode CMap for \"%s\"...\n", font_name); } @@ -1240,7 +1088,10 @@ otf_create_ToUnicode_stream (const char *font_name, } if (!sfont) { - _tt_abort("Could not open OpenType/TrueType font file \"%s\"", font_name); + dpx_warning("Could not open OpenType/TrueType font file \"%s\"", font_name); + free(cmap_name); + ttstub_input_close(handle); + return NULL; } switch (sfont->type) { @@ -1250,7 +1101,11 @@ otf_create_ToUnicode_stream (const char *font_name, case SFNT_TYPE_TTC: offset = ttc_read_offset(sfont, ttc_index); if (offset == 0) { - _tt_abort("Invalid TTC index"); + dpx_warning("Invalid TTC index for font: %s", font_name); + sfnt_close(sfont); + ttstub_input_close(handle); + free(cmap_name); + return NULL; } break; default: @@ -1259,113 +1114,178 @@ otf_create_ToUnicode_stream (const char *font_name, } if (sfnt_read_table_directory(sfont, offset) < 0) { - _tt_abort("Could not read OpenType/TrueType table directory."); + dpx_warning("Could not read OpenType/TrueType table directory for font: %s", font_name); + sfnt_close(sfont); + ttstub_input_close(handle); + free(cmap_name); + return NULL; } - code_to_cid_cmap = CMap_cache_get(cmap_id); - cmap_type = CMap_get_type(code_to_cid_cmap); - if (cmap_type != CMAP_TYPE_CODE_TO_CID) - code_to_cid_cmap = NULL; - - cmap_add_name = NEW(strlen(font_name) + strlen(",000-UCS32-Add") + 1, char); - sprintf(cmap_add_name, "%s,%03d-UCS32-Add", font_name, ttc_index); - cmap_add_id = CMap_cache_find(cmap_add_name); - free(cmap_add_name); - if (cmap_add_id < 0) { - cmap_add = NULL; - } else { - cmap_add = CMap_cache_get(cmap_add_id); + /* cmap_add is used for storing information on ToUnicode mapping for + * unencoded glyphs which can be reached only through GSUB substitution. + * This is available only when "unicode" is specified in the encoding + * field of fontmap. We remember the inverse mapping via cmap_add in this + * case. + */ + { + char *cmap_add_name; + cmap_add_name = NEW(strlen(font_name) + strlen(",000-UCS32-Add") + 1, char); + sprintf(cmap_add_name, "%s,%03d-UCS32-Add", font_name, ttc_index); + cmap_add_id = CMap_cache_find(cmap_add_name); + free(cmap_add_name); + if (cmap_add_id < 0) { + cmap_add = NULL; + } else { + cmap_add = CMap_cache_get(cmap_add_id); + } } - CMap_set_silent(1); /* many warnings without this... */ + ttcmap = NULL; for (i = 0; i < sizeof(cmap_plat_encs) / sizeof(cmap_plat_enc_rec); ++i) { ttcmap = tt_cmap_read(sfont, cmap_plat_encs[i].platform, cmap_plat_encs[i].encoding); if (!ttcmap) continue; if (ttcmap->format == 4 || ttcmap->format == 12) { - cmap_obj = create_ToUnicode_cmap(ttcmap, cmap_name, cmap_add, used_chars, - sfont, code_to_cid_cmap); - break; + break; + } else { + tt_cmap_release(ttcmap); + ttcmap = NULL; } } - if (cmap_obj == NULL) - dpx_warning("Unable to read OpenType/TrueType Unicode cmap table."); - tt_cmap_release(ttcmap); - CMap_set_silent(0); - if (cmap_obj) { - res_id = pdf_defineresource("CMap", cmap_name, + if (ttcmap) { + pdf_obj *cmap_obj; + + CMap_set_silent(1); /* many warnings without this... */ + cmap_obj = create_ToUnicode_cmap(ttcmap, cmap_name, cmap_add, used_chars, sfont); + CMap_set_silent(0); + if (cmap_obj) { + cmap_id = pdf_defineresource("CMap", cmap_name, cmap_obj, PDF_RES_FLUSH_IMMEDIATE); - cmap_ref = pdf_get_resource_reference(res_id); - } else { - cmap_ref = NULL; + cmap_ref = pdf_get_resource_reference(cmap_id); + } + tt_cmap_release(ttcmap); } - free(cmap_name); + /* Cleanup */ + free(cmap_name); sfnt_close(sfont); if (handle) ttstub_input_close(handle); + if (!cmap_ref) { + dpx_warning("Creating ToUnicode CMap failed for \"%s\"", font_name); + } + return cmap_ref; } +/* Creating input CMaps from OT cmap table */ -static int -load_base_CMap (const char *cmap_name, CMap *tounicode_add, int wmode, - CIDSysInfo *csi, unsigned char *GIDToCIDMap, - otl_gsub *gsub_vert, otl_gsub *gsub_list, - tt_cmap *ttcmap) +static void +load_cmap4 (struct cmap4 *map, uint16_t *GIDToCIDMap, USHORT num_glyphs, + otl_gsub *gsub_vert, otl_gsub *gsub_list, + CMap *cmap, int32_t *map_base, int32_t *map_sub) { - int cmap_id; - - cmap_id = CMap_cache_find(cmap_name); - if (cmap_id < 0) { - CMap *cmap; + USHORT c0, c1, gid, cid; + USHORT j, d, segCount; + USHORT ch; + int i; + unsigned char buf[4]; + + segCount = map->segCountX2 / 2; + for (i = segCount - 1; i >= 0 ; i--) { + c0 = map->startCount[i]; + c1 = map->endCount[i]; + d = map->idRangeOffset[i] / 2 - (segCount - i); + for (j = 0; j <= c1 - c0; j++) { + ch = c0 + j; + if (map->idRangeOffset[i] == 0) { + gid = (ch + map->idDelta[i]) & 0xffff; + } else if (c0 == 0xffff && c1 == 0xffff && map->idRangeOffset[i] == 0xffff) { + /* this is for protection against some old broken fonts... */ + gid = 0; + } else { + gid = (map->glyphIndexArray[j+d] + map->idDelta[i]) & 0xffff; + } + if (gid != 0 && gid != 0xffff) { + /* Apply GSUB features */ + if (gsub_list) + otl_gsub_apply_chain(gsub_list, &gid); + if (gsub_vert) + otl_gsub_apply(gsub_vert, &gid); + cid = (gid < num_glyphs) ? GIDToCIDMap[gid] : 0; + buf[0] = 0; + buf[1] = 0; + buf[2] = (ch >> 8) & 0xff; + buf[3] = ch & 0xff; + CMap_add_cidchar(cmap, buf, 4, cid); + /* For ToUnicode creation */ + if (map_base && map_sub) { + if (is_PUA_or_presentation(ch)) { + map_sub[gid] = ch; + } else { + map_base[gid] = ch; + } + } + } + } + } - cmap = CMap_new(); - CMap_set_name (cmap, cmap_name); - CMap_set_type (cmap, CMAP_TYPE_CODE_TO_CID); - CMap_set_wmode(cmap, wmode); - CMap_add_codespacerange(cmap, lrange_min, lrange_max, 4); + return; +} - if (csi) { /* CID */ - CMap_set_CIDSysInfo(cmap, csi); +static void +load_cmap12 (struct cmap12 *map, uint16_t *GIDToCIDMap, USHORT num_glyphs, + otl_gsub *gsub_vert, otl_gsub *gsub_list, + CMap *cmap, int32_t *map_base, int32_t *map_sub) +{ + ULONG i, ch; + USHORT gid, cid; + unsigned char buf[4]; + + for (i = 0; i < map->nGroups; i++) { + for (ch = map->groups[i].startCharCode; + ch <= map->groups[i].endCharCode; ch++) { + int d = ch - map->groups[i].startCharCode; + gid = (USHORT) ((map->groups[i].startGlyphID + d) & 0xffff); + if (gsub_list) + otl_gsub_apply_chain(gsub_list, &gid); + if (gsub_vert) + otl_gsub_apply(gsub_vert, &gid); + cid = (gid < num_glyphs) ? GIDToCIDMap[gid] : 0; + buf[0] = (ch >> 24) & 0xff; + buf[1] = (ch >> 16) & 0xff; + buf[2] = (ch >> 8) & 0xff; + buf[3] = ch & 0xff; + CMap_add_cidchar(cmap, buf, 4, cid); + if (map_base && map_sub) { + if (is_PUA_or_presentation(ch)) { + map_sub[gid] = ch; } else { - CMap_set_CIDSysInfo(cmap, &CSI_IDENTITY); - } - - if (ttcmap->format == 12) { - load_cmap12(ttcmap->map, GIDToCIDMap, gsub_vert, gsub_list, cmap, tounicode_add); - } else if (ttcmap->format == 4) { - load_cmap4(ttcmap->map, GIDToCIDMap, gsub_vert, gsub_list, cmap, tounicode_add); + map_base[gid] = ch; } - - cmap_id = CMap_cache_add(cmap); + } } + } - return cmap_id; + return; } - int otf_load_Unicode_CMap (const char *map_name, int ttc_index, /* 0 for non-TTC font */ const char *otl_tags, int wmode) { int cmap_id = -1; - /* Additional ToUnicode mappings required by OTL GSUB substitusion */ - int tounicode_add_id = -1; - CMap *tounicode_add = NULL; - char *tounicode_add_name = NULL; - int is_cidfont = 0; - sfnt *sfont; + char *cmap_name = NULL; + sfnt *sfont = NULL; ULONG offset = 0; - char *base_name = NULL, *cmap_name = NULL; + uint16_t num_glyphs = 0; rust_input_handle_t handle = NULL; - otl_gsub *gsub_vert = NULL, *gsub_list = NULL; tt_cmap *ttcmap; CIDSysInfo csi = {NULL, NULL, 0}; - unsigned char *GIDToCIDMap = NULL; + uint16_t *GIDToCIDMap = NULL; if (!map_name) return -1; @@ -1374,28 +1294,67 @@ otf_load_Unicode_CMap (const char *map_name, int ttc_index, /* 0 for non-TTC fon return -1; /* Sorry for this... */ } + /* First look for cache if it was already loaded */ + cmap_name = NEW(strlen(map_name)+strlen("-UCS4-H")+5, char); + if (otl_tags) { + cmap_name = NEW(strlen(map_name)+strlen(otl_tags)+strlen("-UCS4-H")+6, char); + if (wmode) + sprintf(cmap_name, "%s,%03d,%s-UCS4-V", map_name, ttc_index, otl_tags); + else + sprintf(cmap_name, "%s,%03d,%s-UCS4-H", map_name, ttc_index, otl_tags); + } else { + if (wmode) + sprintf(cmap_name, "%s,%03d-UCS4-V", map_name, ttc_index); + else { + sprintf(cmap_name, "%s,%03d-UCS4-H", map_name, ttc_index); + } + } + cmap_id = CMap_cache_find(cmap_name); + if (cmap_id >= 0) { + free(cmap_name); + if (dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) + dpx_message("otf_cmap>> Found at cmap_id=%d.\n", cmap_id); + + return cmap_id; + } + + /* CMap not found */ + if (dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { + dpx_message("\n"); + dpx_message("otf_cmap>> Creating Unicode charmap for font=\"%s\" layout=\"%s\"\n", + map_name, (otl_tags ? otl_tags : "none")); + } + handle = dpx_open_truetype_file(map_name); if (handle == NULL) handle = dpx_open_opentype_file(map_name); if (handle == NULL) { handle = dpx_open_dfont_file(map_name); - if (handle == NULL) + if (handle == NULL) { + free(cmap_name); return -1; - + } sfont = dfont_open(handle, ttc_index); } else { sfont = sfnt_open(handle); } if (!sfont) { - _tt_abort("Could not open OpenType/TrueType/dfont font file \"%s\"", map_name); + dpx_warning("Could not open OpenType/TrueType/dfont font file \"%s\"", map_name); + free(cmap_name); + ttstub_input_close(handle); + return -1; } switch (sfont->type) { case SFNT_TYPE_TTC: offset = ttc_read_offset(sfont, ttc_index); if (offset == 0) { - _tt_abort("Invalid TTC index"); + dpx_warning("Offset=0 reurned for font=%s, TTC_index=%d", map_name, ttc_index); + free(cmap_name); + sfnt_close(sfont); + ttstub_input_close(handle); + return -1; } break; case SFNT_TYPE_TRUETYPE: @@ -1406,79 +1365,78 @@ otf_load_Unicode_CMap (const char *map_name, int ttc_index, /* 0 for non-TTC fon offset = sfont->offset; break; default: - _tt_abort("Not a OpenType/TrueType/TTC font?: %s", map_name); - break; + dpx_warning("Not a OpenType/TrueType/TTC font?: %s", map_name); + free(cmap_name); + sfnt_close(sfont); + ttstub_input_close(handle); + return -1; } - if (sfnt_read_table_directory(sfont, offset) < 0) - _tt_abort("Could not read OpenType/TrueType table directory."); - - base_name = NEW(strlen(map_name)+strlen("-UCS4-H")+5, char); - if (wmode) - sprintf(base_name, "%s,%03d-UCS4-V", map_name, ttc_index); - else { - sprintf(base_name, "%s,%03d-UCS4-H", map_name, ttc_index); + if (sfnt_read_table_directory(sfont, offset) < 0) { + dpx_warning("Could not read OpenType/TrueType table directory."); + free(cmap_name); + sfnt_close(sfont); + ttstub_input_close(handle); + return -1; } - if (otl_tags) { - cmap_name = NEW(strlen(map_name)+strlen(otl_tags)+strlen("-UCS4-H")+6, char); - if (wmode) - sprintf(cmap_name, "%s,%03d,%s-UCS4-V", map_name, ttc_index, otl_tags); - else - sprintf(cmap_name, "%s,%03d,%s-UCS4-H", map_name, ttc_index, otl_tags); - - /* tounicode_add here is later refered by otf_create_ToUnicode_stream() - * for finding additional CID to Unicode mapping entries required by - * OTL gsub substitution. - */ - tounicode_add_name = NEW(strlen(map_name) + strlen(",000-UCS32-Add") + 1, char); - sprintf(tounicode_add_name, "%s,%03d-UCS32-Add", map_name, ttc_index); - tounicode_add_id = CMap_cache_find(tounicode_add_name); - - if (tounicode_add_id >= 0) { - tounicode_add = CMap_cache_get(tounicode_add_id); - } else { - tounicode_add = CMap_new(); - CMap_set_name (tounicode_add, tounicode_add_name); - CMap_set_type (tounicode_add, CMAP_TYPE_TO_UNICODE); - CMap_set_wmode(tounicode_add, 0); - CMap_add_codespacerange(tounicode_add, srange_min, srange_max, 2); - CMap_set_CIDSysInfo(tounicode_add, &CSI_UNICODE); - CMap_add_bfchar(tounicode_add, srange_min, 2, srange_max, 2); - tounicode_add_id = CMap_cache_add(tounicode_add); - } + { + struct tt_maxp_table *maxp; - free(tounicode_add_name); - } else { - cmap_name = NEW(strlen(base_name)+1, char); - strcpy(cmap_name, base_name); + maxp = tt_read_maxp_table(sfont); + num_glyphs = (card16) maxp->numGlyphs; + free(maxp); } + GIDToCIDMap = NEW(num_glyphs, uint16_t); + memset(GIDToCIDMap, 0, num_glyphs*sizeof(uint16_t)); if (sfont->type == SFNT_TYPE_POSTSCRIPT) { - is_cidfont = handle_CIDFont(sfont, &GIDToCIDMap, &csi); - } else { - is_cidfont = 0; - } - - if (verbose > VERBOSE_LEVEL_MIN) { - dpx_message("\n"); - dpx_message("otf_cmap>> Unicode charmap for font=\"%s\" layout=\"%s\"\n", - map_name, (otl_tags ? otl_tags : "none")); - } - - cmap_id = CMap_cache_find(cmap_name); - if (cmap_id >= 0) { - free(cmap_name); - free(base_name); - free(GIDToCIDMap); - - sfnt_close(sfont); - ttstub_input_close(handle); + cff_font *cffont; + card16 gid; + + offset = sfnt_find_table_pos(sfont, "CFF "); + cffont = cff_open(sfont->handle, offset, 0); + if (!cffont) { + free(cmap_name); + free(GIDToCIDMap); + sfnt_close(sfont); + ttstub_input_close(handle); + return -1; + } + if (!(cffont->flag & FONTTYPE_CIDFONT)) { + csi.registry = strdup("Adobe"); + csi.ordering = strdup("Identity"); + csi.supplement = 0; + for (gid = 0; gid < num_glyphs; gid++) { + GIDToCIDMap[gid] = gid; + } + } else { + if (!cff_dict_known(cffont->topdict, "ROS")) { + csi.registry = strdup("Adobe"); + csi.ordering = strdup("Identity"); + csi.supplement = 0; + } else { + card16 reg, ord; - if (verbose > VERBOSE_LEVEL_MIN) - dpx_message("otf_cmap>> Found at cmap_id=%d.\n", cmap_id); + reg = (card16) cff_dict_get(cffont->topdict, "ROS", 0); + ord = (card16) cff_dict_get(cffont->topdict, "ROS", 1); + csi.registry = cff_get_string(cffont, reg); + csi.ordering = cff_get_string(cffont, ord); + csi.supplement = (int) cff_dict_get(cffont->topdict, "ROS", 2); + } + cff_read_charsets(cffont); + create_GIDToCIDMap(GIDToCIDMap, num_glyphs, cffont); + } + cff_close(cffont); + } else { + uint16_t gid; - return cmap_id; + csi.registry = strdup("Adobe"); + csi.ordering = strdup("Identity"); + csi.supplement = 0; + for (gid = 0; gid < num_glyphs; gid++) { + GIDToCIDMap[gid] = gid; + } } ttcmap = tt_cmap_read(sfont, 3, 10); /* Microsoft UCS4 */ @@ -1486,66 +1444,285 @@ otf_load_Unicode_CMap (const char *map_name, int ttc_index, /* 0 for non-TTC fon ttcmap = tt_cmap_read(sfont, 3, 1); /* Microsoft UCS2 */ if (!ttcmap) { ttcmap = tt_cmap_read(sfont, 0, 3); /* Unicode 2.0 or later */ - if (!ttcmap) { - _tt_abort("Unable to read OpenType/TrueType Unicode cmap table."); - } } } - if (wmode == 1) { - gsub_vert = otl_gsub_new(); - if (otl_gsub_add_feat(gsub_vert, "*", "*", "vrt2", sfont) < 0) { - if (otl_gsub_add_feat(gsub_vert, "*", "*", "vert", sfont) < 0) { - dpx_warning("GSUB feature vrt2/vert not found."); - otl_gsub_release(gsub_vert); - gsub_vert = NULL; + if (ttcmap) { + CMap *cmap = NULL; + int32_t *map_base, *map_sub; + otl_gsub *gsub_vert = NULL; + otl_gsub *gsub_list = NULL; + uint32_t gid; + + if (wmode == 1) { + gsub_vert = otl_gsub_new(); + if (otl_gsub_add_feat(gsub_vert, "*", "*", "vrt2", sfont) < 0) { + if (otl_gsub_add_feat(gsub_vert, "*", "*", "vert", sfont) < 0) { + dpx_warning("GSUB feature vrt2/vert not found."); + otl_gsub_release(gsub_vert); + gsub_vert = NULL; + } else { + otl_gsub_select(gsub_vert, "*", "*", "vert"); + } } else { - otl_gsub_select(gsub_vert, "*", "*", "vert"); + otl_gsub_select(gsub_vert, "*", "*", "vrt2"); } } else { - otl_gsub_select(gsub_vert, "*", "*", "vrt2"); + gsub_vert = NULL; } - } else { - gsub_vert = NULL; - } - - if (otl_tags) { - gsub_list = otl_gsub_new(); - if (otl_gsub_add_feat_list(gsub_list, otl_tags, sfont) < 0) { - dpx_warning("Reading GSUB feature table(s) failed for \"%s\"", otl_tags); + if (otl_tags) { + gsub_list = otl_gsub_new(); + if (otl_gsub_add_feat_list(gsub_list, otl_tags, sfont) < 0) { + dpx_warning("Reading GSUB feature table(s) failed for \"%s\"", otl_tags); + } else { + otl_gsub_set_chain(gsub_list, otl_tags); + } } else { - otl_gsub_set_chain(gsub_list, otl_tags); + gsub_list = NULL; } - } else { - gsub_list = NULL; + cmap = CMap_new(); + CMap_set_name(cmap, cmap_name); + CMap_set_type(cmap, CMAP_TYPE_CODE_TO_CID); + CMap_set_wmode(cmap, wmode); + CMap_add_codespacerange(cmap, lrange_min, lrange_max, 4); + CMap_set_CIDSysInfo(cmap, &csi); + map_base = NEW(num_glyphs, int32_t); + map_sub = NEW(num_glyphs, int32_t); + for (gid = 0; gid < num_glyphs; gid++) { + map_base[gid] = -1; + map_sub[gid] = -1; + } + switch (ttcmap->format) { + case 12: + load_cmap12(ttcmap->map, GIDToCIDMap, num_glyphs, + gsub_vert, gsub_list, + cmap, map_base, map_sub); + break; + case 4: + load_cmap4(ttcmap->map, GIDToCIDMap, num_glyphs, + gsub_vert, gsub_list, + cmap, map_base, map_sub); + break; + } + if (gsub_vert) + otl_gsub_release(gsub_vert); + if (gsub_list) + otl_gsub_release(gsub_list); + tt_cmap_release(ttcmap); + + if (otl_tags) { + CMap *tounicode = NULL; + char *tounicode_name; + int tounicode_id; + + tounicode_name = NEW(strlen(map_name)+strlen(",000-UCS32-Add")+1, char); + sprintf(tounicode_name, "%s,%03d-UCS32-Add", map_name, ttc_index); + tounicode_id = CMap_cache_find(tounicode_name); + + if (tounicode_id >= 0) { + tounicode = CMap_cache_get(tounicode_id); + } else { + tounicode = CMap_new(); + CMap_set_name (tounicode, tounicode_name); + CMap_set_type (tounicode, CMAP_TYPE_TO_UNICODE); + CMap_set_wmode(tounicode, 0); + CMap_add_codespacerange(tounicode, srange_min, srange_max, 2); + CMap_set_CIDSysInfo(tounicode, &CSI_UNICODE); + CMap_add_bfchar(tounicode, srange_min, 2, srange_max, 2); + tounicode_id = CMap_cache_add(tounicode); + } + + free(tounicode_name); + + for (gid = 0; gid < num_glyphs; gid++) { + uint16_t cid = GIDToCIDMap[gid]; + unsigned char src[2], dst[4]; + if (cid > 0) { + int32_t ch = UC_is_valid(map_base[gid]) ? map_base[gid] : map_sub[gid]; + if (UC_is_valid(ch)) { + unsigned char *p = dst; + unsigned char *endptr = dst + 4; + size_t len; + src[0] = (cid >> 8) & 0xff; + src[1] = cid & 0xff; + len = UC_UTF16BE_encode_char(ch, &p, endptr); + if (len > 0) { + CMap_add_bfchar(tounicode, src, 2, dst, len); + } + } + } + } + } + + cmap_id = CMap_cache_add(cmap); } - cmap_id = load_base_CMap(cmap_name, tounicode_add, wmode, - (is_cidfont ? &csi : NULL), GIDToCIDMap, - gsub_vert, gsub_list, ttcmap); + free(cmap_name); + free(GIDToCIDMap); + free(csi.registry); + free(csi.ordering); + sfnt_close(sfont); + ttstub_input_close(handle); - if (cmap_id < 0) - _tt_abort("Failed to read OpenType/TrueType cmap table."); + return cmap_id; +} - if (gsub_vert) - otl_gsub_release(gsub_vert); - gsub_vert = NULL; +int +otf_try_load_GID_to_CID_map (const char *map_name, int ttc_index, int wmode) +{ + int cmap_id = -1; + sfnt *sfont = NULL; + ULONG offset = 0; + char *cmap_name = NULL; + rust_input_handle_t handle = NULL; + + if (!map_name) + return -1; + + if (ttc_index > 999 || ttc_index < 0) { + return -1; /* Sorry for this... */ + } + + /* Check if already loaded */ + cmap_name = NEW(strlen(map_name)+strlen("-GID")+5, char); + sprintf(cmap_name, "%s:%3d-GID", map_name, ttc_index); + cmap_id = CMap_cache_find(cmap_name); + if (cmap_id >= 0) { + free(cmap_name); + if (dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) + dpx_message("otf_cmap>> GID-to-CID mapping found at cmap_id=%d.\n", cmap_id); - if (gsub_list) - otl_gsub_release(gsub_list); - gsub_list = NULL; + return cmap_id; + } + + handle = dpx_open_truetype_file(map_name); + if (handle == NULL) + handle = dpx_open_opentype_file(map_name); + if (handle == NULL) { + handle = dpx_open_dfont_file(map_name); + if (handle == NULL) { + free(cmap_name); + return -1; + } + sfont = dfont_open(handle, ttc_index); + } else { + sfont = sfnt_open(handle); + } + + if (!sfont) { + dpx_warning("Could not open OpenType/TrueType/dfont font file \"%s\"", map_name); + free(cmap_name); + ttstub_input_close(handle); + return -1; + } + switch (sfont->type) { + case SFNT_TYPE_TTC: + offset = ttc_read_offset(sfont, ttc_index); + if (offset == 0) { + dpx_warning("Invalid TTC index for font \"%s\": %d", map_name, ttc_index); + sfnt_close(sfont); + ttstub_input_close(handle); + free(cmap_name); + return -1; + } + break; + case SFNT_TYPE_TRUETYPE: + case SFNT_TYPE_POSTSCRIPT: + offset = 0; + break; + case SFNT_TYPE_DFONT: + offset = sfont->offset; + break; + default: + dpx_warning("Not a OpenType/TrueType/TTC font?: %s", map_name); + sfnt_close(sfont); + ttstub_input_close(handle); + free(cmap_name); + return -1; + } + if (sfnt_read_table_directory(sfont, offset) < 0) { + dpx_warning("Could not read OpenType/TrueType table directory: %s", map_name); + sfnt_close(sfont); + ttstub_input_close(handle); free(cmap_name); - free(base_name); - free(GIDToCIDMap); + return -1; + } + if (sfont->type != SFNT_TYPE_POSTSCRIPT) { + free(cmap_name); + sfnt_close(sfont); + ttstub_input_close(handle); + return -1; + } + + /* Read GID-to-CID mapping if CFF OpenType is found. */ + if (sfont->type == SFNT_TYPE_POSTSCRIPT) { + cff_font *cffont; + struct tt_maxp_table *maxp; + const unsigned char csrange[4] = {0x00, 0x00, 0xff, 0xff}; + uint16_t num_glyphs = 0; + + maxp = tt_read_maxp_table(sfont); + num_glyphs = (card16) maxp->numGlyphs; + free(maxp); - if (is_cidfont) { + offset = sfnt_find_table_pos(sfont, "CFF "); + cffont = cff_open(sfont->handle, offset, 0); + if (cffont && cffont->flag & FONTTYPE_CIDFONT) { + CMap *cmap; + uint16_t gid; + uint16_t *GIDToCIDMap = NULL; + CIDSysInfo csi = {NULL, NULL, 0}; + + if (!cff_dict_known(cffont->topdict, "ROS")) { + csi.registry = strdup("Adobe"); + csi.ordering = strdup("Identity"); + csi.supplement = 0; + } else { + card16 reg, ord; + + reg = (card16) cff_dict_get(cffont->topdict, "ROS", 0); + ord = (card16) cff_dict_get(cffont->topdict, "ROS", 1); + csi.registry = cff_get_string(cffont, reg); + csi.ordering = cff_get_string(cffont, ord); + csi.supplement = (int) cff_dict_get(cffont->topdict, "ROS", 2); + } + cff_read_charsets(cffont); + GIDToCIDMap = NEW(num_glyphs, uint16_t); + memset(GIDToCIDMap, 0, num_glyphs*sizeof(uint16_t)); + create_GIDToCIDMap(GIDToCIDMap, num_glyphs, cffont); + cmap = CMap_new(); + CMap_set_name (cmap, cmap_name); + CMap_set_type (cmap, CMAP_TYPE_CODE_TO_CID); + CMap_set_wmode(cmap, wmode); + CMap_add_codespacerange(cmap, &csrange[0], &csrange[2], 2); + CMap_set_CIDSysInfo(cmap, &csi); + for (gid = 0; gid < num_glyphs; gid++) { + unsigned char src[2], dst[2]; + src[0] = (gid >> 8) & 0xff; + src[1] = gid & 0xff; + dst[0] = (GIDToCIDMap[gid] >> 8) & 0xff; + dst[1] = GIDToCIDMap[gid] & 0xff; + CMap_add_bfchar(cmap, src, 2, dst, 2); + } + cmap_id = CMap_cache_add(cmap); + if (dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { + dpx_message("\n"); + dpx_message("otf_cmap>> Creating GID-to-CID mapping for font=\"%s\"\n", map_name); + } + free(GIDToCIDMap); + if (csi.registry) free(csi.registry); + if (csi.ordering) free(csi.ordering); } + if (cffont) + cff_close(cffont); + } - tt_cmap_release(ttcmap); - sfnt_close(sfont); - ttstub_input_close(handle); - return cmap_id; + free(cmap_name); + sfnt_close(sfont); + ttstub_input_close(handle); + + return cmap_id; } diff --git a/tectonic/dpx-tt_cmap.h b/tectonic/dpx-tt_cmap.h index bd04a0d257..1fe9702611 100644 --- a/tectonic/dpx-tt_cmap.h +++ b/tectonic/dpx-tt_cmap.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -25,8 +25,6 @@ #include "dpx-sfnt.h" -void otf_cmap_set_verbose (int level); - /* TrueType cmap table */ typedef struct { @@ -70,11 +68,11 @@ void tt_cmap_release (tt_cmap *cmap); /* Indirect reference */ pdf_obj *otf_create_ToUnicode_stream (const char *map_name, int ttc_index, - const char *used_chars, - int cmap_id); + const char *basefont, + const char *used_chars); /* CMap ID */ int otf_load_Unicode_CMap (const char *map_name, int ttc_index, const char *otl_opts, int wmode); - +int otf_try_load_GID_to_CID_map (const char *map_name, int ttc_index, int wmode); #endif /* _TT_CMAP_H_ */ diff --git a/tectonic/dpx-tt_gsub.c b/tectonic/dpx-tt_gsub.c index 55cb0d3783..f266897255 100644 --- a/tectonic/dpx-tt_gsub.c +++ b/tectonic/dpx-tt_gsub.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -30,18 +30,13 @@ #include #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-error.h" #include "dpx-mem.h" #include "dpx-otl_opt.h" #include "dpx-sfnt.h" -#define VERBOSE_LEVEL_MIN 0 -static int verbose = 0; -void -otl_gsub_set_verbose (int level) -{ - verbose = level; -} +#define VERBOSE_LEVEL_MIN 2 typedef USHORT Offset; typedef USHORT GlyphID; @@ -574,35 +569,31 @@ otl_gsub_read_alternate (struct otl_gsub_subtab *subtab, sfnt *sfont) data->AlternateSetCount = altset_offsets.count; if (data->AlternateSetCount == 0) { data->AlternateSet = NULL; - data->coverage.count = 0; - data->coverage.format = 0; - data->coverage.list = NULL; - return len; - } - data->AlternateSet = NEW(data->AlternateSetCount, - struct otl_gsub_altset); - for (i = 0; i < data->AlternateSetCount; i++) { - struct otl_gsub_altset *altset; - ULONG altset_offset; + } else { + data->AlternateSet = NEW(data->AlternateSetCount, + struct otl_gsub_altset); + for (i = 0; i < data->AlternateSetCount; i++) { + struct otl_gsub_altset *altset; + ULONG altset_offset; - altset = &(data->AlternateSet[i]); + altset = &(data->AlternateSet[i]); - altset_offset = offset + altset_offsets.value[i]; - sfnt_seek_set(sfont, altset_offset); - altset->GlyphCount = sfnt_get_ushort(sfont); - len += 2; - if (altset->GlyphCount == 0) { - altset->Alternate = NULL; - break; - } - altset->Alternate = NEW(altset->GlyphCount, GlyphID); - for (j = 0; j < altset->GlyphCount; j++) { - altset->Alternate[j] = sfnt_get_ushort(sfont); + altset_offset = offset + altset_offsets.value[i]; + sfnt_seek_set(sfont, altset_offset); + altset->GlyphCount = sfnt_get_ushort(sfont); len += 2; + if (altset->GlyphCount == 0) { + altset->Alternate = NULL; + continue; + } + altset->Alternate = NEW(altset->GlyphCount, GlyphID); + for (j = 0; j < altset->GlyphCount; j++) { + altset->Alternate[j] = sfnt_get_ushort(sfont); + len += 2; + } } + clt_release_number_list(&altset_offsets); } - clt_release_number_list(&altset_offsets); - sfnt_seek_set(sfont, offset + cov_offset); len += clt_read_coverage(&data->coverage, sfont); @@ -641,49 +632,46 @@ otl_gsub_read_ligature (struct otl_gsub_subtab *subtab, sfnt *sfont) data->LigSetCount = ligset_offsets.count; if (data->LigSetCount == 0) { data->LigatureSet = NULL; - data->coverage.count = 0; - data->coverage.format = 0; - data->coverage.list = NULL; - return len; - } - data->LigatureSet = NEW(data->LigSetCount, - struct otl_gsub_ligset); - for (i = 0; i < data->LigSetCount; i++) { - struct clt_number_list ligset_tab; - struct otl_gsub_ligset *ligset; - ULONG ligset_offset; - USHORT count; + } else { + data->LigatureSet = NEW(data->LigSetCount, + struct otl_gsub_ligset); + for (i = 0; i < data->LigSetCount; i++) { + struct clt_number_list ligset_tab; + struct otl_gsub_ligset *ligset; + ULONG ligset_offset; + USHORT count; - ligset = &(data->LigatureSet[i]); + ligset = &(data->LigatureSet[i]); - ligset_offset = offset + ligset_offsets.value[i]; - sfnt_seek_set(sfont, ligset_offset); - len += clt_read_number_list(&ligset_tab, sfont); + ligset_offset = offset + ligset_offsets.value[i]; + sfnt_seek_set(sfont, ligset_offset); + len += clt_read_number_list(&ligset_tab, sfont); - ligset->LigatureCount = ligset_tab.count; - if (ligset_tab.count == 0) { - ligset->Ligature = NULL; - break; - } - ligset->Ligature = NEW(ligset_tab.count, - struct otl_gsub_ligtab); - for (j = 0; j < ligset_tab.count; j++) { - sfnt_seek_set(sfont, ligset_offset + ligset_tab.value[j]); - ligset->Ligature[j].LigGlyph = sfnt_get_ushort(sfont); - ligset->Ligature[j].CompCount = sfnt_get_ushort(sfont); - if (ligset->Ligature[j].CompCount == 0) { - ligset->Ligature[j].Component = NULL; - break; + ligset->LigatureCount = ligset_tab.count; + if (ligset_tab.count == 0) { + ligset->Ligature = NULL; + continue; } - ligset->Ligature[j].Component = - NEW(ligset->Ligature[j].CompCount - 1, GlyphID); - for (count = 0; - count < ligset->Ligature[j].CompCount - 1; count++) { - ligset->Ligature[j].Component[count] = sfnt_get_ushort(sfont); + ligset->Ligature = NEW(ligset_tab.count, + struct otl_gsub_ligtab); + for (j = 0; j < ligset_tab.count; j++) { + sfnt_seek_set(sfont, ligset_offset + ligset_tab.value[j]); + ligset->Ligature[j].LigGlyph = sfnt_get_ushort(sfont); + ligset->Ligature[j].CompCount = sfnt_get_ushort(sfont); + if (ligset->Ligature[j].CompCount == 0) { + ligset->Ligature[j].Component = NULL; + continue; + } + ligset->Ligature[j].Component = + NEW(ligset->Ligature[j].CompCount - 1, GlyphID); + for (count = 0; + count < ligset->Ligature[j].CompCount - 1; count++) { + ligset->Ligature[j].Component[count] = sfnt_get_ushort(sfont); + } + len += 4 + count * 2; } - len += 4 + count * 2; + clt_release_number_list(&ligset_tab); } - clt_release_number_list(&ligset_tab); } clt_release_number_list(&ligset_offsets); @@ -872,7 +860,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) script_tab.DefaultLangSys != 0) { struct clt_langsys_table langsys_tab; - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("otl_gsub>> OTL script-language enabled: %c%c%c%c.dflt\n", script_list.record[script_idx].tag[0], script_list.record[script_idx].tag[1], @@ -902,7 +890,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) if (otl_match_optrule(language, langsys_rec->tag)) { struct clt_langsys_table langsys_tab; - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("otl_gsub>> OTL script-language enabled: %c%c%c%c.%c%c%c%c\n", script_list.record[script_idx].tag[0], script_list.record[script_idx].tag[1], @@ -940,7 +928,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) sfnt_seek_set(sfont, offset); clt_read_number_list(&lookup_list, sfont); - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("otl_gsub>> Reading OTL feature(s):"); } @@ -952,7 +940,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) struct clt_feature_table feature_table; int i; - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message(" %c%c%c%c", feature_list.record[feat_idx].tag[0], feature_list.record[feat_idx].tag[1], @@ -966,10 +954,11 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) sfnt_seek_set(sfont, offset); clt_read_feature_table(&feature_table, sfont); +#if 0 if (feature_table.FeatureParams != 0) { _tt_abort("unrecognized FeatureParams"); } - +#endif /* Lookup table */ for (i = 0; i < feature_table.LookupListIndex.count; i++) { struct clt_lookup_table lookup_table; @@ -988,7 +977,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) lookup_table.LookupType != OTL_GSUB_TYPE_ALTERNATE && lookup_table.LookupType != OTL_GSUB_TYPE_LIGATURE && lookup_table.LookupType != OTL_GSUB_TYPE_ESUBST) { - if (verbose > VERBOSE_LEVEL_MIN) + if (dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) dpx_warning("Skipping unsupported GSUB subtable: LookupType=%d", lookup_table.LookupType); continue; } @@ -1012,7 +1001,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) if (r <= 0) dpx_warning("Reading GSUB subtable (single) failed..."); else { - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("(single)"); } n_st++; @@ -1025,7 +1014,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) if (r <= 0) dpx_warning("Reading GSUB subtable (alternate) failed..."); else { - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("(alternate)"); } n_st++; @@ -1038,7 +1027,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) if (r <= 0) dpx_warning("Reading GSUB subtable (ligature) failed..."); else { - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("(ligature)"); } n_st++; @@ -1065,7 +1054,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) if (r <= 0) dpx_warning("Reading GSUB subtable (ext:single) failed..."); else { - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("(ext:single)"); } n_st++; @@ -1078,7 +1067,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) if (r <= 0) dpx_warning("Reading GSUB subtable (alternate) failed..."); else { - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("(alternate)"); } n_st++; @@ -1091,7 +1080,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) if (r <= 0) dpx_warning("Reading GSUB subtable (ext:ligature) failed..."); else { - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("(ext:ligature)"); } n_st++; @@ -1113,7 +1102,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) } } - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("\n"); dpx_message("otl_gsub>> %d subtable(s) read.\n", num_subtabs); } @@ -1326,7 +1315,7 @@ otl_gsub_add_feat (otl_gsub *gsub_list, gsub->feature = NEW(strlen(feature) +1, char); strcpy(gsub->feature, feature); - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("\n"); dpx_message("otl_gsub>> Reading \"%s.%s.%s\"...\n", script, language, feature); } @@ -1336,7 +1325,7 @@ otl_gsub_add_feat (otl_gsub *gsub_list, gsub_list->select = i; gsub_list->num_gsubs++; } else { - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("otl_gsub>> Failed\n"); } free(gsub->script); @@ -1679,3 +1668,349 @@ otl_gsub_apply_chain (otl_gsub *gsub_list, USHORT *gid) return retval; } + +#if 1 +#include "dpx-unicode.h" + +#ifndef is_used_char2 +#define is_used_char2(b,c) (((b)[(c)/8]) & (1 << (7-((c)%8)))) +#endif + +static int +add_glyph_if_valid (CMap *cmap, char *used_chars, + int32_t *map_base, int32_t *map_sub, USHORT num_glyphs, + uint16_t *GIDToCIDMap, USHORT gid, USHORT gid_sub) +{ + int count = 0; + unsigned char src[2], dst[4]; + unsigned char *p = dst, *endptr = dst + 4; + size_t len; + uint16_t cid_sub; + + if (gid_sub >= num_glyphs || gid >= num_glyphs) + return 0; + + cid_sub = GIDToCIDMap[gid_sub]; + if (is_used_char2(used_chars, cid_sub)) { + int32_t ch = map_base[gid]; + if (UC_is_valid(ch)) { + src[0] = (cid_sub >> 8) & 0xff; + src[1] = cid_sub & 0xff; + len = UC_UTF16BE_encode_char(ch, &p, endptr); + CMap_add_bfchar(cmap, src, 2, dst, len); + used_chars[cid_sub / 8] &= ~(1 << (7 - (cid_sub % 8))); + count = 1; + } else { + ch = map_sub[gid]; + if (UC_is_valid(ch)) { + src[0] = (cid_sub >> 8) & 0xff; + src[1] = cid_sub & 0xff; + len = UC_UTF16BE_encode_char(ch, &p, endptr); + CMap_add_bfchar(cmap, src, 2, dst, len); + used_chars[cid_sub / 8] &= ~(1 << (7 - (cid_sub % 8))); + count = 1; + } + } + } + return count; +} + +static int +add_ToUnicode_single (CMap *cmap, char *used_chars, + struct otl_gsub_subtab *subtab, + int32_t *map_base, int32_t *map_sub, USHORT num_glyphs, + uint16_t *GIDToCIDMap) +{ + int count = 0; + USHORT i, idx, gid; + USHORT gid_sub; + + assert(subtab); + + if (subtab->SubstFormat == 1) { + struct otl_gsub_single1 *data; + struct clt_coverage *cov; + + data = (subtab->table).single1; + cov = &data->coverage; + switch (cov->format) { + case 1: /* list */ + for (idx = 0; idx < cov->count; idx++) { + gid = cov->list[idx]; + gid_sub = gid + data->DeltaGlyphID; + count += add_glyph_if_valid(cmap, used_chars, + map_base, map_sub, num_glyphs, + GIDToCIDMap, gid, gid_sub); + } + break; + case 2: /* range */ + for (i = 0; i < cov->count; i++) { + for (gid = cov->range[i].Start; + gid <= cov->range[i].End && gid < num_glyphs; gid++) { + idx = cov->range[i].StartCoverageIndex + gid - cov->range[i].Start; + gid_sub = gid + data->DeltaGlyphID; + count += add_glyph_if_valid(cmap, used_chars, + map_base, map_sub, num_glyphs, + GIDToCIDMap, gid, gid_sub); + } + } + break; + } + } else if (subtab->SubstFormat == 2) { + struct otl_gsub_single2 *data; + struct clt_coverage *cov; + + data = (subtab->table).single2; + cov = &data->coverage; + switch (cov->format) { + case 1: /* list */ + for (idx = 0; idx < cov->count; idx++) { + gid = cov->list[idx]; + if (idx >= 0 && idx < data->GlyphCount) { + gid_sub = (data->Substitute)[idx]; + count += add_glyph_if_valid(cmap, used_chars, + map_base, map_sub, num_glyphs, + GIDToCIDMap, gid, gid_sub); + } + } + break; + case 2: /* range */ + for (i = 0; i < cov->count; i++) { + for (gid = cov->range[i].Start; + gid <= cov->range[i].End && gid < num_glyphs; gid++) { + idx = cov->range[i].StartCoverageIndex + gid - cov->range[i].Start; + if (idx >= 0 && idx < data->GlyphCount) { + gid_sub = (data->Substitute)[idx]; + count += add_glyph_if_valid(cmap, used_chars, + map_base, map_sub, num_glyphs, + GIDToCIDMap, gid, gid_sub); + } + } + } + break; + } + } + + return count; +} + +static int32_t +add_alternate1_inverse_map (CMap *cmap, char *used_chars, + int32_t *map_base, int32_t *map_sub, USHORT num_glyphs, + uint16_t *GIDToCIDMap, USHORT gid, int idx, + struct otl_gsub_alternate1 *data) +{ + int32_t count = 0; + + if (idx >= 0 && idx < data->AlternateSetCount) { + struct otl_gsub_altset *altset; + USHORT i; + + altset = &(data->AlternateSet[idx]); + if (altset->GlyphCount == 0) + return count; + for (i = 0; i < altset->GlyphCount; i++) { + USHORT gid_alt = altset->Alternate[i]; + count += add_glyph_if_valid(cmap, used_chars, + map_base, map_sub, num_glyphs, + GIDToCIDMap, gid, gid_alt); + } + } + return count; +} + +static int32_t +add_ToUnicode_alternate (CMap *cmap, char *used_chars, + struct otl_gsub_subtab *subtab, + int32_t *map_base, int32_t *map_sub, USHORT num_glyphs, + uint16_t *GIDToCIDMap) +{ + int32_t count = 0; + USHORT i, gid, idx; + + assert(subtab); + + if (subtab->SubstFormat == 1) { + struct otl_gsub_alternate1 *data; + struct clt_coverage *cov; + data = subtab->table.alternate1; + cov = &data->coverage; + switch (cov->format) { + case 1: /* list */ + for (idx = 0; idx < cov->count; idx++) { + gid = cov->list[idx]; + if (gid < num_glyphs) { + count += add_alternate1_inverse_map(cmap, used_chars, + map_base, map_sub, num_glyphs, + GIDToCIDMap, gid, idx, data); + } + } + break; + case 2: /* range */ + for (i = 0; i < cov->count; i++) { + for (gid = cov->range[i].Start; + gid <= cov->range[i].End && gid < num_glyphs; gid++) { + idx = cov->range[i].StartCoverageIndex + gid - cov->range[i].Start; + count += add_alternate1_inverse_map(cmap, used_chars, + map_base, map_sub, num_glyphs, + GIDToCIDMap, gid, idx, data); + } + } + break; + } + } + return count; +} + +static int32_t +add_ligature1_inverse_map (CMap *cmap, char *used_chars, + int32_t *map_base, int32_t *map_sub, USHORT num_glyphs, + uint16_t *GIDToCIDMap, USHORT gid_1, int idx, + struct otl_gsub_ligature1 *data) +{ + int32_t count = 0; + + if (idx >= 0 && idx < data->LigSetCount) { + struct otl_gsub_ligset *ligset; + USHORT i, j; + + ligset = &(data->LigatureSet[idx]); + for (j = 0; j < ligset->LigatureCount; j++) { + USHORT gid_sub = ligset->Ligature[j].LigGlyph; + if (gid_sub < num_glyphs) { + uint16_t cid = GIDToCIDMap[gid_sub]; + if (is_used_char2(used_chars, cid)) { + int32_t ch, *ucv; + USHORT comp_count = ligset->Ligature[j].CompCount; + int fail_count = 0; + + ucv = NEW(comp_count, int32_t); + ch = UC_is_valid(map_base[gid_1]) ? map_base[gid_1] : map_sub[gid_1]; + ucv[0] = ch; + fail_count += UC_is_valid(ch) ? 0 : 1; + for (i = 0; i < ligset->Ligature[j].CompCount - 1; i++) { + USHORT gid = ligset->Ligature[j].Component[i]; + if (gid < num_glyphs) { + ch = UC_is_valid(map_base[gid]) ? map_base[gid] : map_sub[gid]; + ucv[i+1] = ch; + fail_count += UC_is_valid(ch) ? 0 : 1; + } else { + fail_count += 1; + } + } + if (fail_count == 0) { + unsigned char src[2], *dst; + unsigned char *p, *endptr; + size_t len = 0; + + src[0] = (cid >> 8) & 0xff; + src[1] = cid & 0xff; + dst = NEW(comp_count*4, unsigned char); + p = dst; + endptr = dst + comp_count * 4; + for (i = 0; i < comp_count; i++) { + len += UC_UTF16BE_encode_char(ucv[i], &p, endptr); + } + CMap_add_bfchar(cmap, src, 2, dst, len); + used_chars[cid / 8] &= ~(1 << (7 - (cid % 8))); + count++; + free(dst); + } + free(ucv); + } + } + } + } + + return count; +} + +static int32_t +add_ToUnicode_ligature (CMap *cmap, char *used_chars, + struct otl_gsub_subtab *subtab, + int32_t *map_base, int32_t *map_sub, USHORT num_glyphs, + uint16_t *GIDToCIDMap) +{ + int32_t count = 0; + USHORT i, idx, gid; + + assert(subtab); + + if (subtab->SubstFormat == 1) { + struct otl_gsub_ligature1 *data; + struct clt_coverage *cov; + + data = subtab->table.ligature1; + cov = &data->coverage; + switch (cov->format) { + case 1: /* list */ + for (idx = 0; idx < cov->count; idx++) { + gid = cov->list[idx]; + if (gid < num_glyphs) { + count += add_ligature1_inverse_map(cmap, used_chars, + map_base, map_sub, num_glyphs, + GIDToCIDMap, gid, idx, data); + } + } + break; + case 2: /* range */ + for (i = 0; i < cov->count; i++) { + for (gid = cov->range[i].Start; + gid <= cov->range[i].End && gid < num_glyphs; gid++) { + idx = cov->range[i].StartCoverageIndex + gid - cov->range[i].Start; + if (gid < num_glyphs) { + count += add_ligature1_inverse_map(cmap, used_chars, + map_base, map_sub, num_glyphs, + GIDToCIDMap, gid, idx, data); + } + } + } + break; + } + } + + return 0; +} + +int +otl_gsub_add_ToUnicode (CMap *cmap, char *used_chars, + int32_t *map_base, int32_t *map_sub, USHORT num_glyphs, + uint16_t *GIDToCIDMap, sfnt *sfont) +{ + int count = 0; + otl_gsub *gsub_list; + struct otl_gsub_tab *gsub; + struct otl_gsub_subtab *subtab; + int i, j; + + gsub_list = otl_gsub_new(); + otl_gsub_add_feat(gsub_list, "*", "*", "*", sfont); + + for (i = 0; i < gsub_list->num_gsubs; i++) { + gsub = &(gsub_list->gsubs[i]); + for (j = 0; j < gsub->num_subtables; j++) { + subtab = &(gsub->subtables[j]); + switch ((int) subtab->LookupType){ + case OTL_GSUB_TYPE_SINGLE: + count += add_ToUnicode_single(cmap, used_chars, subtab, + map_base, map_sub, num_glyphs, + GIDToCIDMap); + break; + case OTL_GSUB_TYPE_ALTERNATE: + count += add_ToUnicode_alternate(cmap, used_chars, subtab, + map_base, map_sub, num_glyphs, + GIDToCIDMap); + break; + case OTL_GSUB_TYPE_LIGATURE: + count += add_ToUnicode_ligature(cmap, used_chars, subtab, + map_base, map_sub, num_glyphs, + GIDToCIDMap); + break; + } + } + } + otl_gsub_release(gsub_list); + + return count; +} +#endif diff --git a/tectonic/dpx-tt_gsub.h b/tectonic/dpx-tt_gsub.h index 4ebbd00c56..8d541fcc47 100644 --- a/tectonic/dpx-tt_gsub.h +++ b/tectonic/dpx-tt_gsub.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -21,13 +21,11 @@ #ifndef _TT_GSUB_H_ #define _TT_GSUB_H_ +#include "dpx-cmap.h" #include "dpx-core.h" - #include "dpx-otl_opt.h" #include "dpx-sfnt.h" -void otl_gsub_set_verbose (int level); - typedef struct otl_gsub otl_gsub; /* LookupType for GSUB */ @@ -62,4 +60,7 @@ int otl_gsub_add_feat_list (otl_gsub *gsub_list, const char *otl_tags, sfnt *sfo int otl_gsub_set_chain (otl_gsub *gsub_list, const char *otl_tags); int otl_gsub_apply_chain (otl_gsub *gsub_list, USHORT *gid); +int otl_gsub_add_ToUnicode (CMap *cmap, char *used_chars, + int32_t *map_base, int32_t *map_sub, USHORT num_glyphs, + uint16_t *GIDToCIDMap, sfnt *sfont); #endif /* _TT_GSUB_H_ */ diff --git a/tectonic/dpx-tt_post.c b/tectonic/dpx-tt_post.c index 12f7de3954..c3dfe94657 100644 --- a/tectonic/dpx-tt_post.c +++ b/tectonic/dpx-tt_post.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -42,28 +42,12 @@ read_v2_post_names (struct tt_post_table *post, sfnt *sfont) indices = NEW(post->numberOfGlyphs, USHORT); maxidx = 257; - for (i = 0; - i < post->numberOfGlyphs; i++) { + for (i = 0; i < post->numberOfGlyphs; i++) { idx = sfnt_get_ushort(sfont); if (idx >= 258) { if (idx > maxidx) maxidx = idx; - if (idx > 32767) { - /* Although this is strictly speaking out of spec, it seems to work - and there are real-life fonts that use it. - We show a warning only once, instead of thousands of times */ - static char warning_issued = 0; - if (!warning_issued) { - dpx_warning("TrueType post table name index %u > 32767", idx); - warning_issued = 1; - } - /* In a real-life large font, (x)dvipdfmx crashes if we use - nonvanishing idx in the case of idx > 32767. - If we set idx = 0, (x)dvipdfmx works fine for the font and - created pdf seems fine. The post table may not be important - in such a case */ - idx = 0; - } + /* Tectonic: #if 0 stanza removed */ } indices[i] = idx; } @@ -156,9 +140,8 @@ tt_lookup_post_table (struct tt_post_table *post, const char *glyphname) assert(post && glyphname); - for (gid = 0; gid < post->count; gid++) { - if (post->glyphNamePtr[gid] && - streq_ptr(glyphname, post->glyphNamePtr[gid])) { + for (gid = 0; gid < post->numberOfGlyphs; gid++) { + if (post->glyphNamePtr[gid] && streq_ptr(glyphname, post->glyphNamePtr[gid])) { return gid; } } @@ -169,7 +152,7 @@ tt_lookup_post_table (struct tt_post_table *post, const char *glyphname) char* tt_get_glyphname (struct tt_post_table *post, USHORT gid) { - if (gid < post->count && post->glyphNamePtr[gid]) + if (gid < post->numberOfGlyphs && post->glyphNamePtr[gid]) return xstrdup(post->glyphNamePtr[gid]); return NULL; } diff --git a/tectonic/dpx-tt_table.c b/tectonic/dpx-tt_table.c index dcf7b47ff6..f0d51c53ba 100644 --- a/tectonic/dpx-tt_table.c +++ b/tectonic/dpx-tt_table.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -398,9 +398,12 @@ tt_get_name (sfnt *sfont, char *dest, USHORT destlen, USHORT length = 0; USHORT num_names, string_offset; ULONG name_offset; - int i; + int i, j; + int is_utf16_be; name_offset = sfnt_locate_table (sfont, "name"); + is_utf16_be = (plat_id == 3) && (enco_id == 1) && + (lang_id == 0x0409u) && (name_id == 6); if (sfnt_get_ushort(sfont)) _tt_abort("Expecting zero"); @@ -420,12 +423,22 @@ tt_get_name (sfnt *sfont, char *dest, USHORT destlen, /* language ID value 0xffffu for `accept any language ID' */ if ((p_id == plat_id) && (e_id == enco_id) && (lang_id == 0xffffu || l_id == lang_id) && (n_id == name_id)) { + if (is_utf16_be) { + length /= 2; + } if (length > destlen - 1) { dpx_warning("Name string too long (%u), truncating to %u", length, destlen); length = destlen - 1; } sfnt_seek_set (sfont, name_offset+string_offset+offset); - sfnt_read((unsigned char*)dest, length, sfont); + if (is_utf16_be) { + for (j=0;jdescendant; - return otf_create_ToUnicode_stream(CIDFont_get_ident(cidfont), - CIDFont_get_opt_index(cidfont), - Type0Font_get_usedchars(font), - font->cmap_id); -} - /* Try to load ToUnicode CMap from file system first, if not found fallback to - * font CMap reverse lookup. */ + * font CMap reverse lookup. + * CHANGED: CMap here is not always Unicode to CID mapping. Don't use reverse lookup. + */ static pdf_obj * Type0Font_try_load_ToUnicode_stream(Type0Font *font, char *cmap_base) { - char *cmap_name = NEW(strlen(cmap_base) + strlen("-UTF-16"), char); pdf_obj *tounicode; + char *cmap_name; + cmap_name = NEW(strlen(cmap_base)+strlen("-UTF16")+1, char); sprintf(cmap_name, "%s-UTF16", cmap_base); tounicode = pdf_read_ToUnicode_file(cmap_name); if (!tounicode) { sprintf(cmap_name, "%s-UCS2", cmap_base); tounicode = pdf_read_ToUnicode_file(cmap_name); } - free(cmap_name); - if (!tounicode) - tounicode = Type0Font_create_ToUnicode_stream(font); + if (!tounicode) { + CIDFont *cidfont = font->descendant; + tounicode = otf_create_ToUnicode_stream(CIDFont_get_ident(cidfont), + CIDFont_get_opt_index(cidfont), + CIDFont_get_fontname(cidfont), + Type0Font_get_usedchars(font)); + } return tounicode; } static void -add_ToUnicode (Type0Font *font) +Type0Font_attach_ToUnicode_stream (Type0Font *font) { pdf_obj *tounicode; CIDFont *cidfont; @@ -215,21 +206,30 @@ add_ToUnicode (Type0Font *font) csi = CIDFont_get_CIDSysInfo(cidfont); fontname = CIDFont_get_fontname(cidfont); if (CIDFont_get_embedding(cidfont)) { - fontname += 7; /* FIXME */ + fontname += 7; /* FIXME: Skip pseudo unique tag... */ } - if (streq_ptr(csi->registry, "Adobe") && - streq_ptr(csi->ordering, "Identity")) { + if (streq_ptr(csi->registry, "Adobe") && streq_ptr(csi->ordering, "Identity")) { switch (CIDFont_get_subtype(cidfont)) { case CIDFONT_TYPE2: /* PLEASE FIX THIS */ - tounicode = Type0Font_create_ToUnicode_stream(font); + { + tounicode = otf_create_ToUnicode_stream(CIDFont_get_ident(cidfont), + CIDFont_get_opt_index(cidfont), + CIDFont_get_fontname(cidfont), + Type0Font_get_usedchars(font)); + } break; default: - if (CIDFont_get_flag(cidfont, CIDFONT_FLAG_TYPE1C)) { /* FIXME */ - tounicode = Type0Font_create_ToUnicode_stream(font); - } else if (CIDFont_get_flag(cidfont, CIDFONT_FLAG_TYPE1)) { /* FIXME */ - /* Font loader will create ToUnicode and set. */ + if (CIDFont_get_flag(cidfont, CIDFONT_FLAG_TYPE1C)) { + tounicode = otf_create_ToUnicode_stream(CIDFont_get_ident(cidfont), + CIDFont_get_opt_index(cidfont), + CIDFont_get_fontname(cidfont), + Type0Font_get_usedchars(font)); + } else if (CIDFont_get_flag(cidfont, CIDFONT_FLAG_TYPE1)) { + /* FIXME: handled on very different timing. + * Font loader will create ToUnicode and set. + */ return; } else { tounicode = Type0Font_try_load_ToUnicode_stream(font, fontname); @@ -268,8 +268,9 @@ Type0Font_dofont (Type0Font *font) if (!font || !font->indirect) return; - if (!pdf_lookup_dict(font->fontdict, "ToUnicode")) { /* FIXME */ - add_ToUnicode(font); + /* FIXME: Should move to pdffont.c */ + if (!pdf_lookup_dict(font->fontdict, "ToUnicode")) { + Type0Font_attach_ToUnicode_stream(font); } } @@ -368,10 +369,8 @@ Type0Font_cache_find (const char *map_name, int cmap_id, fontmap_opt *fmap_opt) CIDSysInfo *csi; char *fontname = NULL; int cid_id = -1, parent_id = -1, wmode = 0; - int pdf_ver; - pdf_ver = pdf_get_version(); - if (!map_name || cmap_id < 0 || pdf_ver < 2) + if (!map_name || cmap_id < 0 || pdf_check_version(1, 2) < 0) return -1; /* @@ -461,7 +460,7 @@ Type0Font_cache_find (const char *map_name, int cmap_id, fontmap_opt *fmap_opt) */ fontname = CIDFont_get_fontname(cidfont); - if (__verbose) { + if (dpx_conf.verbose_level > 0) { if (CIDFont_get_embedding(cidfont) && strlen(fontname) > 7) dpx_message("(CID:%s)", fontname+7); /* skip XXXXXX+ */ else diff --git a/tectonic/dpx-type0.h b/tectonic/dpx-type0.h index 5fe19841c5..f9fa693068 100644 --- a/tectonic/dpx-type0.h +++ b/tectonic/dpx-type0.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -30,8 +30,6 @@ typedef struct Type0Font Type0Font; -void Type0Font_set_verbose (int level); - int Type0Font_get_wmode (Type0Font *font); char *Type0Font_get_usedchars (Type0Font *font); diff --git a/tectonic/dpx-type1.c b/tectonic/dpx-type1.c index c9df9a4300..1eb43d3530 100644 --- a/tectonic/dpx-type1.c +++ b/tectonic/dpx-type1.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2008-2016 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, + Copyright (C) 2008-2018 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -34,6 +34,7 @@ #include "dpx-cff_dict.h" #include "dpx-cff_limits.h" #include "dpx-cff_types.h" +#include "dpx-dpxconf.h" #include "dpx-error.h" #include "dpx-mem.h" #include "dpx-numbers.h" @@ -499,7 +500,7 @@ pdf_font_load_type1 (pdf_font *font) double *widths; card16 *GIDMap, num_glyphs = 0; int offset; - int code, verbose; + int code; rust_input_handle_t handle; assert(font); @@ -507,8 +508,6 @@ pdf_font_load_type1 (pdf_font *font) if (!pdf_font_is_in_use(font)) return 0; - verbose = pdf_font_get_verbose(); - encoding_id = pdf_font_get_encoding (font); fontdict = pdf_font_get_resource (font); @@ -604,7 +603,7 @@ pdf_font_load_type1 (pdf_font *font) if (gid < 0) _tt_abort("Type 1 font with no \".notdef\" glyph???"); GIDMap[0] = (card16) gid; - if (verbose > 2) + if (dpx_conf.verbose_level > 2) dpx_message("[glyphs:/.notdef"); num_glyphs = 1; @@ -654,7 +653,7 @@ pdf_font_load_type1 (pdf_font *font) prev = code; num_glyphs++; - if (verbose > 2) + if (dpx_conf.verbose_level > 2) dpx_message("/%s", glyph); /* CharSet is actually string object. */ @@ -743,11 +742,16 @@ pdf_font_load_type1 (pdf_font *font) } if (i == num_glyphs) { - if (verbose > 2) + if (dpx_conf.verbose_level > 2) dpx_message("/%s", achar_name); GIDMap[num_glyphs++] = achar_gid; charset->data.glyphs[charset->num_entries] = cff_get_seac_sid(cffont, achar_name); charset->num_entries += 1; + /* CharSet is actually string object. */ + { + pdf_add_stream(pdfcharset, "/", 1); + pdf_add_stream(pdfcharset, achar_name, strlen(achar_name)); + } } for (i = 0; i < num_glyphs; i++) { @@ -755,11 +759,16 @@ pdf_font_load_type1 (pdf_font *font) break; } if (i == num_glyphs) { - if (verbose > 2) + if (dpx_conf.verbose_level > 2) dpx_message("/%s", bchar_name); GIDMap[num_glyphs++] = bchar_gid; charset->data.glyphs[charset->num_entries] = cff_get_seac_sid(cffont, bchar_name); charset->num_entries += 1; + /* CharSet is actually string object. */ + { + pdf_add_stream(pdfcharset, "/", 1); + pdf_add_stream(pdfcharset, achar_name, strlen(achar_name)); + } } } widths[gid] = gm.wx; @@ -777,7 +786,7 @@ pdf_font_load_type1 (pdf_font *font) cffont->charsets = charset; } - if (verbose > 2) + if (dpx_conf.verbose_level > 2) dpx_message("]"); /* Now we can update the String Index */ @@ -788,7 +797,7 @@ pdf_font_load_type1 (pdf_font *font) add_metrics(font, cffont, enc_vec, widths, num_glyphs); offset = write_fontfile(font, cffont, pdfcharset); - if (verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_message("[%u glyphs][%d bytes]", num_glyphs, offset); pdf_release_obj(pdfcharset); @@ -805,6 +814,5 @@ pdf_font_load_type1 (pdf_font *font) free(widths); free(GIDMap); - /* Maybe writing Charset is recommended for subsetted font. */ return 0; } diff --git a/tectonic/dpx-type1c.c b/tectonic/dpx-type1c.c index dacb38d1da..322dfdb85e 100644 --- a/tectonic/dpx-type1c.c +++ b/tectonic/dpx-type1c.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2008-2016 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, + Copyright (C) 2008-2018 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -46,6 +46,7 @@ #include "dpx-cff_limits.h" #include "dpx-cff_types.h" #include "dpx-cs_type2.h" +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" #include "dpx-error.h" #include "dpx-mem.h" @@ -248,12 +249,9 @@ pdf_font_load_type1c (pdf_font *font) cs_ginfo ginfo; double nominal_width, default_width, notdef_width; double widths[256]; - int verbose; assert(font); - verbose = pdf_font_get_verbose(); - if (!pdf_font_is_in_use(font)) { return 0; } @@ -427,7 +425,7 @@ pdf_font_load_type1c (pdf_font *font) /* First we add .notdef glyph. * All Type 1 font requires .notdef glyph to be present. */ - if (verbose > 2) { + if (dpx_conf.verbose_level > 2) { dpx_message("[glyphs:/.notdef"); } size = cs_idx->offset[1] - cs_idx->offset[0]; @@ -501,7 +499,7 @@ pdf_font_load_type1c (pdf_font *font) pdf_add_stream(pdfcharset, "/", 1); pdf_add_stream(pdfcharset, enc_vec[code], strlen(enc_vec[code])); - if (verbose > 2) { + if (dpx_conf.verbose_level > 2) { dpx_message("/%s", enc_vec[code]); } @@ -527,7 +525,7 @@ pdf_font_load_type1c (pdf_font *font) charset->num_entries += 1; num_glyphs++; } - if (verbose > 2) { + if (dpx_conf.verbose_level > 2) { dpx_message("]"); } free(data); @@ -713,7 +711,7 @@ pdf_font_load_type1c (pdf_font *font) sfnt_close(sfont); ttstub_input_close(handle); - if (verbose > 1) { + if (dpx_conf.verbose_level > 1) { dpx_message("[%u/%u glyphs][%d bytes]", num_glyphs, cs_count, offset); } diff --git a/tectonic/dpx-unicode.c b/tectonic/dpx-unicode.c index 3221ae47ac..947620a7b7 100644 --- a/tectonic/dpx-unicode.c +++ b/tectonic/dpx-unicode.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -71,7 +71,7 @@ UC_UTF16BE_is_valid_string (const unsigned char *p, const unsigned char *endptr) bool UC_UTF8_is_valid_string (const unsigned char *p, const unsigned char *endptr) { - if (p + 1 >= endptr) + if (p >= endptr) return false; while (p < endptr) { int32_t ucv = UC_UTF8_decode_char(&p, endptr); @@ -116,7 +116,7 @@ UC_UTF16BE_encode_char (int32_t ucv, unsigned char **pp, unsigned char *endptr) unsigned char *p = *pp; if (ucv >= 0 && ucv <= 0xFFFF) { - if (p + 2 >= endptr) + if (p + 2 > endptr) return 0; p[0] = (ucv >> 8) & 0xff; p[1] = ucv & 0xff; @@ -124,7 +124,7 @@ UC_UTF16BE_encode_char (int32_t ucv, unsigned char **pp, unsigned char *endptr) } else if (ucv >= 0x010000 && ucv <= 0x10FFFF) { unsigned short high, low; - if (p + 4 >= endptr) + if (p + 4 > endptr) return 0; ucv -= 0x00010000; high = (ucv >> UC_SUR_SHIFT) + UC_SUR_HIGH_START; @@ -135,7 +135,7 @@ UC_UTF16BE_encode_char (int32_t ucv, unsigned char **pp, unsigned char *endptr) p[3] = (low & 0xff); count = 4; } else { - if (p + 2 >= endptr) + if (p + 2 > endptr) return 0; p[0] = (UC_REPLACEMENT_CHAR >> 8) & 0xff; p[1] = (UC_REPLACEMENT_CHAR & 0xff); @@ -200,25 +200,25 @@ UC_UTF8_encode_char (int32_t ucv, unsigned char **pp, unsigned char *endptr) return 0; if (ucv < 0x7f) { - if (p >= endptr - 1) + if (p + 1 > endptr) return 0; p[0] = (unsigned char) ucv; count = 1; } else if (ucv <= 0x7ff) { - if (p >= endptr -2) + if (p + 2 > endptr) return 0; p[0] = (unsigned char) (0xc0 | (ucv >> 6)); p[1] = (unsigned char) (0x80 | (ucv & 0x3f)); count = 2; } else if (ucv <= 0xffff) { - if (p >= endptr - 3) + if (p + 3 > endptr) return 0; p[0] = (unsigned char) (0xe0 | (ucv >> 12)); p[1] = (unsigned char) (0x80 | ((ucv >> 6) & 0x3f)); p[2] = (unsigned char) (0x80 | (ucv & 0x3f)); count = 3; } else if (ucv <= 0x1fffff) { - if (p >= endptr - 4) + if (p + 4 > endptr) return 0; p[0] = (unsigned char) (0xf0 | (ucv >> 18)); p[1] = (unsigned char) (0x80 | ((ucv >> 12) & 0x3f)); @@ -226,7 +226,7 @@ UC_UTF8_encode_char (int32_t ucv, unsigned char **pp, unsigned char *endptr) p[3] = (unsigned char) (0x80 | (ucv & 0x3f)); count = 4; } else if (ucv <= 0x3ffffff) { - if (p >= endptr - 5) + if (p + 5 > endptr) return 0; p[0] = (unsigned char) (0xf8 | (ucv >> 24)); p[1] = (unsigned char) (0x80 | ((ucv >> 18) & 0x3f)); @@ -235,7 +235,7 @@ UC_UTF8_encode_char (int32_t ucv, unsigned char **pp, unsigned char *endptr) p[4] = (unsigned char) (0x80 | (ucv & 0x3f)); count = 5; } else if (ucv <= 0x7fffffff) { - if (p >= endptr - 6) + if (p + 6 > endptr) return 0; p[0] = (unsigned char) (0xfc | (ucv >> 30)); p[1] = (unsigned char) (0x80 | ((ucv >> 24) & 0x3f)); diff --git a/tectonic/dpx-vf.c b/tectonic/dpx-vf.c index 1b73500864..98a03482b3 100644 --- a/tectonic/dpx-vf.c +++ b/tectonic/dpx-vf.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -27,6 +27,7 @@ #include #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-dvi.h" #include "dpx-dvicodes.h" #include "dpx-error.h" @@ -43,13 +44,6 @@ #define TEXPT2PT (72.0/72.27) #define FW2PT (TEXPT2PT/((double)(FIX_WORD_BASE))) -static unsigned char verbose = 0; - -void vf_set_verbose(int level) -{ - verbose = level; -} - struct font_def { int32_t font_id /* id used internally in vf file */; uint32_t checksum, size, design_size; @@ -270,7 +264,7 @@ int vf_locate_font (const char *tex_name, spt_t ptsize) if (vf_handle == NULL) return -1; - if (verbose == 1) + if (dpx_conf.verbose_level > 0) fprintf (stderr, "(VF:%s", tex_name); if (num_vf_fonts >= max_vf_fonts) @@ -289,7 +283,7 @@ int vf_locate_font (const char *tex_name, spt_t ptsize) read_header(vf_handle, thisfont); process_vf_file (vf_handle, thisfont); - if (verbose) + if (dpx_conf.verbose_level > 0) fprintf (stderr, ")"); ttstub_input_close (vf_handle); @@ -391,7 +385,7 @@ static void vf_xxx (int32_t len, unsigned char **start, unsigned char *end) * Warning message from virtual font. */ if (!memcmp((char *)p, "Warning:", 8)) { - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_warning("VF:%s", p+8); } else { dvi_do_special(buffer, len); diff --git a/tectonic/dpx-vf.h b/tectonic/dpx-vf.h index e62e88541e..f7c9fc76ad 100644 --- a/tectonic/dpx-vf.h +++ b/tectonic/dpx-vf.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -29,7 +29,6 @@ #include "dpx-pdfdev.h" -void vf_set_verbose (int level); void vf_reset_global_state (void); int vf_locate_font (const char *tex_name, spt_t ptsize); void vf_set_char (int32_t ch, int vf_font); diff --git a/tectonic/teckit-Engine.cpp b/tectonic/teckit-Engine.cpp index e380403241..005d4e5b3c 100644 --- a/tectonic/teckit-Engine.cpp +++ b/tectonic/teckit-Engine.cpp @@ -403,12 +403,12 @@ Pass::Pass(const TableHeader* inTable, Converter* cnv) bSupplementaryChars = (READ(tableHeader->flags) & kTableFlags_Supplementary) != 0; numPageMaps = 1; - pageBase = (const Byte*)tableHeader + READ(tableHeader->pageBase); - lookupBase = (const Lookup*)((const Byte*)tableHeader + READ(tableHeader->lookupBase)); - matchClassBase = (const Byte*)tableHeader + READ(tableHeader->matchClassBase); - repClassBase = (const Byte*)tableHeader + READ(tableHeader->repClassBase); - stringListBase = (const Byte*)tableHeader + READ(tableHeader->stringListBase); - stringRuleData = (const Byte*)tableHeader + READ(tableHeader->stringRuleData); + pageBase = reinterpret_cast(tableHeader) + READ(tableHeader->pageBase); + lookupBase = reinterpret_cast(reinterpret_cast(tableHeader) + READ(tableHeader->lookupBase)); + matchClassBase = reinterpret_cast(tableHeader) + READ(tableHeader->matchClassBase); + repClassBase = reinterpret_cast(tableHeader) + READ(tableHeader->repClassBase); + stringListBase = reinterpret_cast(tableHeader) + READ(tableHeader->stringListBase); + stringRuleData = reinterpret_cast(tableHeader) + READ(tableHeader->stringRuleData); if (bInputIsUnicode && bSupplementaryChars) { // support supplementary plane chars @@ -583,7 +583,7 @@ binary_search(const T* array, UInt32 count, UInt32 value) long Pass::classMatch(UInt32 classNumber, UInt32 inChar) const { - const UInt32* classPtr = (const UInt32*)(matchClassBase + READ(*((const UInt32*)matchClassBase + classNumber))); + const UInt32* classPtr = reinterpret_cast(matchClassBase + READ(*(reinterpret_cast(matchClassBase) + classNumber))); UInt32 memberCount = READ(*classPtr++); if (bInputIsUnicode) { if (bSupplementaryChars) { @@ -594,16 +594,16 @@ Pass::classMatch(UInt32 classNumber, UInt32 inChar) const } else { // classes are 16-bit - const UInt16* p = binary_search((const UInt16*)classPtr, memberCount, inChar); + const UInt16* p = binary_search(reinterpret_cast(classPtr), memberCount, inChar); if (READ(*p) == inChar) - return p - (const UInt16*)classPtr; + return p - reinterpret_cast(classPtr); } } else { // classes are 8-bit - const UInt8* p = binary_search((const UInt8*)classPtr, memberCount, inChar); + const UInt8* p = binary_search(reinterpret_cast(classPtr), memberCount, inChar); if (READ(*p) == inChar) - return p - (const UInt8*)classPtr; + return p - reinterpret_cast(classPtr); } return -1; } @@ -611,16 +611,16 @@ Pass::classMatch(UInt32 classNumber, UInt32 inChar) const UInt32 Pass::repClassMember(UInt32 classNumber, UInt32 index) const { - const UInt32* classPtr = (const UInt32*)(repClassBase + READ(*((const UInt32*)repClassBase + classNumber))); + const UInt32* classPtr = reinterpret_cast(repClassBase + READ(*(reinterpret_cast(repClassBase) + classNumber))); UInt32 memberCount = READ(*classPtr++); if (index < memberCount) if (bOutputIsUnicode) if (bSupplementaryChars) return READ(classPtr[index]); else - return READ(((const UInt16*)classPtr)[index]); + return READ(reinterpret_cast(classPtr)[index]); else { - return READ(((const UInt8*)classPtr)[index]); + return READ(reinterpret_cast(classPtr)[index]); } else return 0; // this can't happen if the compiler is right! @@ -1000,7 +1000,7 @@ Pass::DoMapping() if (bInputIsUnicode) { // Unicode lookup UInt16 charIndex = 0; - if ((const UInt8*)lookupBase == pageBase) { + if (reinterpret_cast(lookupBase) == pageBase) { // leave charIndex == 0 : pass with no rules } else { @@ -1008,7 +1008,7 @@ Pass::DoMapping() const UInt8* pageMap = 0; if (bSupplementaryChars) { if ((plane < 17) && (READ(planeMap[plane]) != 0xff)) { - pageMap = (const UInt8*)(pageBase + 256 * READ(planeMap[plane])); + pageMap = reinterpret_cast(pageBase + 256 * READ(planeMap[plane])); goto GOT_PAGE_MAP; } } @@ -1017,7 +1017,7 @@ Pass::DoMapping() GOT_PAGE_MAP: UInt8 page = (inChar >> 8) & 0xff; if (READ(pageMap[page]) != 0xff) { - const UInt16* charMapBase = (const UInt16*)(pageBase + 256 * numPageMaps); + const UInt16* charMapBase = reinterpret_cast(pageBase + 256 * numPageMaps); const UInt16* charMap = charMapBase + 256 * READ(pageMap[page]); charIndex = READ(charMap[inChar & 0xff]); } @@ -1027,7 +1027,7 @@ Pass::DoMapping() } else { // byte-oriented lookup - if (pageBase != (const Byte*)tableHeader) { + if (pageBase != reinterpret_cast(tableHeader)) { // dbcsPage present long pageNumber = READ(pageBase[inChar]); if (pageNumber == 0) @@ -1057,14 +1057,14 @@ Pass::DoMapping() UInt8 ruleType = READ(lookup->rules.type); if (ruleType == kLookupType_StringRules || (ruleType & kLookupType_RuleTypeMask) == kLookupType_ExtStringRules) { // process string rule list - const UInt32* ruleList = (const UInt32*)stringListBase + READ(lookup->rules.ruleIndex); + const UInt32* ruleList = reinterpret_cast(stringListBase) + READ(lookup->rules.ruleIndex); bool matched = false; bool allowInsertion = true; int ruleCount = READ(lookup->rules.ruleCount); if ((ruleType & kLookupType_RuleTypeMask) == kLookupType_ExtStringRules) ruleCount += 256 * (ruleType & kLookupType_ExtRuleCountMask); for ( ; ruleCount > 0; --ruleCount) { - const StringRule* rule = (const StringRule*)(stringRuleData + READ(*ruleList)); + const StringRule* rule = reinterpret_cast(stringRuleData + READ(*ruleList)); #ifdef TRACING if (traceLevel > 0) { cerr << "** trying match: "; @@ -1078,7 +1078,7 @@ if (traceLevel > 0) { if (matchElems == 0 && allowInsertion == false) continue; patternLength = matchElems + READ(rule->postLength); - pattern = (const MatchElem*)(rule + 1); // point past the defined struct for the rule header + pattern = reinterpret_cast(rule + 1); // point past the defined struct for the rule header direction = 1; infoLimit = matchElems; @@ -1119,7 +1119,7 @@ if (traceLevel > 0) { cerr << "** GENERATES:"; } #endif - const RepElem* r = (const RepElem*)(pattern + patternLength); + const RepElem* r = reinterpret_cast(pattern + patternLength); for (int i = 0; i < READ(rule->repLength); ++i, ++r) { #ifdef TRACING if (traceLevel > 0) @@ -1288,11 +1288,11 @@ Converter::Converter(const Byte* inTable, UInt32 inTableSize, bool inForward, finalStage = this; UInt16 normForm = 0; if (inTable != 0) { - const FileHeader* fh = (const FileHeader*)inTable; + const FileHeader* fh = reinterpret_cast(inTable); if (READ(fh->type) == kMagicNumberCmp) { // the table is compressed; allocate a new buffer and decompress unsigned long uncompressedLen = READ(fh->version); - table = (Byte*)malloc(uncompressedLen); + table = static_cast(malloc(uncompressedLen)); if (table == 0) { status = kStatus_OutOfMemory; return; @@ -1302,7 +1302,7 @@ Converter::Converter(const Byte* inTable, UInt32 inTableSize, bool inForward, status = kStatus_InvalidMapping; return; } - fh = (const FileHeader*)table; + fh = reinterpret_cast(table); } if (READ(fh->type) != kMagicNumber) { @@ -1315,7 +1315,7 @@ Converter::Converter(const Byte* inTable, UInt32 inTableSize, bool inForward, } if (table == 0) { - table = (Byte*)malloc(inTableSize); + table = static_cast(malloc(inTableSize)); if (table == 0) { status = kStatus_OutOfMemory; return; @@ -1323,8 +1323,8 @@ Converter::Converter(const Byte* inTable, UInt32 inTableSize, bool inForward, memcpy(table, inTable, inTableSize); } - fh = (const FileHeader*)table; - const UInt32* nameOffsets = (const UInt32*)(table + sizeof(FileHeader)); + fh = reinterpret_cast(table); + const UInt32* nameOffsets = reinterpret_cast(table + sizeof(FileHeader)); const UInt32* tableBase = nameOffsets + READ(fh->numNames); UInt32 numTables = READ(fh->numFwdTables); if (!forward) { @@ -1379,7 +1379,7 @@ Converter::Converter(const Byte* inTable, UInt32 inTableSize, bool inForward, // create the processing pipeline for (UInt32 i = 0; i < numTables; ++i) { - const TableHeader* t = (const TableHeader*)(table + READ(tableBase[i])); + const TableHeader* t = reinterpret_cast(table + READ(tableBase[i])); Stage* p = 0; switch (READ(t->type)) { case kTableType_BB: @@ -1690,7 +1690,7 @@ Converter::IsForward() const void Converter::GetFlags(UInt32& sourceFlags, UInt32& targetFlags) const { - const FileHeader* fh = (const FileHeader*)table; + const FileHeader* fh = reinterpret_cast(table); if (forward) { sourceFlags = READ(fh->formFlagsLHS); targetFlags = READ(fh->formFlagsRHS); @@ -1704,13 +1704,13 @@ Converter::GetFlags(UInt32& sourceFlags, UInt32& targetFlags) const static bool getNamePtrFromTable(const Byte* table, UInt16 nameID, const Byte*& outNamePtr, UInt32& outNameLen) { - const FileHeader* fh = (const FileHeader*)table; - const UInt32* nameOffsets = (const UInt32*)(table + sizeof(FileHeader)); + const FileHeader* fh = reinterpret_cast(table); + const UInt32* nameOffsets = reinterpret_cast(table + sizeof(FileHeader)); for (UInt32 i = 0; i < READ(fh->numNames); ++i) { - const NameRec* n = (const NameRec*)(table + READ(nameOffsets[i])); + const NameRec* n = reinterpret_cast(table + READ(nameOffsets[i])); if (READ(n->nameID) == nameID) { outNameLen = READ(n->nameLength); - outNamePtr = (const Byte*)n + sizeof(NameRec); + outNamePtr = reinterpret_cast(n) + sizeof(NameRec); return true; } } @@ -1917,7 +1917,7 @@ Converter::Validate(const Converter* cnv) if (cnv->status != kStatus_NoError) return false; if (cnv->table != 0) { - const FileHeader* fh = (const FileHeader*)cnv->table; + const FileHeader* fh = reinterpret_cast(cnv->table); if (READ(fh->type) != kMagicNumber) return false; } @@ -1940,7 +1940,7 @@ TECkit_CreateConverter( cnv = new Converter(mapping, mappingSize, mapForward, inputForm, outputForm); status = cnv->creationStatus(); if (status == kStatus_NoError) - *converter = (TECkit_Converter)cnv; + *converter = reinterpret_cast(cnv); else delete cnv; return status; @@ -1952,7 +1952,7 @@ TECkit_DisposeConverter( TECkit_Converter converter) { TECkit_Status status = kStatus_NoError; - Converter* cnv = (Converter*)converter; + Converter* cnv = reinterpret_cast(converter); if (!Converter::Validate(cnv)) status = kStatus_InvalidConverter; else @@ -1970,7 +1970,7 @@ TECkit_GetConverterName( UInt32* nameLength) { TECkit_Status status = kStatus_NoError; - Converter* cnv = (Converter*)converter; + Converter* cnv = reinterpret_cast(converter); if (!Converter::Validate(cnv)) status = kStatus_InvalidConverter; else { @@ -1994,7 +1994,7 @@ TECkit_GetConverterFlags( UInt32* targetFlags) { TECkit_Status status = kStatus_NoError; - Converter* cnv = (Converter*)converter; + Converter* cnv = reinterpret_cast(converter); if (!Converter::Validate(cnv)) status = kStatus_InvalidConverter; else @@ -2008,7 +2008,7 @@ TECkit_ResetConverter( TECkit_Converter converter) { TECkit_Status status = kStatus_NoError; - Converter* cnv = (Converter*)converter; + Converter* cnv = reinterpret_cast(converter); if (!Converter::Validate(cnv)) status = kStatus_InvalidConverter; else @@ -2030,7 +2030,7 @@ TECkit_ConvertBufferOpt( UInt32* lookaheadCount) { TECkit_Status status = kStatus_NoError; - Converter* cnv = (Converter*)converter; + Converter* cnv = reinterpret_cast(converter); if (!Converter::Validate(cnv)) status = kStatus_InvalidConverter; else @@ -2065,7 +2065,7 @@ TECkit_FlushOpt( UInt32* lookaheadCount) { TECkit_Status status = kStatus_NoError; - Converter* cnv = (Converter*)converter; + Converter* cnv = reinterpret_cast(converter); if (!Converter::Validate(cnv)) status = kStatus_InvalidConverter; else @@ -2097,12 +2097,12 @@ TECkit_GetMappingFlags( if (mapping == 0) status = kStatus_InvalidMapping; else { - const FileHeader* fh = (const FileHeader*)mapping; + const FileHeader* fh = reinterpret_cast(mapping); FileHeader header; if (READ(fh->type) == kMagicNumberCmp) { // compressed mapping, so we need to decompress enough of it to read the flags unsigned long uncompressedLen = sizeof(FileHeader); - int result = uncompress((Byte*)&header, &uncompressedLen, mapping + 2 * sizeof(UInt32), mappingSize - 2 * sizeof(UInt32)); + int result = uncompress(reinterpret_cast(&header), &uncompressedLen, mapping + 2 * sizeof(UInt32), mappingSize - 2 * sizeof(UInt32)); if (result != Z_BUF_ERROR) status = kStatus_InvalidMapping; fh = &header; @@ -2136,13 +2136,13 @@ TECkit_GetMappingName( if (mapping == 0) status = kStatus_InvalidMapping; else { - const FileHeader* fh = (const FileHeader*)mapping; + const FileHeader* fh = reinterpret_cast(mapping); FileHeader header; if (READ(fh->type) == kMagicNumberCmp) { // compressed mapping, so we need to decompress the fixed header to read the headerLength field, // and then decompress the complete header to get the names unsigned long uncompressedLen = sizeof(FileHeader); - int result = uncompress((Byte*)&header, &uncompressedLen, mapping + 2 * sizeof(UInt32), mappingSize - 2 * sizeof(UInt32)); + int result = uncompress(reinterpret_cast(&header), &uncompressedLen, mapping + 2 * sizeof(UInt32), mappingSize - 2 * sizeof(UInt32)); if (result != Z_BUF_ERROR) status = kStatus_InvalidMapping; else { @@ -2152,10 +2152,10 @@ TECkit_GetMappingName( if (buf == 0) status = kStatus_OutOfMemory; else { - result = uncompress((Byte*)buf, &uncompressedLen, mapping + 2 * sizeof(UInt32), mappingSize - 2 * sizeof(UInt32)); + result = uncompress(static_cast(buf), &uncompressedLen, mapping + 2 * sizeof(UInt32), mappingSize - 2 * sizeof(UInt32)); if (result != Z_BUF_ERROR) status = kStatus_InvalidMapping; - fh = (const FileHeader*)buf; + fh = static_cast(buf); } } } @@ -2164,7 +2164,7 @@ TECkit_GetMappingName( status = kStatus_BadMappingVersion; else { const Byte* namePtr; - if (getNamePtrFromTable((const Byte*)fh, nameID, namePtr, *nameLength)) { + if (getNamePtrFromTable(reinterpret_cast(fh), nameID, namePtr, *nameLength)) { UInt16 copyBytes = *nameLength < bufferSize ? *nameLength : bufferSize; if (copyBytes > 0) memcpy(nameBuffer, namePtr, copyBytes); diff --git a/tectonic/teckit-NormalizationData.c b/tectonic/teckit-NormalizationData.c index c8ff9ab27c..051c46c785 100644 --- a/tectonic/teckit-NormalizationData.c +++ b/tectonic/teckit-NormalizationData.c @@ -2,7 +2,7 @@ const UInt8 ccPlaneMap[] = {0,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}; const UInt8 ccPageMaps[][256] = { {0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,0,0,15,0,0,0,16,17,18,19,20,21,22,0,0,23,0,0,0,0,0,0,0,0,0,0,0,24,25,0,0,26,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27,0,28,29,30,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,33,0}, - {0,34,35,36,0,0,0,0,0,0,37,0,0,0,0,0,38,39,40,41,42,43,44,45,0,0,46,0,47,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,51,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,53,0,0,0,0,0,0,0,0,0,0,0,0,0,54,0,0,0,0,0,0,0,55,56,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,34,35,36,0,0,0,0,0,0,37,0,0,38,0,39,40,41,42,43,44,45,46,47,48,49,50,0,51,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,56,57,0,0,0,0,0,0,0,0,0,0,0,0,0,58,54,59,0,0,0,0,0,60,61,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, }; @@ -12,14 +12,14 @@ const UInt8 ccCharClass[][256] = { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,230,230,230,230,220,230,230,230,222,220,230,230,230,230,230,230,220,220,220,220,220,220,230,230,220,230,230,222,228,230,10,11,12,13,14,15,16,17,18,19,19,20,21,22,0,23,0,24,25,0,230,220,0,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,230,30,31,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27,28,29,30,31,32,33,34,230,230,220,220,230,230,230,230,230,220,230,230,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,0,0,230,230,230,230,220,230,0,0,230,230,0,220,230,230,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,220,230,230,220,230,230,220,220,220,230,220,220,230,220,230,230,230,220,230,220,230,220,230,220,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,220,230,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,0,230,230,230,230,230,230,230,230,230,0,230,230,230,0,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,220,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,230,230,230,230,230,230,230,0,220,230,230,220,230,230,220,230,230,230,220,220,220,27,28,29,230,230,230,220,230,230,220,220,230,230,230,230,230}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,230,220,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,220,230,230,220,230,230,220,220,220,230,220,220,230,220,230,230,230,220,230,220,230,220,230,220,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,220,230,0,0,0,0,0,0,0,0,0,220,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,0,230,230,230,230,230,230,230,230,230,0,230,230,230,0,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,220,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,230,230,230,230,230,230,230,230,230,230,230,230,230,230,0,220,230,230,220,230,230,220,230,230,230,220,220,220,27,28,29,230,230,230,220,230,230,220,220,230,230,230,230,230}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,230,220,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,84,91,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,9,0,0,0,0,0,0,0,0,0,0,0,0,0,107,107,107,107,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,118,118,0,0,0,0,0,0,0,0,0,0,0,0,0,0,122,122,122,122,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,9,0,0,0,0,0,0,0,0,0,0,0,0,0,107,107,107,107,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,118,118,9,0,0,0,0,0,0,0,0,0,0,0,0,0,122,122,122,122,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,0,220,0,216,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,130,0,132,0,0,0,0,0,130,130,130,130,0,0,130,0,230,230,9,0,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, @@ -45,23 +45,28 @@ const UInt8 ccCharClass[][256] = { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,220,0,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,1,220,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,220,230,230,230,220,230,220,220,220,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,0,0,0,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,0,0,0,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,216,216,1,1,1,0,0,0,226,216,216,216,216,216,0,0,0,0,0,0,0,0,220,220,220,220,220,220,220,220,0,0,230,230,230,230,230,220,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {230,230,230,230,230,230,230,0,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,0,0,230,230,230,230,230,230,230,0,230,230,0,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,220,220,220,220,220,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, }; diff --git a/tectonic/teckit-c-Engine.h b/tectonic/teckit-c-Engine.h index e7f0484cd9..8e5a02d191 100644 --- a/tectonic/teckit-c-Engine.h +++ b/tectonic/teckit-c-Engine.h @@ -32,16 +32,16 @@ Last reviewed: Not yet. #include "teckit-Common.h" /* formFlags bits for normalization; if none are set, then this side of the mapping is normalization-form-agnostic on input, and may generate an unspecified mixture */ -#define kFlags_ExpectsNFC 0x00000001 /* expects fully composed text (NC) */ -#define kFlags_ExpectsNFD 0x00000002 /* expects fully decomposed text (NCD) */ -#define kFlags_GeneratesNFC 0x00000004 /* generates fully composed text (NC) */ -#define kFlags_GeneratesNFD 0x00000008 /* generates fully decomposed text (NCD) */ +#define kFlags_ExpectsNFC 0x00000001U /* expects fully composed text (NC) */ +#define kFlags_ExpectsNFD 0x00000002U /* expects fully decomposed text (NCD) */ +#define kFlags_GeneratesNFC 0x00000004U /* generates fully composed text (NC) */ +#define kFlags_GeneratesNFD 0x00000008U /* generates fully decomposed text (NCD) */ /* if VisualOrder is set, this side of the mapping deals with visual-order rather than logical-order text (only relevant for bidi scripts) */ -#define kFlags_VisualOrder 0x00008000 /* visual rather than logical order */ +#define kFlags_VisualOrder 0x00008000U /* visual rather than logical order */ /* if Unicode is set, the encoding is Unicode on this side of the mapping */ -#define kFlags_Unicode 0x00010000 /* this is Unicode rather than a byte encoding */ +#define kFlags_Unicode 0x00010000U /* this is Unicode rather than a byte encoding */ /* required names */ #define kNameID_LHS_Name 0 /* "source" or LHS encoding name, e.g. "SIL-EEG_URDU-2001" */ diff --git a/tectonic/xetex-XeTeXFontMgr.cpp b/tectonic/xetex-XeTeXFontMgr.cpp index e1876f078b..4366a9fea5 100644 --- a/tectonic/xetex-XeTeXFontMgr.cpp +++ b/tectonic/xetex-XeTeXFontMgr.cpp @@ -105,7 +105,7 @@ XeTeXFontMgr::findFont(const char* name, char* variant, double ptSize) { std::string nameStr(name); Font* font = NULL; - int dsize = 100; + double dsize = 10.0; loaded_font_design_size = 655360L; for (int pass = 0; pass < 2; ++pass) { @@ -113,7 +113,7 @@ XeTeXFontMgr::findFont(const char* name, char* variant, double ptSize) std::map::iterator i = m_nameToFont.find(nameStr); if (i != m_nameToFont.end()) { font = i->second; - if (font->opSizeInfo.designSize != 0) + if (font->opSizeInfo.designSize != 0.0) dsize = font->opSizeInfo.designSize; break; } @@ -128,7 +128,7 @@ XeTeXFontMgr::findFont(const char* name, char* variant, double ptSize) i = f->second->styles->find(style); if (i != f->second->styles->end()) { font = i->second; - if (font->opSizeInfo.designSize != 0) + if (font->opSizeInfo.designSize != 0.0) dsize = font->opSizeInfo.designSize; break; } @@ -139,7 +139,7 @@ XeTeXFontMgr::findFont(const char* name, char* variant, double ptSize) i = m_psNameToFont.find(nameStr); if (i != m_psNameToFont.end()) { font = i->second; - if (font->opSizeInfo.designSize != 0) + if (font->opSizeInfo.designSize != 0.0) dsize = font->opSizeInfo.designSize; break; } @@ -372,9 +372,8 @@ XeTeXFontMgr::findFont(const char* name, char* variant, double ptSize) // if there's optical size info, try to apply it if (ptSize < 0.0) - ptSize = dsize / 10.0; + ptSize = dsize; if (font != NULL && font->opSizeInfo.subFamilyID != 0 && ptSize > 0.0) { - ptSize = ptSize * 10.0; // convert to decipoints for comparison with the opSize values double bestMismatch = my_fmax(font->opSizeInfo.minSize - ptSize, ptSize - font->opSizeInfo.maxSize); if (bestMismatch > 0.0) { Font* bestMatch = font; @@ -393,8 +392,8 @@ XeTeXFontMgr::findFont(const char* name, char* variant, double ptSize) } } - if (font != NULL && font->opSizeInfo.designSize != 0) - loaded_font_design_size = (font->opSizeInfo.designSize << 16L) / 10; + if (font != NULL && font->opSizeInfo.designSize != 0.0) + loaded_font_design_size = unsigned(font->opSizeInfo.designSize * 65536.0 + 0.5); if (get_tracing_fonts_state() > 0) { begin_diagnostic(); @@ -469,15 +468,21 @@ XeTeXFontMgr::getOpSize(XeTeXFont font) hb_face_t *face = hb_font_get_face(hbFont); OpSizeRec *pSizeRec = (OpSizeRec*) xmalloc(sizeof(OpSizeRec)); + unsigned int designSize, minSize, maxSize; bool ok = hb_ot_layout_get_size_params(face, - &pSizeRec->designSize, + &designSize, &pSizeRec->subFamilyID, &pSizeRec->nameCode, - &pSizeRec->minSize, - &pSizeRec->maxSize); - - if (ok) + &minSize, + &maxSize); + + if (ok) { + // Convert sizes from PostScript deci-points to TeX points + pSizeRec->designSize = designSize * 72.27 / 72.0 / 10.0; + pSizeRec->minSize = minSize * 72.27 / 72.0 / 10.0; + pSizeRec->maxSize = maxSize * 72.27 / 72.0 / 10.0; return pSizeRec; + } free(pSizeRec); return NULL; @@ -492,7 +497,8 @@ XeTeXFontMgr::getDesignSize(XeTeXFont font) if (pSizeRec == NULL) return 10.0; - double result = pSizeRec->designSize / 10.0; + /* Tectonic: make sure not to leak pSizeRec */ + double result = pSizeRec->designSize; free(pSizeRec); return result; } @@ -510,8 +516,9 @@ XeTeXFontMgr::getOpSizeRecAndStyleFlags(Font* theFont) theFont->opSizeInfo.designSize = pSizeRec->designSize; if (pSizeRec->subFamilyID == 0 && pSizeRec->nameCode == 0 - && pSizeRec->minSize == 0 - && pSizeRec->maxSize == 0) { + && pSizeRec->minSize == 0.0 + && pSizeRec->maxSize == 0.0) { + /* Tectonic: make sure not to leak pSizeRec */ free(pSizeRec); goto done_size; // feature is valid, but no 'size' range } diff --git a/tectonic/xetex-XeTeXFontMgr.h b/tectonic/xetex-XeTeXFontMgr.h index 61f0c9bba5..5d7d59bd4b 100644 --- a/tectonic/xetex-XeTeXFontMgr.h +++ b/tectonic/xetex-XeTeXFontMgr.h @@ -97,11 +97,11 @@ class XeTeXFontMgr class Family; struct OpSizeRec { - unsigned int designSize; + double designSize; + double minSize; + double maxSize; unsigned int subFamilyID; unsigned int nameCode; - unsigned int minSize; - unsigned int maxSize; }; class Font { @@ -112,7 +112,7 @@ class XeTeXFontMgr , fontRef(ref), weight(0), width(0), slant(0) , isReg(false), isBold(false), isItalic(false) { opSizeInfo.subFamilyID = 0; - opSizeInfo.designSize = 100; } /* default to 10bp */ + opSizeInfo.designSize = 10.0; } /* default to 10.0pt */ ~Font() { delete m_fullName; delete m_psName; } diff --git a/tectonic/xetex-XeTeXLayoutInterface.cpp b/tectonic/xetex-XeTeXLayoutInterface.cpp index 2241efe946..19b8dd4d45 100644 --- a/tectonic/xetex-XeTeXLayoutInterface.cpp +++ b/tectonic/xetex-XeTeXLayoutInterface.cpp @@ -39,8 +39,11 @@ authorization from the copyright holders. #include #include +#include #include +#if !HB_VERSION_ATLEAST(2,5,0) #include +#endif #include #include "xetex-web.h" @@ -732,6 +735,7 @@ deleteLayoutEngine(XeTeXLayoutEngine engine) delete engine; } +#if !HB_VERSION_ATLEAST(2,5,0) static unsigned int _decompose_compat(hb_unicode_funcs_t* ufuncs, hb_codepoint_t u, @@ -748,8 +752,7 @@ _get_unicode_funcs(void) hb_unicode_funcs_set_decompose_compatibility_func(ufuncs, _decompose_compat, NULL, NULL); return ufuncs; } - -static hb_unicode_funcs_t* hbUnicodeFuncs = NULL; +#endif int layoutChars(XeTeXLayoutEngine engine, uint16_t chars[], int32_t offset, int32_t count, int32_t max, @@ -770,11 +773,15 @@ layoutChars(XeTeXLayoutEngine engine, uint16_t chars[], int32_t offset, int32_t script = hb_ot_tag_to_script (engine->script); + hb_buffer_reset(engine->hbBuffer); + +#if !HB_VERSION_ATLEAST(2,5,0) + static hb_unicode_funcs_t* hbUnicodeFuncs = NULL; if (hbUnicodeFuncs == NULL) hbUnicodeFuncs = _get_unicode_funcs(); - - hb_buffer_reset(engine->hbBuffer); hb_buffer_set_unicode_funcs(engine->hbBuffer, hbUnicodeFuncs); +#endif + hb_buffer_add_utf16(engine->hbBuffer, chars, max, offset, count); hb_buffer_set_direction(engine->hbBuffer, direction); hb_buffer_set_script(engine->hbBuffer, script); diff --git a/tectonic/xetex-constants.h b/tectonic/xetex-constants.h index ad858d20b1..39a7100d71 100644 --- a/tectonic/xetex-constants.h +++ b/tectonic/xetex-constants.h @@ -82,9 +82,11 @@ #define FROZEN_DONT_EXPAND (FROZEN_CONTROL_SEQUENCE + 9) #define FROZEN_SPECIAL (FROZEN_CONTROL_SEQUENCE + 10) #define FROZEN_PRIMITIVE (FROZEN_CONTROL_SEQUENCE + 11) -#define FROZEN_NULL_FONT (FROZEN_CONTROL_SEQUENCE + 12) +#define PRIM_SIZE 500 +#define FROZEN_NULL_FONT (FROZEN_CONTROL_SEQUENCE + 12 + PRIM_SIZE) #define FONT_ID_BASE FROZEN_NULL_FONT /* nominally minus FONT_BASE, but that's 0 */ #define UNDEFINED_CONTROL_SEQUENCE (FROZEN_NULL_FONT + MAX_FONT_MAX + 1) +#define PRIM_EQTB_BASE (FROZEN_PRIMITIVE + 1) #define GLUE_BASE (UNDEFINED_CONTROL_SEQUENCE + 1) /* "region 3": glue values */ @@ -600,62 +602,70 @@ #define INT_VAL 0 #define DIMEN_VAL 1 #define GLUE_VAL 2 -#define MU_VAL 3 #define LAST_NODE_TYPE_CODE 3 #define INPUT_LINE_NO_CODE 4 #define BADNESS_CODE 5 -#define ETEX_VERSION_CODE 6 -#define CURRENT_GROUP_LEVEL_CODE 7 -#define CURRENT_GROUP_TYPE_CODE 8 -#define CURRENT_IF_LEVEL_CODE 9 -#define CURRENT_IF_TYPE_CODE 10 -#define CURRENT_IF_BRANCH_CODE 11 -#define GLUE_STRETCH_ORDER_CODE 12 -#define GLUE_SHRINK_ORDER_CODE 13 -#define XETEX_VERSION_CODE 14 -#define XETEX_COUNT_GLYPHS_CODE 15 -#define XETEX_COUNT_VARIATIONS_CODE 16 -#define XETEX_VARIATION_CODE 17 -#define XETEX_FIND_VARIATION_BY_NAME_CODE 18 -#define XETEX_VARIATION_MIN_CODE 19 -#define XETEX_VARIATION_MAX_CODE 20 -#define XETEX_VARIATION_DEFAULT_CODE 21 -#define XETEX_COUNT_FEATURES_CODE 22 -#define XETEX_FEATURE_CODE_CODE 23 -#define XETEX_FIND_FEATURE_BY_NAME_CODE 24 -#define XETEX_IS_EXCLUSIVE_FEATURE_CODE 25 -#define XETEX_COUNT_SELECTORS_CODE 26 -#define XETEX_SELECTOR_CODE_CODE 27 -#define XETEX_FIND_SELECTOR_BY_NAME_CODE 28 -#define XETEX_IS_DEFAULT_SELECTOR_CODE 29 -#define XETEX_OT_COUNT_SCRIPTS_CODE 30 -#define XETEX_OT_COUNT_LANGUAGES_CODE 31 -#define XETEX_OT_COUNT_FEATURES_CODE 32 -#define XETEX_OT_SCRIPT_CODE 33 -#define XETEX_OT_LANGUAGE_CODE 34 -#define XETEX_OT_FEATURE_CODE 35 -#define XETEX_MAP_CHAR_TO_GLYPH_CODE 36 -#define XETEX_GLYPH_INDEX_CODE 37 -#define XETEX_FONT_TYPE_CODE 38 -#define XETEX_FIRST_CHAR_CODE 39 -#define XETEX_LAST_CHAR_CODE 40 -#define PDF_LAST_X_POS_CODE 41 -#define PDF_LAST_Y_POS_CODE 42 -#define PDF_SHELL_ESCAPE_CODE 45 -#define XETEX_PDF_PAGE_COUNT_CODE 46 -#define XETEX_GLYPH_BOUNDS_CODE 47 -#define FONT_CHAR_WD_CODE 48 -#define FONT_CHAR_HT_CODE 49 -#define FONT_CHAR_DP_CODE 50 -#define FONT_CHAR_IC_CODE 51 -#define PAR_SHAPE_LENGTH_CODE 52 -#define PAR_SHAPE_INDENT_CODE 53 -#define PAR_SHAPE_DIMEN_CODE 54 -#define GLUE_STRETCH_CODE 55 -#define GLUE_SHRINK_CODE 56 -#define MU_TO_GLUE_CODE 57 -#define GLUE_TO_MU_CODE 58 -#define ETEX_EXPR 59 +#define PDF_LAST_X_POS_CODE 12 +#define PDF_LAST_Y_POS_CODE 13 +#define ELAPSED_TIME_CODE 16 +#define PDF_SHELL_ESCAPE_CODE 17 +#define RANDOM_SEED_CODE 18 +#define ETEX_VERSION_CODE 19 +#define CURRENT_GROUP_LEVEL_CODE 20 +#define CURRENT_GROUP_TYPE_CODE 21 +#define CURRENT_IF_LEVEL_CODE 22 +#define CURRENT_IF_TYPE_CODE 23 +#define CURRENT_IF_BRANCH_CODE 24 +#define GLUE_STRETCH_ORDER_CODE 25 +#define GLUE_SHRINK_ORDER_CODE 26 +#define XETEX_INT 27 /* base number for XeTeX special integer codes */ +#define XETEX_VERSION_CODE 27 +#define XETEX_COUNT_GLYPHS_CODE 28 +#define XETEX_COUNT_VARIATIONS_CODE 29 +#define XETEX_VARIATION_CODE 30 +#define XETEX_FIND_VARIATION_BY_NAME_CODE 31 +#define XETEX_VARIATION_MIN_CODE 32 +#define XETEX_VARIATION_MAX_CODE 33 +#define XETEX_VARIATION_DEFAULT_CODE 34 +#define XETEX_COUNT_FEATURES_CODE 35 +#define XETEX_FEATURE_CODE_CODE 36 +#define XETEX_FIND_FEATURE_BY_NAME_CODE 37 +#define XETEX_IS_EXCLUSIVE_FEATURE_CODE 38 +#define XETEX_COUNT_SELECTORS_CODE 39 +#define XETEX_SELECTOR_CODE_CODE 40 +#define XETEX_FIND_SELECTOR_BY_NAME_CODE 41 +#define XETEX_IS_DEFAULT_SELECTOR_CODE 42 +#define XETEX_OT_COUNT_SCRIPTS_CODE 43 +#define XETEX_OT_COUNT_LANGUAGES_CODE 44 +#define XETEX_OT_COUNT_FEATURES_CODE 45 +#define XETEX_OT_SCRIPT_CODE 46 +#define XETEX_OT_LANGUAGE_CODE 47 +#define XETEX_OT_FEATURE_CODE 48 +#define XETEX_MAP_CHAR_TO_GLYPH_CODE 49 +#define XETEX_GLYPH_INDEX_CODE 50 +#define XETEX_FONT_TYPE_CODE 51 +#define XETEX_FIRST_CHAR_CODE 52 +#define XETEX_LAST_CHAR_CODE 53 +#define XETEX_PDF_PAGE_COUNT_CODE 54 +#define XETEX_LAST_ITEM_CODES XETEX_PDF_PAGE_COUNT_CODE /*54*/ +#define XETEX_DIM (XETEX_LAST_ITEM_CODES + 1) /*55*/ +#define XETEX_GLYPH_BOUNDS_CODE (XETEX_DIM + 0) /*55*/ +#define XETEX_LAST_DIM_CODES XETEX_GLYPH_BOUNDS_CODE /*55*/ +#define ETEX_DIM (XETEX_LAST_DIM_CODES + 1) /*56*/ +#define ETEX_GLUE (ETEX_DIM + 9) /*65*/ +#define ETEX_MU (ETEX_GLUE + 1) /*66*/ +#define FONT_CHAR_WD_CODE 56 +#define FONT_CHAR_HT_CODE 57 +#define FONT_CHAR_DP_CODE 58 +#define FONT_CHAR_IC_CODE 59 +#define PAR_SHAPE_LENGTH_CODE 60 +#define PAR_SHAPE_INDENT_CODE 61 +#define PAR_SHAPE_DIMEN_CODE 62 +#define GLUE_STRETCH_CODE 63 +#define GLUE_SHRINK_CODE 64 +#define MU_TO_GLUE_CODE 65 +#define GLUE_TO_MU_CODE 66 +#define ETEX_EXPR 67 /* = ETEX_MU + 1 */ /* args to CONVERT -- also heavily overloaded */ #define NUMBER_CODE 0 @@ -663,19 +673,26 @@ #define STRING_CODE 2 #define MEANING_CODE 3 #define FONT_NAME_CODE 4 -#define ETEX_REVISION_CODE 5 -#define XETEX_REVISION_CODE 6 -#define XETEX_VARIATION_NAME_CODE 7 -#define XETEX_FEATURE_NAME_CODE 8 -#define XETEX_SELECTOR_NAME_CODE 9 -#define XETEX_GLYPH_NAME_CODE 10 -#define LEFT_MARGIN_KERN_CODE 11 -#define RIGHT_MARGIN_KERN_CODE 12 -#define XETEX_UCHAR_CODE 13 -#define XETEX_UCHARCAT_CODE 14 -#define JOB_NAME_CODE 15 -#define PDF_STRCMP_CODE 43 -#define PDF_MDFIVE_SUM_CODE 44 +#define ETEX_REVISION_CODE 5 /* = ETEX_CONVERT_BASE */ +#define EXPANDED_CODE 6 /* = ETEX_CONVERT_CODES */ +#define LEFT_MARGIN_KERN_CODE 16 +#define RIGHT_MARGIN_KERN_CODE 17 +#define PDF_STRCMP_CODE 18 +#define PDF_CREATION_DATE_CODE 22 +#define PDF_FILE_MOD_DATE_CODE 23 +#define PDF_FILE_SIZE_CODE 24 +#define PDF_MDFIVE_SUM_CODE 25 +#define PDF_FILE_DUMP_CODE 26 +#define UNIFORM_DEVIATE_CODE 29 +#define NORMAL_DEVIATE_CODE 30 +#define XETEX_VARIATION_NAME_CODE 32 +#define XETEX_REVISION_CODE 33 +#define XETEX_FEATURE_NAME_CODE 35 +#define XETEX_SELECTOR_NAME_CODE 36 +#define XETEX_GLYPH_NAME_CODE 37 +#define XETEX_UCHAR_CODE 38 +#define XETEX_UCHARCAT_CODE 39 +#define JOB_NAME_CODE 40 /* args to IF_TEST */ #define IF_CHAR_CODE 0 @@ -779,7 +796,9 @@ #define IMMEDIATE_CODE 4 #define SET_LANGUAGE_CODE 5 #define PDFTEX_FIRST_EXTENSION_CODE 6 -#define PDF_SAVE_POS_NODE 6 +#define PDF_SAVE_POS_NODE (PDFTEX_FIRST_EXTENSION_CODE + 15) +#define RESET_TIMER_CODE (PDFTEX_FIRST_EXTENSION_CODE + 25) +#define SET_RANDOM_SEED_CODE (PDFTEX_FIRST_EXTENSION_CODE + 27) #define PIC_FILE_CODE 41 /* not to be confused with PIC_NODE = 43! */ #define PDF_FILE_CODE 42 /* not to be confused with PDF_NODE = 44! */ #define GLYPH_CODE 43 /* not to be confused with GLYPH_NODE = 42! */ @@ -887,6 +906,7 @@ #define MATH_SHIFT 3 #define SPACE_ADJUSTMENT 3 #define SUB_MLIST 3 +#define MU_VAL 3 #define IDENT_VAL 4 #define MATH_TEXT_CHAR 4 #define RESTORE_SA 4 @@ -922,15 +942,11 @@ #define VRULE 35 #define FRACTIONNUMERATORGAPMIN 36 #define FRACTIONNUMDISPLAYSTYLEGAPMIN 37 -#define XETEX_FIRST_CHAR_CODE 39 #define FRACTIONDENOMINATORGAPMIN 39 #define FRACTIONDENOMDISPLAYSTYLEGAPMIN 40 -#define XETEX_DIM 47 #define RADICALVERTICALGAP 49 #define RADICALDISPLAYSTYLEVERTICALGAP 50 #define RADICALRULETHICKNESS 51 -#define ETEX_GLUE 57 -#define ETEX_MU 58 #define COND_MATH_GLUE 98 #define MU_GLUE 99 #define MAX_COMMAND 102 diff --git a/tectonic/xetex-ini.c b/tectonic/xetex-ini.c index 0bff9bdc77..6b5b1f6e11 100644 --- a/tectonic/xetex-ini.c +++ b/tectonic/xetex-ini.c @@ -78,6 +78,11 @@ unsigned char help_ptr; bool use_err_help; bool arith_error; scaled_t tex_remainder; +int32_t randoms[55]; +unsigned char j_random; +scaled_t random_seed; +int32_t two_to_the[31]; +int32_t spec_log[29]; int32_t temp_ptr; memory_word *mem; int32_t lo_mem_max; @@ -111,7 +116,6 @@ bool no_new_control_sequence; int32_t cs_count; b32x2 prim[501]; int32_t prim_used; -memory_word prim_eqtb[501]; memory_word *save_stack; int32_t save_ptr; int32_t max_save_stack; @@ -222,6 +226,8 @@ int32_t dead_cycles; bool doing_leaders; scaled_t rule_ht, rule_dp, rule_wd; scaled_t cur_h, cur_v; +int32_t epochseconds; +int32_t microseconds; scaled_t total_stretch[4], total_shrink[4]; int32_t last_badness; int32_t adjust_tail; @@ -607,9 +613,9 @@ primitive(const char* ident, uint16_t c, int32_t o) eqtb[cur_val].b16.s0 = LEVEL_ONE; eqtb[cur_val].b16.s1 = c; eqtb[cur_val].b32.s1 = o; - prim_eqtb[prim_val].b16.s0 = LEVEL_ONE; - prim_eqtb[prim_val].b16.s1 = c; - prim_eqtb[prim_val].b32.s1 = o; + eqtb[PRIM_EQTB_BASE + prim_val].b16.s0 = LEVEL_ONE; + eqtb[PRIM_EQTB_BASE + prim_val].b16.s1 = c; + eqtb[PRIM_EQTB_BASE + prim_val].b32.s1 = o; } /*:925*//*977: */ @@ -2303,9 +2309,6 @@ store_fmt_file(void) for (p = 0; p <= PRIM_SIZE; p++) dump_b32(prim[p]); - for (p = 0; p <= PRIM_SIZE; p++) - dump_b64(prim_eqtb[p]); - /* control sequences */ dump_int(hash_used); @@ -2714,9 +2717,6 @@ load_fmt_file(void) for (p = 0; p <= PRIM_SIZE; p++) undump_b32(prim[p]); - for (p = 0; p <= PRIM_SIZE; p++) - undump_b64(prim_eqtb[p]); - undump_int(x); if (x < HASH_BASE || x > FROZEN_CONTROL_SEQUENCE) goto bad_fmt; @@ -3087,6 +3087,27 @@ initialize_more_variables(void) help_ptr = 0; use_err_help = false; + two_to_the[0] = 1; + for (k = 1; k <= 30; k++) + two_to_the[k] = 2 * two_to_the[k - 1]; + + spec_log[1] = 93032640L; + spec_log[2] = 38612034L; + spec_log[3] = 17922280L; + spec_log[4] = 8662214L; + spec_log[5] = 4261238L; + spec_log[6] = 2113709L; + spec_log[7] = 1052693L; + spec_log[8] = 525315L; + spec_log[9] = 262400L; + spec_log[10] = 131136L; + spec_log[11] = 65552L; + spec_log[12] = 32772L; + spec_log[13] = 16385; + for (k = 14; k <= 27; k++) + spec_log[k] = two_to_the[27 - k]; + spec_log[28] = 1; + nest_ptr = 0; max_nest_stack = 0; cur_list.mode = VMODE; @@ -3102,6 +3123,7 @@ initialize_more_variables(void) last_glue = MAX_HALFWORD; last_penalty = 0; last_kern = 0; + last_node_type = -1; page_so_far[7] = 0; for (k = INT_BASE; k <= EQTB_SIZE; k++) @@ -3114,13 +3136,6 @@ initialize_more_variables(void) for (k = 1; k <= PRIM_SIZE; k++) prim[k] = prim[0]; - prim_eqtb[0].b16.s0 = LEVEL_ZERO; - prim_eqtb[0].b16.s1 = UNDEFINED_CS; - prim_eqtb[0].b32.s1 = TEX_NULL; - - for (k = 1; k <= PRIM_SIZE; k++) - prim_eqtb[k] = prim_eqtb[0]; - save_ptr = 0; cur_level = LEVEL_ONE; cur_group = BOTTOM_LEVEL; @@ -3615,15 +3630,29 @@ initialize_primitives(void) primitive("lastskip", LAST_ITEM, GLUE_VAL); primitive("inputlineno", LAST_ITEM, INPUT_LINE_NO_CODE); primitive("badness", LAST_ITEM, BADNESS_CODE); + primitive("pdflastxpos", LAST_ITEM, PDF_LAST_X_POS_CODE); + primitive("pdflastypos", LAST_ITEM, PDF_LAST_Y_POS_CODE); + primitive("elapsedtime", LAST_ITEM, ELAPSED_TIME_CODE); + primitive("shellescape", LAST_ITEM, PDF_SHELL_ESCAPE_CODE); + primitive("randomseed", LAST_ITEM, RANDOM_SEED_CODE); primitive("number", CONVERT, NUMBER_CODE); primitive("romannumeral", CONVERT, ROMAN_NUMERAL_CODE); primitive("string", CONVERT, STRING_CODE); primitive("meaning", CONVERT, MEANING_CODE); primitive("fontname", CONVERT, FONT_NAME_CODE); - primitive("jobname", CONVERT, JOB_NAME_CODE); + primitive("expanded", CONVERT, EXPANDED_CODE); primitive("leftmarginkern", CONVERT, LEFT_MARGIN_KERN_CODE); primitive("rightmarginkern", CONVERT, RIGHT_MARGIN_KERN_CODE); + primitive("creationdate", CONVERT, PDF_CREATION_DATE_CODE); + primitive("filemoddate", CONVERT, PDF_FILE_MOD_DATE_CODE); + primitive("filesize", CONVERT, PDF_FILE_SIZE_CODE); + primitive("mdfivesum", CONVERT, PDF_MDFIVE_SUM_CODE); + primitive("filedump", CONVERT, PDF_FILE_DUMP_CODE); + primitive("strcmp", CONVERT, PDF_STRCMP_CODE); + primitive("uniformdeviate", CONVERT, UNIFORM_DEVIATE_CODE); + primitive("normaldeviate", CONVERT, NORMAL_DEVIATE_CODE); + primitive("jobname", CONVERT, JOB_NAME_CODE); primitive("Uchar", CONVERT, XETEX_UCHAR_CODE); primitive("Ucharcat", CONVERT, XETEX_UCHARCAT_CODE); @@ -3838,6 +3867,8 @@ initialize_primitives(void) eqtb[FROZEN_SPECIAL] = eqtb[cur_val]; primitive("immediate", EXTENSION, IMMEDIATE_CODE); primitive("setlanguage", EXTENSION, SET_LANGUAGE_CODE); + primitive("resettimer", EXTENSION, RESET_TIMER_CODE); + primitive("setrandomseed", EXTENSION, SET_RANDOM_SEED_CODE); primitive("synctex", ASSIGN_INT, INT_BASE + INT_PAR__synctex); @@ -4087,6 +4118,9 @@ tt_run_engine(const char *dump_name, const char *input_file_name, time_t build_d initialize_pagebuilder_variables(); initialize_shipout_variables(); + get_seconds_and_micros(&epochseconds, µseconds); + init_start_time(build_date); + selector = SELECTOR_TERM_ONLY; tally = 0; term_offset = 0; @@ -4137,7 +4171,7 @@ tt_run_engine(const char *dump_name, const char *input_file_name, time_t build_d primitive("XeTeXpdffile", EXTENSION, PDF_FILE_CODE); primitive("XeTeXglyph", EXTENSION, GLYPH_CODE); primitive("XeTeXlinebreaklocale", EXTENSION, XETEX_LINEBREAK_LOCALE_EXTENSION_CODE); - primitive("pdfsavepos", EXTENSION, PDFTEX_FIRST_EXTENSION_CODE + 0); + primitive("pdfsavepos", EXTENSION, PDF_SAVE_POS_NODE); primitive("lastnodetype", LAST_ITEM, LAST_NODE_TYPE_CODE); primitive("eTeXversion", LAST_ITEM, ETEX_VERSION_CODE); @@ -4183,16 +4217,8 @@ tt_run_engine(const char *dump_name, const char *input_file_name, time_t build_d primitive("XeTeXfonttype", LAST_ITEM, XETEX_FONT_TYPE_CODE); primitive("XeTeXfirstfontchar", LAST_ITEM, XETEX_FIRST_CHAR_CODE); primitive("XeTeXlastfontchar", LAST_ITEM, XETEX_LAST_CHAR_CODE); - primitive("pdflastxpos", LAST_ITEM, PDF_LAST_X_POS_CODE); - primitive("pdflastypos", LAST_ITEM, PDF_LAST_Y_POS_CODE); - - primitive("strcmp", CONVERT, PDF_STRCMP_CODE); - primitive("mdfivesum", CONVERT, PDF_MDFIVE_SUM_CODE); - primitive("pdfmdfivesum", CONVERT, PDF_MDFIVE_SUM_CODE); - - primitive("shellescape", LAST_ITEM, PDF_SHELL_ESCAPE_CODE); primitive("XeTeXpdfpagecount", LAST_ITEM, XETEX_PDF_PAGE_COUNT_CODE); - + /* everyeof moved to be with other assign_toks */ primitive("tracingassigns", ASSIGN_INT, INT_BASE + INT_PAR__tracing_assigns); primitive("tracinggroups", ASSIGN_INT, INT_BASE + INT_PAR__tracing_groups); @@ -4395,6 +4421,9 @@ tt_run_engine(const char *dump_name, const char *input_file_name, time_t build_d for (font_k = 0; font_k <= font_max; font_k++) font_used[font_k] = false; + random_seed = (microseconds * 1000) + (epochseconds % 1000000L); + init_randoms(random_seed); + if (interaction == BATCH_MODE) selector = SELECTOR_NO_PRINT; else diff --git a/tectonic/xetex-linebreak.c b/tectonic/xetex-linebreak.c index d45a14f8cf..f338dd38b5 100644 --- a/tectonic/xetex-linebreak.c +++ b/tectonic/xetex-linebreak.c @@ -372,7 +372,10 @@ line_break(bool d) if (LC_CODE(c) != 0) { hf = NATIVE_NODE_font(s); prev_s = s; - goto done2; + if (LC_CODE(c) == c || INTPAR(uc_hyph) > 0) + goto done2; + else + goto done1; } if (c >= 65536L) diff --git a/tectonic/xetex-output.c b/tectonic/xetex-output.c index 1d8041b162..62797eb3b4 100644 --- a/tectonic/xetex-output.c +++ b/tectonic/xetex-output.c @@ -220,6 +220,8 @@ print_char(int32_t s) print_raw_char('0' + l, true); else print_raw_char('a' + l - 10, true); + } else if (selector == SELECTOR_PSEUDO) { + print_raw_char(s, true); } else { if (s < 2048) { print_raw_char(192 + s / 64, false); @@ -411,7 +413,10 @@ print_cs(int32_t p) } else if (hash[p].s1 >= str_ptr) { print_esc_cstr("NONEXISTENT."); } else { - print_esc(hash[p].s1); + if (p >= PRIM_EQTB_BASE && p < FROZEN_NULL_FONT) + print_esc(prim[p - PRIM_EQTB_BASE].s1 - 1); + else + print_esc(hash[p].s1); print_char(' '); } } @@ -429,8 +434,11 @@ sprint_cs(int32_t p) print_esc_cstr("csname"); print_esc_cstr("endcsname"); } - } else + } else if (p >= PRIM_EQTB_BASE && p < FROZEN_NULL_FONT) { + print_esc(prim[p - PRIM_EQTB_BASE].s1 - 1); + } else { print_esc(hash[p].s1); + } } diff --git a/tectonic/xetex-scaledmath.c b/tectonic/xetex-scaledmath.c index 829413bedf..98163002fc 100644 --- a/tectonic/xetex-scaledmath.c +++ b/tectonic/xetex-scaledmath.c @@ -11,11 +11,11 @@ int32_t tex_round (double r) { /* We must reproduce very particular rounding semantics to pass the TRIP - * test. Specifically, values within the 32-bit range of TeX integers are - * rounded to the nearest integer with half-integral values going away + * test. Specifically, values within the 32-bit range of TeX int32_ts are + * rounded to the nearest int32_t with half-integral values going away * from zero: 0.5 => 1, -0.5 => -1. * - * `r` does not necessarily lie within the range of a 32-bit TeX integer; + * `r` does not necessarily lie within the range of a 32-bit TeX int32_t; * if it doesn't, we clip. The following LaTeX document allegedly triggers * that codepath: * @@ -34,7 +34,7 @@ tex_round (double r) if (r < -2147483648.0) /* -0x80000000 */ return -2147483648; - /* ANSI defines the float-to-integer cast to truncate towards zero, so the + /* ANSI defines the float-to-int32_t cast to truncate towards zero, so the * following code is all that's necessary to get the desired behavior. The * truncation technically causes an uncaught "inexact" floating-point * exception, but exception is virtually impossible to avoid in real @@ -160,3 +160,354 @@ round_xn_over_d(scaled_t x, int32_t n, int32_t d) else return -(int32_t) u; } + +static int32_t +make_frac(int32_t p, int32_t q) +{ + int32_t f; + int32_t n; + bool negative; + int32_t be_careful; + + if (p >= 0) + negative = false; + else { + p = -p; + negative = true; + } + + if (q <= 0) { + q = -q; + negative = !negative; + } + + n = p / q; + p = p % q; + + if (n >= 8) { + arith_error = true; + if (negative) + return -0x7FFFFFFF; + else + return 0x7FFFFFFF; + } else { + n = (n - 1) * 0x10000000; + f = 1; + + do { + be_careful = p - q; + p = be_careful + p; + if (p >= 0) + f = f + f + 1; + else { + f = f + f; + p = p + q; + } + } while (f < 0x10000000); + + be_careful = p - q; + if (be_careful + p >= 0) + f += 1; + + if (negative) + return -(f + n); + else + return f + n; + } +} + +static int32_t +take_frac(int32_t q, int32_t f) +{ + int32_t p; + bool negative; + int32_t n; + int32_t be_careful; + + if (f >= 0) + negative = false; + else { + f = -f; + negative = true; + } + + if (q < 0) { + q = -q; + negative = !negative; + } + + if (f < 0x10000000) + n = 0; + else { + n = f / 0x10000000; + f = f % 0x10000000; + + if (q <= 0x7FFFFFFF / n) + n = n * q; + else { + arith_error = true; + n = 0x7FFFFFFF; + } + } + + f = f + 0x10000000; + p = 0x08000000; + + if (q < 0x40000000) { + do { + if (odd(f)) + p = (p + q) / 2; + else + p = p / 2; + f = f / 2; + } while (f != 1); + } else { + do { + if (odd(f)) + p = p + (q - p) / 2; + else + p = p / 2; + f = f / 2; + } while (f != 1); /*:120 */ + } + + be_careful = n - 0x7FFFFFFF; + if (be_careful + p > 0) { + arith_error = true; + n = 0x7FFFFFFF - p; + } + + if (negative) + return -(n + p); + else + return n + p; +} + +static int32_t +m_log(int32_t x) +{ + int32_t y, z; + int32_t k; + + if (x <= 0) { /*125: */ + error_here_with_diagnostic("Logarithm of "); + print_scaled(x); + print_cstr(" has been replaced by 0"); + capture_to_diagnostic(NULL); + help_ptr = 2; + help_line[1] = "Since I don't take logs of non-positive numbers,"; + help_line[0] = "I'm zeroing this one. Proceed, with fingers crossed."; + error(); + return 0; + } else { + y = 1302456860L; + z = 6581195L; + + while (x < 0x40000000) { + x = x + x; + y = y - 93032639L; + z = z - 48782L; + } + + y = y + (z / 65536L); + k = 2; + + while (x > 0x40000004) { /*124: */ + z = ((x - 1) / two_to_the[k]) + 1; + + while (x < 0x40000000 + z) { + z = (z + 1) / 2; + k = k + 1; + } + + y = y + spec_log[k]; + x = x - z; + } + + return y / 8; + } +} + +static int32_t +ab_vs_cd(int32_t a, int32_t b, int32_t c, int32_t d) +{ + int32_t q, r; + + if (a < 0) { + a = -a; + b = -b; + } + + if (c < 0) { + c = -c; + d = -d; + } + + if (d <= 0) { + if (b >= 0) { + if ((a == 0 || b == 0) && (c == 0 || d == 0)) { + return 0; + } else { + return 1; + } + } + + if (d == 0) { + if (a == 0) { + return 0; + } else { + return -1; + } + } + + q = a; + a = c; + c = q; + q = -b; + b = -d; + d = q; + } else if (b <= 0) { + if (b < 0) { + if (a > 0) { + return -1; + } + } + + if (c == 0) { + return 0; + } else { + return -1; + } + } + + while (true) { + q = a / d; + r = c / b; + + if (q != r) { + if (q > r) { + return 1; + } else { + return -1; + } + } + + q = a % d; + r = c % b; + + if (r == 0) { + if (q == 0) { + return 0; + } else { + return 1; + } + } + + if (q == 0) { + return -1; + } + + a = b; + b = q; + c = d; + d = r; + } +} + +static void +new_randoms(void) +{ + unsigned char k; + int32_t x; + + for (k = 0; k < 24; k++) { + x = randoms[k] - randoms[k + 31]; + if (x < 0) + x = x + 0x10000000; + randoms[k] = x; + } + + for (k = 24; k < 55; k++) { + x = randoms[k] - randoms[k - 24]; + if (x < 0) + x = x + 0x10000000; + randoms[k] = x; + } + + j_random = 54; +} + +void +init_randoms(int32_t seed) +{ + int32_t j, jj, k; + unsigned char i; + + j = abs(seed); + + while (j >= 0x10000000) + j = j / 2; + + k = 1; + + for (i = 0; i < 55; i++) { + jj = k; + k = j - k; + j = jj; + if (k < 0) + k = k + 0x10000000; + randoms[(i * 21) % 55] = j; + } + + new_randoms(); + new_randoms(); + new_randoms(); +} + +int32_t +unif_rand(int32_t x) +{ + int32_t y; + + if (j_random == 0) + new_randoms(); + else + j_random--; + + y = take_frac(abs(x), randoms[j_random]); + if (y == abs(x)) + return 0; + else if (x > 0) + return y; + else + return -y; +} + +int32_t +norm_rand(void) +{ + int32_t x, u, l; + + do { + do { + if (j_random == 0) + new_randoms(); + else + j_random--; + + x = take_frac(112429L, randoms[j_random] - 0x08000000); + + if (j_random == 0) + new_randoms(); + else + j_random--; + + u = randoms[j_random]; + } while (abs(x) >= u); + + x = make_frac(x, u); + l = 139548960L - m_log(u); + } while (ab_vs_cd(1024, l, x, x) < 0); + + return x; +} diff --git a/tectonic/xetex-shipout.c b/tectonic/xetex-shipout.c index 88b9578c13..49fe8ad377 100644 --- a/tectonic/xetex-shipout.c +++ b/tectonic/xetex-shipout.c @@ -782,8 +782,9 @@ hlist_out(void) break; case PDF_SAVE_POS_NODE: - pdf_last_x_pos = cur_h + cur_h_offset; - pdf_last_y_pos = cur_page_height - cur_v - cur_v_offset; + /* These magic numbers are in the original XeTeX source. */ + pdf_last_x_pos = cur_h + 4736286L; + pdf_last_y_pos = cur_page_height - cur_v - 4736286L; break; default: @@ -1282,8 +1283,9 @@ vlist_out(void) break; case PDF_SAVE_POS_NODE: - pdf_last_x_pos = cur_h + cur_h_offset; - pdf_last_y_pos = cur_page_height - cur_v - cur_v_offset; + /* These magic numbers are in the original XeTeX source. */ + pdf_last_x_pos = cur_h + 4736286L; + pdf_last_y_pos = cur_page_height - cur_v - 4736286L; break; default: diff --git a/tectonic/xetex-synctex.c b/tectonic/xetex-synctex.c index 6e3b9cdcc3..a57d5d425b 100644 --- a/tectonic/xetex-synctex.c +++ b/tectonic/xetex-synctex.c @@ -262,7 +262,8 @@ synctex_dot_open(void) /*printf("\nSyncTeX warning: no synchronization, problem with %s\n", the_name);*/ goto fail; - synctex_ctxt.magnification = 1000; + if (synctex_ctxt.magnification == 0) + synctex_ctxt.magnification = 1000; synctex_ctxt.unit = 1; the_name = mfree(the_name); @@ -403,17 +404,17 @@ void synctex_sheet(int32_t mag) } return; } + if (total_pages == 0) { + /* Now it is time to properly set up the scale factor. */ + if (mag > 0) { + synctex_ctxt.magnification = mag; + } + } if (NULL != synctex_prepare_content()) { /* First possibility: the .synctex file is already open because SyncTeX was activated on the CLI * or it was activated with the \synctex macro and the first page is already shipped out. * Second possibility: tries to open the .synctex, useful if synchronization was enabled * from the source file and not from the CLI. */ - if (total_pages == 0) { - /* Now it is time to properly set up the scale factor. */ - if (mag > 0) { - synctex_ctxt.magnification = mag; - } - } synctex_record_sheet(total_pages + 1); } return; diff --git a/tectonic/xetex-texmfmp.c b/tectonic/xetex-texmfmp.c index 0d23de7c98..e34518786c 100644 --- a/tectonic/xetex-texmfmp.c +++ b/tectonic/xetex-texmfmp.c @@ -10,11 +10,104 @@ #include "xetex-ext.h" #include /* For `struct tm'. Moved here for Visual Studio 2005. */ - +#include static char *last_source_name = NULL; static int last_lineno; +#define check_nprintf(size_get, size_want) \ + if ((unsigned)(size_get) >= (unsigned)(size_want)) \ + _tt_abort ("snprintf failed: file %s, line %d", __FILE__, __LINE__); + +/* minimum size for time_str is 24: "D:YYYYmmddHHMMSS+HH'MM'" */ +#define TIME_STR_SIZE 30 +static char start_time_str[TIME_STR_SIZE]; + +static void +makepdftime(time_t t, char *time_str, bool utc) +{ + struct tm lt, gmt; + size_t size; + int i, off, off_hours, off_mins; + + /* get the time */ + if (utc) { + lt = *gmtime(&t); + } + else { + lt = *localtime(&t); + } + size = strftime(time_str, TIME_STR_SIZE, "D:%Y%m%d%H%M%S", <); + /* expected format: "YYYYmmddHHMMSS" */ + if (size == 0) { + /* unexpected, contents of time_str is undefined */ + time_str[0] = '\0'; + return; + } + + /* correction for seconds: %S can be in range 00..61, + the PDF reference expects 00..59, + therefore we map "60" and "61" to "59" */ + if (time_str[14] == '6') { + time_str[14] = '5'; + time_str[15] = '9'; + time_str[16] = '\0'; /* for safety */ + } + + /* get the time zone offset */ + gmt = *gmtime(&t); + + /* this calculation method was found in exim's tod.c */ + off = 60 * (lt.tm_hour - gmt.tm_hour) + lt.tm_min - gmt.tm_min; + if (lt.tm_year != gmt.tm_year) { + off += (lt.tm_year > gmt.tm_year) ? 1440 : -1440; + } else if (lt.tm_yday != gmt.tm_yday) { + off += (lt.tm_yday > gmt.tm_yday) ? 1440 : -1440; + } + + if (off == 0) { + time_str[size++] = 'Z'; + time_str[size] = 0; + } else { + off_hours = off / 60; + off_mins = abs(off - off_hours * 60); + i = snprintf(&time_str[size], 9, "%+03d'%02d'", off_hours, off_mins); + check_nprintf(i, 9); + } +} + + +void +init_start_time(time_t source_date_epoch) +{ + makepdftime(source_date_epoch, start_time_str, /* utc= */true); +} + + +void +getcreationdate(void) +{ + size_t len; + int i; + + /* init_start_time(); -- Tectonic: not needed*/ + /* put creation date on top of string pool and update pool_ptr */ + len = strlen(start_time_str); + + /* In e-pTeX, "init len => call init_start_time()" (as pdftexdir/utils.c) + yields unintentional output. */ + + if ((unsigned) (pool_ptr + len) >= (unsigned) (pool_size)) { + pool_ptr = pool_size; + /* error by str_toks that calls str_room(1) */ + return; + } + + for (i = 0; i < len; i++) + str_pool[pool_ptr++] = (uint16_t)start_time_str[i]; +} + + void get_date_and_time (time_t source_date_epoch, int32_t *minutes, int32_t *day, @@ -28,6 +121,137 @@ get_date_and_time (time_t source_date_epoch, } +void +get_seconds_and_micros (int32_t *seconds, int32_t *micros) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + *seconds = tv.tv_sec; + *micros = tv.tv_usec; +} + + +/* Given a file name stored in the string pool, insert into the string pool text + * giving its modification date in PDF-style format. */ +void +getfilemoddate(str_number s) +{ + char *name; + time_t mtime; + size_t text_len; + rust_input_handle_t handle; + char buf[20]; + int i; + + name = gettexstring(s); + handle = ttstub_input_open(name, TTIF_TEX, 0); + free(name); + + if (handle == NULL) + return; /* => evaluate to the empty string; intentional */ + + mtime = ttstub_input_get_mtime(handle); + ttstub_input_close(handle); + + makepdftime(mtime, buf, /* utc= */true); + text_len = strlen(buf); + + if ((unsigned) (pool_ptr + text_len) >= (unsigned) pool_size) { + pool_ptr = pool_size; + /* error by str_toks that calls str_room(1) */ + } else { + int i; + + for (i = 0; i < text_len; i++) + str_pool[pool_ptr++] = (uint16_t) buf[i]; + } +} + +/* Given a file name stored in the string pool, insert into the string pool text + * giving its size in bytes. */ +void +getfilesize(str_number s) +{ + char *name; + size_t file_len, text_len; + rust_input_handle_t handle; + char buf[20]; + int i; + + name = gettexstring(s); + handle = ttstub_input_open(name, TTIF_TEX, 0); + free(name); + + if (handle == NULL) + return; /* => evaluate to the empty string; intentional */ + + file_len = ttstub_input_get_size(handle); + ttstub_input_close(handle); + + i = snprintf(buf, sizeof(buf), "%lu", (long unsigned int) file_len); + check_nprintf(i, sizeof(buf)); + text_len = strlen(buf); + + if ((unsigned) (pool_ptr + text_len) >= (unsigned) pool_size) { + pool_ptr = pool_size; + /* error by str_toks that calls str_room(1) */ + } else { + int i; + + for (i = 0; i < text_len; i++) + str_pool[pool_ptr++] = (uint16_t) buf[i]; + } +} + +void getfiledump(int32_t s, int offset, int length) +{ + char *name; + size_t text_len; + rust_input_handle_t handle; + unsigned char *buffer; + int i, j, k; + ssize_t actual; + char strbuf[3]; + + if (length == 0) + return; /* => evaluate to the empty string; intentional */ + + if (pool_ptr + 2 * length + 1 >= pool_size) { + /* not enough room to hold the result; trigger an error back in TeX: */ + pool_ptr = pool_size; + return; + } + + buffer = (unsigned char *) xmalloc(length + 1); + if (buffer == NULL) { + pool_ptr = pool_size; + return; + } + + name = gettexstring(s); + handle = ttstub_input_open(name, TTIF_TEX, 0); + free(name); + + if (handle == NULL) { + free(buffer); + return; /* => evaluate to the empty string; intentional */ + } + + ttstub_input_seek(handle, offset, SEEK_SET); + actual = ttstub_input_read(handle, (char *) buffer, length); + ttstub_input_close(handle); + + for (j = 0; j < actual; j++) { + i = snprintf(strbuf, 3, "%.2X", (unsigned int) buffer[j]); + check_nprintf(i, 3); + for (k = 0; k < i; k++) + str_pool[pool_ptr++] = (uint16_t) strbuf[k]; + } + + free(buffer); +} + + static void checkpool_pointer (pool_pointer pool_ptr, size_t len) { diff --git a/tectonic/xetex-xetex0.c b/tectonic/xetex-xetex0.c index 81abea2c1f..5176d44c97 100644 --- a/tectonic/xetex-xetex0.c +++ b/tectonic/xetex-xetex0.c @@ -465,6 +465,21 @@ int32_t prev_rightmost(int32_t s, int32_t e) return p; } +int32_t +get_microinterval(void) +{ + int32_t s, m; + + get_seconds_and_micros(&s, &m); + + if ((s - epochseconds) > 0x7FFF) + return -1; + else if (microseconds > m) + return ((s - 1 - epochseconds) * 65536) + (((m + 1000000L - microseconds) / 100.0) * 65536) / 10000.0; + else + return ((s - epochseconds) * 65536) + (((m - microseconds) / 100.0) * 65536) / 10000.0; +} + void short_display(int32_t p) { @@ -922,6 +937,9 @@ show_node_list(int32_t p) print_int(mem[p + 1].b16.s0); print_char(')'); break; + case PDF_SAVE_POS_NODE: + print_esc_cstr("pdfsavepos"); + break; case NATIVE_WORD_NODE: case NATIVE_WORD_NODE_AT: print_esc(hash[FONT_ID_BASE + mem[p + 4].b16.s2].s1); @@ -945,9 +963,6 @@ show_node_list(int32_t p) print_raw_char(PIC_NODE_path(p)[i], true); print('"'); break; - case PDF_SAVE_POS_NODE: - print_esc_cstr("pdfsavepos"); - break; default: print_cstr("whatsit?"); break; @@ -2686,9 +2701,6 @@ print_cmd_chr(uint16_t cmd, int32_t chr_code) case INPUT_LINE_NO_CODE: print_esc_cstr("inputlineno"); break; - case PDF_SHELL_ESCAPE_CODE: - print_esc_cstr("shellescape"); - break; case LAST_NODE_TYPE_CODE: print_esc_cstr("lastnodetype"); break; @@ -2779,12 +2791,6 @@ print_cmd_chr(uint16_t cmd, int32_t chr_code) case XETEX_LAST_CHAR_CODE: print_esc_cstr("XeTeXlastfontchar"); break; - case PDF_LAST_X_POS_CODE: - print_esc_cstr("pdflastxpos"); - break; - case PDF_LAST_Y_POS_CODE: - print_esc_cstr("pdflastypos"); - break; case XETEX_PDF_PAGE_COUNT_CODE: print_esc_cstr("XeTeXpdfpagecount"); break; @@ -2854,6 +2860,21 @@ print_cmd_chr(uint16_t cmd, int32_t chr_code) case GLUE_TO_MU_CODE: print_esc_cstr("gluetomu"); break; + case PDF_LAST_X_POS_CODE: + print_esc_cstr("pdflastxpos"); + break; + case PDF_LAST_Y_POS_CODE: + print_esc_cstr("pdflastypos"); + break; + case ELAPSED_TIME_CODE: + print_esc_cstr("elapsedtime"); + break; + case PDF_SHELL_ESCAPE_CODE: + print_esc_cstr("shellescape"); + break; + case RANDOM_SEED_CODE: + print_esc_cstr("randomseed"); + break; default: print_esc_cstr("badness"); break; @@ -2877,11 +2898,11 @@ print_cmd_chr(uint16_t cmd, int32_t chr_code) case FONT_NAME_CODE: print_esc_cstr("fontname"); break; - case PDF_STRCMP_CODE: - print_esc_cstr("strcmp"); + case ETEX_REVISION_CODE: + print_esc_cstr("eTeXrevision"); break; - case PDF_MDFIVE_SUM_CODE: - print_esc_cstr("mdfivesum"); + case EXPANDED_CODE: + print_esc_cstr("expanded"); break; case LEFT_MARGIN_KERN_CODE: print_esc_cstr("leftmarginkern"); @@ -2889,8 +2910,29 @@ print_cmd_chr(uint16_t cmd, int32_t chr_code) case RIGHT_MARGIN_KERN_CODE: print_esc_cstr("rightmarginkern"); break; - case ETEX_REVISION_CODE: - print_esc_cstr("eTeXrevision"); + case PDF_CREATION_DATE_CODE: + print_esc_cstr("creationdate"); + break; + case PDF_FILE_MOD_DATE_CODE: + print_esc_cstr("filemoddate"); + break; + case PDF_FILE_SIZE_CODE: + print_esc_cstr("filesize"); + break; + case PDF_MDFIVE_SUM_CODE: + print_esc_cstr("mdfivesum"); + break; + case PDF_FILE_DUMP_CODE: + print_esc_cstr("filedump"); + break; + case PDF_STRCMP_CODE: + print_esc_cstr("strcmp"); + break; + case UNIFORM_DEVIATE_CODE: + print_esc_cstr("uniformdeviate"); + break; + case NORMAL_DEVIATE_CODE: + print_esc_cstr("normaldeviate"); break; case XETEX_REVISION_CODE: print_esc_cstr("XeTeXrevision"); @@ -3562,6 +3604,15 @@ print_cmd_chr(uint16_t cmd, int32_t chr_code) case SET_LANGUAGE_CODE: print_esc_cstr("setlanguage"); break; + case PDF_SAVE_POS_NODE: + print_esc_cstr("pdfsavepos"); + break; + case RESET_TIMER_CODE: + print_esc_cstr("resettimer"); + break; + case SET_RANDOM_SEED_CODE: + print_esc_cstr("setrandomseed"); + break; case PIC_FILE_CODE: print_esc_cstr("XeTeXpicfile"); break; @@ -3580,9 +3631,6 @@ print_cmd_chr(uint16_t cmd, int32_t chr_code) case XETEX_DEFAULT_ENCODING_EXTENSION_CODE: print_esc_cstr("XeTeXdefaultencoding"); break; - case PDF_SAVE_POS_NODE: - print_esc_cstr("pdfsavepos"); - break; default: print_cstr("[unknown extension!]"); break; @@ -4791,7 +4839,7 @@ void show_context(void) for_end = first_count - 1; if (q <= for_end) do - print_raw_char(trick_buf[q % error_line], true); + print_char(trick_buf[q % error_line]); while (q++ < for_end); } print_ln(); @@ -4814,7 +4862,7 @@ void show_context(void) for_end = p - 1; if (q <= for_end) do - print_raw_char(trick_buf[q % error_line], true); + print_char(trick_buf[q % error_line]); while (q++ < for_end); } if (m + n > error_line) @@ -6200,10 +6248,10 @@ expand(void) cur_cs = prim_lookup(hash[cur_cs].s1); if (cur_cs != UNDEFINED_PRIMITIVE) { - t = prim_eqtb[cur_cs].b16.s1; + t = eqtb[PRIM_EQTB_BASE + cur_cs].b16.s1; if (t > MAX_COMMAND) { cur_cmd = t; - cur_chr = prim_eqtb[cur_cs].b32.s1; + cur_chr = eqtb[PRIM_EQTB_BASE + cur_cs].b32.s1; cur_tok = (cur_cmd * MAX_CHAR_VAL) + cur_chr; cur_cs = 0; goto reswitch; @@ -6448,10 +6496,13 @@ bool scan_keyword(const char* s) { int32_t p = BACKUP_HEAD; int32_t q; + int32_t save_cur_cs; + mem[p].b32.s1 = TEX_NULL; if (strlen(s) == 1) { char c = s[0]; + save_cur_cs = cur_cs; while (true) { get_x_token(); @@ -6468,6 +6519,7 @@ bool scan_keyword(const char* s) back_input(); if (p != BACKUP_HEAD) begin_token_list(mem[BACKUP_HEAD].b32.s1, BACKED_UP); + cur_cs = save_cur_cs; return false; } } @@ -7025,6 +7077,7 @@ scan_something_internal(small_number level, bool negative) b16x4 i; int32_t p; +restart: m = cur_chr; switch (cur_cmd) { @@ -7293,6 +7346,7 @@ scan_something_internal(small_number level, bool negative) case CHAR_GIVEN: case MATH_GIVEN: + case XETEX_MATH_GIVEN: cur_val = cur_chr; cur_val_level = INT_VAL; break; @@ -7531,6 +7585,14 @@ scan_something_internal(small_number level, bool negative) cur_val = last_badness; break; + case ELAPSED_TIME_CODE: + cur_val = get_microinterval(); + break; + + case RANDOM_SEED_CODE: + cur_val = random_seed; + break; + case PDF_SHELL_ESCAPE_CODE: cur_val = 0; /* shellenabledp */ break; @@ -7547,9 +7609,9 @@ scan_something_internal(small_number level, bool negative) scan_font_ident(); n = cur_val; if (font_area[n] == AAT_FONT_FLAG) - cur_val = aat_font_get(m - 14, font_layout_engine[n]); + cur_val = aat_font_get(m - XETEX_INT, font_layout_engine[n]); else if (font_area[n] == OTGR_FONT_FLAG) - cur_val = ot_font_get(m - 14, font_layout_engine[n]); + cur_val = ot_font_get(m - XETEX_INT, font_layout_engine[n]); else cur_val = 0; break; @@ -7558,9 +7620,9 @@ scan_something_internal(small_number level, bool negative) scan_font_ident(); n = cur_val; if (font_area[n] == AAT_FONT_FLAG) - cur_val = aat_font_get(m - 14, font_layout_engine[n]); + cur_val = aat_font_get(m - XETEX_INT, font_layout_engine[n]); else if (font_area[n] == OTGR_FONT_FLAG && usingGraphite(font_layout_engine[n])) - cur_val = ot_font_get(m - 14, font_layout_engine[n]); + cur_val = ot_font_get(m - XETEX_INT, font_layout_engine[n]); else cur_val = 0; break; @@ -7583,11 +7645,11 @@ scan_something_internal(small_number level, bool negative) if (font_area[n] == AAT_FONT_FLAG) { scan_int(); k = cur_val; - cur_val = aat_font_get_1(m - 14, font_layout_engine[n], k); + cur_val = aat_font_get_1(m - XETEX_INT, font_layout_engine[n], k); } else if (font_area[n] == OTGR_FONT_FLAG && usingGraphite(font_layout_engine[n])) { scan_int(); k = cur_val; - cur_val = ot_font_get_1(m - 14, font_layout_engine[n], k); + cur_val = ot_font_get_1(m - XETEX_INT, font_layout_engine[n], k); } else { not_aat_gr_font_error(LAST_ITEM, m, n); cur_val = -1; @@ -7602,12 +7664,12 @@ scan_something_internal(small_number level, bool negative) scan_int(); k = cur_val; scan_int(); - cur_val = aat_font_get_2(m - 14, font_layout_engine[n], k, cur_val); + cur_val = aat_font_get_2(m - XETEX_INT, font_layout_engine[n], k, cur_val); } else if (font_area[n] == OTGR_FONT_FLAG && usingGraphite(font_layout_engine[n])) { scan_int(); k = cur_val; scan_int(); - cur_val = ot_font_get_2(m - 14, font_layout_engine[n], k, cur_val); + cur_val = ot_font_get_2(m - XETEX_INT, font_layout_engine[n], k, cur_val); } else { not_aat_gr_font_error(LAST_ITEM, m, n); cur_val = -1; @@ -7619,7 +7681,7 @@ scan_something_internal(small_number level, bool negative) n = cur_val; if (font_area[n] == AAT_FONT_FLAG) { scan_and_pack_name(); - cur_val = aat_font_get_named(m - 14, font_layout_engine[n]); + cur_val = aat_font_get_named(m - XETEX_INT, font_layout_engine[n]); } else { not_aat_font_error(LAST_ITEM, m, n); cur_val = -1; @@ -7631,10 +7693,10 @@ scan_something_internal(small_number level, bool negative) n = cur_val; if (font_area[n] == AAT_FONT_FLAG) { scan_and_pack_name(); - cur_val = aat_font_get_named(m - 14, font_layout_engine[n]); + cur_val = aat_font_get_named(m - XETEX_INT, font_layout_engine[n]); } else if (font_area[n] == OTGR_FONT_FLAG && usingGraphite(font_layout_engine[n])) { scan_and_pack_name(); - cur_val = gr_font_get_named(m - 14, font_layout_engine[n]); + cur_val = gr_font_get_named(m - XETEX_INT, font_layout_engine[n]); } else { not_aat_gr_font_error(LAST_ITEM, m, n); cur_val = -1; @@ -7648,12 +7710,12 @@ scan_something_internal(small_number level, bool negative) scan_int(); k = cur_val; scan_and_pack_name(); - cur_val = aat_font_get_named_1(m - 14, font_layout_engine[n], k); + cur_val = aat_font_get_named_1(m - XETEX_INT, font_layout_engine[n], k); } else if (font_area[n] == OTGR_FONT_FLAG && usingGraphite(font_layout_engine[n])) { scan_int(); k = cur_val; scan_and_pack_name(); - cur_val = gr_font_get_named_1(m - 14, font_layout_engine[n], k); + cur_val = gr_font_get_named_1(m - XETEX_INT, font_layout_engine[n], k); } else { not_aat_gr_font_error(LAST_ITEM, m, n); cur_val = -1; @@ -7664,7 +7726,7 @@ scan_something_internal(small_number level, bool negative) scan_font_ident(); n = cur_val; if (font_area[n] == OTGR_FONT_FLAG && usingOpenType(font_layout_engine[n])) { - cur_val = ot_font_get(m - 14, font_layout_engine[n]); + cur_val = ot_font_get(m - XETEX_INT, font_layout_engine[n]); } else { cur_val = 0; } @@ -7676,7 +7738,7 @@ scan_something_internal(small_number level, bool negative) n = cur_val; if (font_area[n] == OTGR_FONT_FLAG && usingOpenType(font_layout_engine[n])) { scan_int(); - cur_val = ot_font_get_1(m - 14, font_layout_engine[n], cur_val); + cur_val = ot_font_get_1(m - XETEX_INT, font_layout_engine[n], cur_val); } else { not_ot_font_error(LAST_ITEM, m, n); cur_val = -1; @@ -7691,7 +7753,7 @@ scan_something_internal(small_number level, bool negative) scan_int(); k = cur_val; scan_int(); - cur_val = ot_font_get_2(m - 14, font_layout_engine[n], k, cur_val); + cur_val = ot_font_get_2(m - XETEX_INT, font_layout_engine[n], k, cur_val); } else { not_ot_font_error(LAST_ITEM, m, n); cur_val = -1; @@ -7707,7 +7769,7 @@ scan_something_internal(small_number level, bool negative) scan_int(); kk = cur_val; scan_int(); - cur_val = ot_font_get_3(m - 14, font_layout_engine[n], k, kk, cur_val); + cur_val = ot_font_get_3(m - XETEX_INT, font_layout_engine[n], k, kk, cur_val); } else { not_ot_font_error(LAST_ITEM, m, n); cur_val = -1; @@ -7891,6 +7953,31 @@ scan_something_internal(small_number level, bool negative) } break; + case IGNORE_SPACES: + if (cur_chr == 1) { /*406: */ + get_token(); + + if (cur_cs < HASH_BASE) { + cur_cs = prim_lookup(cur_cs - SINGLE_BASE); + } else { + cur_cs = prim_lookup(hash[cur_cs].s1); + } + + if (cur_cs != UNDEFINED_PRIMITIVE) { + cur_cmd = eqtb[PRIM_EQTB_BASE + cur_cs].b16.s1; + cur_chr = eqtb[PRIM_EQTB_BASE + cur_cs].b32.s1; + cur_cs = PRIM_EQTB_BASE + cur_cs; + cur_tok = CS_TOKEN_FLAG + cur_cs; + } else { + cur_cmd = RELAX; + cur_chr = 0; + cur_tok = CS_TOKEN_FLAG + FROZEN_RELAX; + cur_cs = FROZEN_RELAX; + } + goto restart; + } + break; + default: error_here_with_diagnostic("You can't use `"); print_cmd_chr(cur_cmd, cur_chr); @@ -7957,6 +8044,7 @@ scan_int(void) } } while (cur_tok == OTHER_TOKEN + '+'); +restart: if (cur_tok == ALPHA_TOKEN) { /*460:*/ get_token(); @@ -7988,6 +8076,27 @@ scan_int(void) if (cur_cmd != SPACER) back_input(); } + } else if (cur_tok == CS_TOKEN_FLAG + FROZEN_PRIMITIVE) { /*406:*/ + get_token(); + + if (cur_cs < HASH_BASE) { + cur_cs = prim_lookup(cur_cs - SINGLE_BASE); + } else { + cur_cs = prim_lookup(hash[cur_cs].s1); + } + + if (cur_cs != UNDEFINED_PRIMITIVE) { + cur_cmd = eqtb[PRIM_EQTB_BASE + cur_cs].b16.s1; + cur_chr = eqtb[PRIM_EQTB_BASE + cur_cs].b32.s1; + cur_cs = PRIM_EQTB_BASE + cur_cs; + cur_tok = CS_TOKEN_FLAG + cur_cs; + } else { + cur_cmd = RELAX; + cur_chr = 0; + cur_tok = CS_TOKEN_FLAG + FROZEN_RELAX; + cur_cs = FROZEN_RELAX; + } + goto restart; } else if (cur_cmd >= MIN_INTERNAL && cur_cmd <= MAX_INTERNAL) { scan_something_internal(INT_VAL, false); } else { /*462:*/ @@ -9018,6 +9127,8 @@ int32_t str_toks_cat(pool_pointer b, small_number cat) } if (cat == 0) t = OTHER_TOKEN + t; + else if (cat == ACTIVE_CHAR) + t = CS_TOKEN_FLAG + 1 + t; else t = MAX_CHAR_VAL * cat + t; } @@ -9161,7 +9272,7 @@ conv_toks(void) UTF16_code quote_char; small_number cat; UnicodeScalar saved_chr; - int32_t p = TEX_NULL, q; + int32_t p = TEX_NULL, q, j; cat = 0; c = cur_chr; @@ -9184,36 +9295,52 @@ conv_toks(void) scan_font_ident(); break; - case XETEX_UCHAR_CODE: - scan_usv_num(); + case ETEX_REVISION_CODE: break; - case XETEX_UCHARCAT_CODE: - scan_usv_num(); - saved_chr = cur_val; - scan_int(); + case EXPANDED_CODE: + save_scanner_status = scanner_status; + save_warning_index = warning_index; + save_def_ref = def_ref; + if (str_start[str_ptr - TOO_BIG_CHAR] < pool_ptr) + u = make_string(); + else + u = 0; + scan_pdf_ext_toks(); + warning_index = save_warning_index; + scanner_status = save_scanner_status; + begin_token_list(mem[def_ref].b32.s1, INSERTED); + def_ref = save_def_ref; + if (u != 0) + str_ptr--; + return; - if (cur_val < LEFT_BRACE || cur_val > OTHER_CHAR || cur_val == OUT_PARAM || cur_val == IGNORE) { - error_here_with_diagnostic("Invalid code ("); - print_int(cur_val); - print_cstr("), should be in the ranges 1..4, 6..8, 10..12"); - capture_to_diagnostic(NULL); + case LEFT_MARGIN_KERN_CODE: + case RIGHT_MARGIN_KERN_CODE: + scan_register_num(); - help_ptr = 1; - help_line[0] = "I'm going to use 12 instead of that illegal code value."; - error(); - cat = 12; + if (cur_val < 256) { + p = BOX_REG(cur_val); } else { - cat = cur_val; + find_sa_element(4, cur_val, false); + if (cur_ptr == TEX_NULL) + p = TEX_NULL; + else + p = mem[cur_ptr + 1].b32.s1; } - cur_val = saved_chr; + if (p == TEX_NULL || NODE_type(p) != HLIST_NODE) + pdf_error("marginkern", "a non-empty hbox expected"); break; - case ETEX_REVISION_CODE: + case PDF_CREATION_DATE_CODE: + b = pool_ptr; + getcreationdate(); + mem[GARBAGE].b32.s1 = str_toks(b); + begin_token_list(mem[TEMP_HEAD].b32.s1, INSERTED); break; - case PDF_STRCMP_CODE: + case PDF_FILE_MOD_DATE_CODE: save_scanner_status = scanner_status; save_warning_index = warning_index; save_def_ref = def_ref; @@ -9221,13 +9348,69 @@ conv_toks(void) u = make_string(); else u = 0; - compare_strings(); + scan_pdf_ext_toks(); + + if (selector == SELECTOR_NEW_STRING) + pdf_error("tokens", "tokens_to_string() called while selector = new_string"); + + old_setting = selector; + selector = SELECTOR_NEW_STRING; + show_token_list(mem[def_ref].b32.s1, TEX_NULL, pool_size - pool_ptr); + selector = old_setting; + s = make_string(); + delete_token_ref(def_ref); def_ref = save_def_ref; warning_index = save_warning_index; scanner_status = save_scanner_status; + b = pool_ptr; + getfilemoddate(s); /* <= the difference-maker */ + mem[GARBAGE].b32.s1 = str_toks(b); + + if (s == str_ptr - 1) { + str_ptr--; + pool_ptr = str_start[str_ptr - TOO_BIG_CHAR]; + } + + begin_token_list(mem[TEMP_HEAD].b32.s1, INSERTED); if (u != 0) str_ptr--; - break; + return; + + case PDF_FILE_SIZE_CODE: + save_scanner_status = scanner_status; + save_warning_index = warning_index; + save_def_ref = def_ref; + if (str_start[str_ptr - TOO_BIG_CHAR] < pool_ptr) + u = make_string(); + else + u = 0; + scan_pdf_ext_toks(); + + if (selector == SELECTOR_NEW_STRING) + pdf_error("tokens", "tokens_to_string() called while selector = new_string"); + + old_setting = selector; + selector = SELECTOR_NEW_STRING; + show_token_list(mem[def_ref].b32.s1, TEX_NULL, pool_size - pool_ptr); + selector = old_setting; + s = make_string(); + delete_token_ref(def_ref); + def_ref = save_def_ref; + warning_index = save_warning_index; + scanner_status = save_scanner_status; + b = pool_ptr; + getfilesize(s); /* <= the difference-maker */ + mem[GARBAGE].b32.s1 = str_toks(b); + + if (s == str_ptr - 1) { + str_ptr--; + pool_ptr = str_start[str_ptr - TOO_BIG_CHAR]; + } + + begin_token_list(mem[TEMP_HEAD].b32.s1, INSERTED); + if (u != 0) + str_ptr--; + return; case PDF_MDFIVE_SUM_CODE: save_scanner_status = scanner_status; @@ -9246,7 +9429,81 @@ conv_toks(void) pdf_error("tokens", "tokens_to_string() called while selector = new_string"); old_setting = selector; - selector = SELECTOR_NEW_STRING ; + selector = SELECTOR_NEW_STRING; + show_token_list(mem[def_ref].b32.s1, TEX_NULL, pool_size - pool_ptr); + selector = old_setting; + s = make_string(); + delete_token_ref(def_ref); + def_ref = save_def_ref; + warning_index = save_warning_index; + scanner_status = save_scanner_status; + b = pool_ptr; + getmd5sum(s, boolvar); /* <== the difference-maker */ + mem[GARBAGE].b32.s1 = str_toks(b); + + if (s == str_ptr - 1) { + str_ptr--; + pool_ptr = str_start[str_ptr - TOO_BIG_CHAR]; + } + + begin_token_list(mem[TEMP_HEAD].b32.s1, INSERTED); + if (u != 0) + str_ptr--; + return; + break; + + case PDF_FILE_DUMP_CODE: + save_scanner_status = scanner_status; + save_warning_index = warning_index; + save_def_ref = def_ref; + + if (str_start[str_ptr - TOO_BIG_CHAR] < pool_ptr) + u = make_string(); + else + u = 0; + + cur_val = 0; + + if (scan_keyword("offset")) { + scan_int(); + + if (cur_val < 0) { + error_here_with_diagnostic("Bad file offset"); + capture_to_diagnostic(NULL); + help_ptr = 2; + help_line[1] = "A file offset must be between 0 and 2^_31_-1,"; + help_line[0] = "I changed this one to zero."; + int_error(cur_val); + cur_val = 0; + } + } + + i = cur_val; + cur_val = 0; + + if (scan_keyword("length")) { + scan_int(); + + if (cur_val < 0) { + error_here_with_diagnostic("Bad dump length"); + capture_to_diagnostic(NULL); + help_ptr = 2; + help_line[1] = "A dump length must be between 0 and 2^_31_-1,"; + help_line[0] = "I changed this one to zero."; + int_error(cur_val); + cur_val = 0; + } + } + + j = cur_val; + + scan_pdf_ext_toks(); + + if (selector == SELECTOR_NEW_STRING) + pdf_error("tokens", "tokens_to_string() called while selector = new_string"); + + old_setting = selector; + selector = SELECTOR_NEW_STRING; show_token_list(mem[def_ref].b32.s1, TEX_NULL, pool_size - pool_ptr); selector = old_setting; s = make_string(); @@ -9255,7 +9512,7 @@ conv_toks(void) warning_index = save_warning_index; scanner_status = save_scanner_status; b = pool_ptr; - getmd5sum(s, boolvar); + getfiledump(s, i, j); /* <=== non-boilerplate */ mem[GARBAGE].b32.s1 = str_toks(b); if (s == str_ptr - 1) { @@ -9267,6 +9524,47 @@ conv_toks(void) if (u != 0) str_ptr--; return; + + case PDF_STRCMP_CODE: + save_scanner_status = scanner_status; + save_warning_index = warning_index; + save_def_ref = def_ref; + if (str_start[str_ptr - TOO_BIG_CHAR] < pool_ptr) + u = make_string(); + else + u = 0; + compare_strings(); + def_ref = save_def_ref; + warning_index = save_warning_index; + scanner_status = save_scanner_status; + if (u != 0) + str_ptr--; + break; + + case XETEX_UCHAR_CODE: + scan_usv_num(); + break; + + case XETEX_UCHARCAT_CODE: + scan_usv_num(); + saved_chr = cur_val; + scan_int(); + + if (cur_val < LEFT_BRACE || cur_val > OTHER_CHAR || cur_val == OUT_PARAM || cur_val == IGNORE) { + error_here_with_diagnostic("Invalid code ("); + print_int(cur_val); + print_cstr("), should be in the ranges 1..4, 6..8, 10..12"); + capture_to_diagnostic(NULL); + + help_ptr = 1; + help_line[0] = "I'm going to use 12 instead of that illegal code value."; + error(); + cat = 12; + } else { + cat = cur_val; + } + + cur_val = saved_chr; break; case XETEX_REVISION_CODE: @@ -9322,28 +9620,17 @@ conv_toks(void) } break; - case LEFT_MARGIN_KERN_CODE: - case RIGHT_MARGIN_KERN_CODE: - scan_register_num(); - - if (cur_val < 256) { - p = BOX_REG(cur_val); - } else { - find_sa_element(4, cur_val, false); - if (cur_ptr == TEX_NULL) - p = TEX_NULL; - else - p = mem[cur_ptr + 1].b32.s1; - } - - if (p == TEX_NULL || NODE_type(p) != HLIST_NODE) - pdf_error("marginkern", "a non-empty hbox expected"); - break; - case JOB_NAME_CODE: if (job_name == 0) open_log_file(); break; + + case UNIFORM_DEVIATE_CODE: + scan_int(); + break; + + case NORMAL_DEVIATE_CODE: + break; } old_setting = selector; @@ -9394,41 +9681,10 @@ conv_toks(void) } break; - case XETEX_UCHAR_CODE: - case XETEX_UCHARCAT_CODE: - print_char(cur_val); - break; - case ETEX_REVISION_CODE: print_cstr(".6"); break; - case PDF_STRCMP_CODE: - print_int(cur_val); - break; - - case XETEX_REVISION_CODE: - print_cstr(".99998"); - break; - - case XETEX_VARIATION_NAME_CODE: - if (font_area[fnt] == AAT_FONT_FLAG) - aat_print_font_name(c, font_layout_engine[fnt], arg1, arg2); - break; - - case XETEX_FEATURE_NAME_CODE: - case XETEX_SELECTOR_NAME_CODE: - if (font_area[fnt] == AAT_FONT_FLAG) - aat_print_font_name(c, font_layout_engine[fnt], arg1, arg2); - else if (font_area[fnt] == OTGR_FONT_FLAG && usingGraphite(font_layout_engine[fnt])) - gr_print_font_name(c, font_layout_engine[fnt], arg1, arg2); - break; - - case XETEX_GLYPH_NAME_CODE: - if (font_area[fnt] == AAT_FONT_FLAG || font_area[fnt] == OTGR_FONT_FLAG) - print_glyph_name(fnt, arg1); - break; - case LEFT_MARGIN_KERN_CODE: p = mem[p + 5].b32.s1; while (p != TEX_NULL && @@ -9498,6 +9754,45 @@ conv_toks(void) print_cstr("pt"); break; + case PDF_STRCMP_CODE: + print_int(cur_val); + break; + + case UNIFORM_DEVIATE_CODE: + print_int(unif_rand(cur_val)); + break; + + case NORMAL_DEVIATE_CODE: + print_int(norm_rand()); + break; + + case XETEX_UCHAR_CODE: + case XETEX_UCHARCAT_CODE: + print_char(cur_val); + break; + + case XETEX_REVISION_CODE: + print_cstr(".999992"); + break; + + case XETEX_VARIATION_NAME_CODE: + if (font_area[fnt] == AAT_FONT_FLAG) + aat_print_font_name(c, font_layout_engine[fnt], arg1, arg2); + break; + + case XETEX_FEATURE_NAME_CODE: + case XETEX_SELECTOR_NAME_CODE: + if (font_area[fnt] == AAT_FONT_FLAG) + aat_print_font_name(c, font_layout_engine[fnt], arg1, arg2); + else if (font_area[fnt] == OTGR_FONT_FLAG && usingGraphite(font_layout_engine[fnt])) + gr_print_font_name(c, font_layout_engine[fnt], arg1, arg2); + break; + + case XETEX_GLYPH_NAME_CODE: + if (font_area[fnt] == AAT_FONT_FLAG || font_area[fnt] == OTGR_FONT_FLAG) + print_glyph_name(fnt, arg1); + break; + case JOB_NAME_CODE: print_file_name(job_name, 0, 0); break; @@ -10194,8 +10489,10 @@ conditional(void) m = prim_lookup(cur_cs - SINGLE_BASE); else m = prim_lookup(hash[cur_cs].s1); - b = (cur_cmd != UNDEFINED_CS && m != UNDEFINED_PRIMITIVE - && cur_cmd == prim_eqtb[m].b16.s1 && cur_chr == prim_eqtb[m].b32.s1); + b = (cur_cmd != UNDEFINED_CS + && m != UNDEFINED_PRIMITIVE + && cur_cmd == eqtb[PRIM_EQTB_BASE + m].b16.s1 + && cur_chr == eqtb[PRIM_EQTB_BASE + m].b32.s1); break; } @@ -10436,30 +10733,80 @@ make_name_string(void) } +static void +scan_file_name_braced(void) +{ + small_number save_scanner_status; + int32_t save_def_ref, save_cur_cs; + str_number s; + int32_t i; + bool save_stop_at_space; + + save_scanner_status = scanner_status; + save_def_ref = def_ref; + save_cur_cs = cur_cs; + cur_cs = warning_index; + scan_toks(false, true); + + old_setting = selector; + selector = SELECTOR_NEW_STRING; + show_token_list(mem[def_ref].b32.s1, TEX_NULL, pool_size - pool_ptr); + selector = old_setting; + s = make_string(); + delete_token_ref(def_ref); + def_ref = save_def_ref; + cur_cs = save_cur_cs; + scanner_status = save_scanner_status; + save_stop_at_space = stop_at_space; + + begin_name(); + + for (i = str_start[s - TOO_BIG_CHAR]; i < str_start[s + 1 - TOO_BIG_CHAR]; i++) + more_name(str_pool[i]); + + stop_at_space = save_stop_at_space; +} + + void scan_file_name(void) { - name_in_progress = true; - begin_name(); + int32_t save_warning_index; + save_warning_index = warning_index; + warning_index = cur_cs; do { get_x_token(); - } while (cur_cmd == SPACER); + } while (cur_cmd == SPACER || cur_cmd == RELAX); - while (true) { - if (cur_cmd > OTHER_CHAR || cur_chr > BIGGEST_CHAR) { - back_input(); - break; - } + back_input(); - if (!more_name(cur_chr)) - break; + if (cur_cmd == LEFT_BRACE) { + scan_file_name_braced(); + } else { + name_in_progress = true; + begin_name(); - get_x_token(); + do { + get_x_token(); + } while(cur_cmd == SPACER); + + while (true) { + if (cur_cmd > OTHER_CHAR || cur_chr > BIGGEST_CHAR) { + back_input(); + break; + } + + if (!more_name(cur_chr)) + break; + + get_x_token(); + } } end_name(); name_in_progress = false; + warning_index = save_warning_index; } @@ -15969,7 +16316,7 @@ void do_extension(void) int32_t p; switch (cur_chr) { - case 0: + case OPEN_NODE: { new_write_whatsit(OPEN_NODE_SIZE); scan_optional_equals(); @@ -15979,7 +16326,8 @@ void do_extension(void) mem[cur_list.tail + 2].b32.s1 = cur_ext; } break; - case 1: + + case WRITE_NODE: { k = cur_cs; new_write_whatsit(WRITE_NODE_SIZE); @@ -15988,13 +16336,15 @@ void do_extension(void) mem[cur_list.tail + 1].b32.s1 = def_ref; } break; - case 2: + + case CLOSE_NODE: { new_write_whatsit(WRITE_NODE_SIZE); mem[cur_list.tail + 1].b32.s1 = TEX_NULL; } break; - case 3: + + case SPECIAL_NODE: { new_whatsit(SPECIAL_NODE, WRITE_NODE_SIZE); mem[cur_list.tail + 1].b32.s0 = TEX_NULL; @@ -16002,7 +16352,8 @@ void do_extension(void) mem[cur_list.tail + 1].b32.s1 = def_ref; } break; - case 4: + + case IMMEDIATE_CODE: { get_x_token(); if ((cur_cmd == EXTENSION) && (cur_chr <= CLOSE_NODE)) { @@ -16016,11 +16367,11 @@ void do_extension(void) back_input(); } break; - case 5: + + case SET_LANGUAGE_CODE: if (abs(cur_list.mode) != HMODE) report_illegal_case(); else { - new_whatsit(LANGUAGE_NODE, SMALL_NODE_SIZE); scan_int(); if (cur_val <= 0) @@ -16034,19 +16385,38 @@ void do_extension(void) mem[cur_list.tail + 1].b16.s0 = norm_min(INTPAR(right_hyphen_min)); } break; - case 41: + + case PDF_SAVE_POS_NODE: + new_whatsit(PDF_SAVE_POS_NODE, SMALL_NODE_SIZE); + break; + + case RESET_TIMER_CODE: + get_seconds_and_micros(&epochseconds, µseconds); + break; + + case SET_RANDOM_SEED_CODE: + scan_int(); + if (cur_val < 0) + cur_val = -cur_val; + random_seed = cur_val; + init_randoms(random_seed); + break; + + case PIC_FILE_CODE: if (abs(cur_list.mode) == MMODE) report_illegal_case(); else load_picture(false); break; - case 42: + + case PDF_FILE_CODE: if (abs(cur_list.mode) == MMODE) report_illegal_case(); else load_picture(true); break; - case 43: + + case GLYPH_CODE: { if (abs(cur_list.mode) == VMODE) { back_input(); @@ -16081,7 +16451,8 @@ void do_extension(void) } } break; - case 44: + + case XETEX_INPUT_ENCODING_EXTENSION_CODE: { scan_and_pack_name(); i = get_encoding_mode_and_info(&j); @@ -16098,7 +16469,8 @@ void do_extension(void) set_input_file_encoding(input_file[in_open], i, j); } break; - case 45: + + case XETEX_DEFAULT_ENCODING_EXTENSION_CODE: { scan_and_pack_name(); i = get_encoding_mode_and_info(&j); @@ -16106,7 +16478,8 @@ void do_extension(void) INTPAR(xetex_default_input_encoding) = j; } break; - case 46: + + case XETEX_LINEBREAK_LOCALE_EXTENSION_CODE: { scan_file_name(); if (length(cur_name) == 0) @@ -16115,11 +16488,7 @@ void do_extension(void) INTPAR(xetex_linebreak_locale) = cur_name; } break; - case 6: - { - new_whatsit(PDFTEX_FIRST_EXTENSION_CODE, SMALL_NODE_SIZE); - } - break; + default: confusion("ext1"); break; @@ -16450,7 +16819,7 @@ void main_control(void) find_sa_element(INTER_CHAR_VAL, space_class * CHAR_CLASS_LIMIT + ((CHAR_CLASS_LIMIT - 1)), false); - if (cur_ptr != TEX_NULL) { + if (cur_ptr != TEX_NULL && ETEX_SA_ptr(cur_ptr) != TEX_NULL) { if (cur_cs == 0) { if (cur_cmd == CHAR_NUM) cur_cmd = OTHER_CHAR; @@ -16502,8 +16871,9 @@ void main_control(void) else cur_cs = prim_lookup(hash[cur_cs].s1); if (cur_cs != UNDEFINED_PRIMITIVE) { - cur_cmd = prim_eqtb[cur_cs].b16.s1; - cur_chr = prim_eqtb[cur_cs].b32.s1; + cur_cmd = eqtb[PRIM_EQTB_BASE + cur_cs].b16.s1; + cur_chr = eqtb[PRIM_EQTB_BASE + cur_cs].b32.s1; + cur_tok = CS_TOKEN_FLAG + PRIM_EQTB_BASE + cur_cs; goto reswitch; } } @@ -17104,7 +17474,7 @@ void main_control(void) find_sa_element(INTER_CHAR_VAL, ((CHAR_CLASS_LIMIT - 1)) * CHAR_CLASS_LIMIT + space_class, false); - if (cur_ptr != TEX_NULL) { + if (cur_ptr != TEX_NULL && ETEX_SA_ptr(cur_ptr) != TEX_NULL) { if (cur_cmd != LETTER) cur_cmd = OTHER_CHAR; cur_tok = (cur_cmd * MAX_CHAR_VAL) + cur_chr; @@ -17117,7 +17487,7 @@ void main_control(void) } else { find_sa_element(INTER_CHAR_VAL, prev_class * CHAR_CLASS_LIMIT + space_class, false); - if (cur_ptr != TEX_NULL) { + if (cur_ptr != TEX_NULL && ETEX_SA_ptr(cur_ptr) != TEX_NULL) { if (cur_cmd != LETTER) cur_cmd = OTHER_CHAR; cur_tok = (cur_cmd * MAX_CHAR_VAL) + cur_chr; @@ -17176,7 +17546,7 @@ void main_control(void) prev_class = ((CHAR_CLASS_LIMIT - 1)); find_sa_element(INTER_CHAR_VAL, space_class * CHAR_CLASS_LIMIT + ((CHAR_CLASS_LIMIT - 1)), false); - if (cur_ptr != TEX_NULL) { + if (cur_ptr != TEX_NULL && ETEX_SA_ptr(cur_ptr) != TEX_NULL) { if (cur_cs == 0) { if (cur_cmd == CHAR_NUM) cur_cmd = OTHER_CHAR; @@ -17235,24 +17605,23 @@ void main_control(void) main_pp = cur_list.tail; if (cur_list.mode == HMODE) { main_ppp = cur_list.head; - if (main_ppp != main_pp) - while ((mem[main_ppp].b32.s1 != main_pp)) { - if (!is_char_node(main_ppp) && NODE_type(main_ppp) == DISC_NODE) { - temp_ptr = main_ppp; - { - register int32_t for_end; - main_p = 1; - for_end = mem[temp_ptr].b16.s0; - if (main_p <= for_end) - do - main_ppp = LLIST_link(main_ppp); - while (main_p++ < for_end); - } + while (main_ppp != main_pp && mem[main_ppp].b32.s1 != main_pp) { + if (!is_char_node(main_ppp) && NODE_type(main_ppp) == DISC_NODE) { + temp_ptr = main_ppp; + { + register int32_t for_end; + main_p = 1; + for_end = mem[temp_ptr].b16.s0; + if (main_p <= for_end) + do + main_ppp = LLIST_link(main_ppp); + while (main_p++ < for_end); } - if (main_ppp != main_pp) - main_ppp = LLIST_link(main_ppp); } + if (main_ppp != main_pp) + main_ppp = LLIST_link(main_ppp); + } temp_ptr = 0; do { if (main_h == 0) @@ -17335,24 +17704,22 @@ void main_control(void) } else { main_ppp = cur_list.head; - if (main_ppp != main_pp) - while ((mem[main_ppp].b32.s1 != main_pp)) { - - if (!is_char_node(main_ppp) && NODE_type(main_ppp) == DISC_NODE) { - temp_ptr = main_ppp; - { - register int32_t for_end; - main_p = 1; - for_end = mem[temp_ptr].b16.s0; - if (main_p <= for_end) - do - main_ppp = LLIST_link(main_ppp); - while (main_p++ < for_end); - } + while (main_ppp != main_pp && mem[main_ppp].b32.s1 != main_pp) { + if (!is_char_node(main_ppp) && NODE_type(main_ppp) == DISC_NODE) { + temp_ptr = main_ppp; + { + register int32_t for_end; + main_p = 1; + for_end = mem[temp_ptr].b16.s0; + if (main_p <= for_end) + do + main_ppp = LLIST_link(main_ppp); + while (main_p++ < for_end); } - if (main_ppp != main_pp) - main_ppp = LLIST_link(main_ppp); } + if (main_ppp != main_pp) + main_ppp = LLIST_link(main_ppp); + } if ((((main_pp) != TEX_NULL && (!(is_char_node(main_pp))) && (NODE_type(main_pp) == WHATSIT_NODE) && ((mem[main_pp].b16.s0 == NATIVE_WORD_NODE) || (mem[main_pp].b16.s0 == NATIVE_WORD_NODE_AT)))) && (mem[main_pp + 4].b16.s2 == main_f) @@ -17496,7 +17863,7 @@ void main_control(void) if ((cur_input.state != TOKEN_LIST) || (cur_input.index != BACKED_UP_CHAR)) { find_sa_element(INTER_CHAR_VAL, ((CHAR_CLASS_LIMIT - 1)) * CHAR_CLASS_LIMIT + space_class, false); - if (cur_ptr != TEX_NULL) { + if (cur_ptr != TEX_NULL && ETEX_SA_ptr(cur_ptr) != TEX_NULL) { if (cur_cmd != LETTER) cur_cmd = OTHER_CHAR; cur_tok = (cur_cmd * MAX_CHAR_VAL) + cur_chr; @@ -17509,7 +17876,7 @@ void main_control(void) } else { find_sa_element(INTER_CHAR_VAL, prev_class * CHAR_CLASS_LIMIT + space_class, false); - if (cur_ptr != TEX_NULL) { + if (cur_ptr != TEX_NULL && ETEX_SA_ptr(cur_ptr) != TEX_NULL) { if (cur_cmd != LETTER) cur_cmd = OTHER_CHAR; cur_tok = (cur_cmd * MAX_CHAR_VAL) + cur_chr; @@ -17652,7 +18019,7 @@ void main_control(void) if ((cur_input.state != TOKEN_LIST) || (cur_input.index != BACKED_UP_CHAR)) { find_sa_element(INTER_CHAR_VAL, ((CHAR_CLASS_LIMIT - 1)) * CHAR_CLASS_LIMIT + space_class, false); - if (cur_ptr != TEX_NULL) { + if (cur_ptr != TEX_NULL && ETEX_SA_ptr(cur_ptr) != TEX_NULL) { if (cur_cmd != LETTER) cur_cmd = OTHER_CHAR; cur_tok = (cur_cmd * MAX_CHAR_VAL) + cur_chr; @@ -17665,7 +18032,7 @@ void main_control(void) } else { find_sa_element(INTER_CHAR_VAL, prev_class * CHAR_CLASS_LIMIT + space_class, false); - if (cur_ptr != TEX_NULL) { + if (cur_ptr != TEX_NULL && ETEX_SA_ptr(cur_ptr) != TEX_NULL) { if (cur_cmd != LETTER) cur_cmd = OTHER_CHAR; cur_tok = (cur_cmd * MAX_CHAR_VAL) + cur_chr; @@ -17877,7 +18244,7 @@ void main_control(void) prev_class = ((CHAR_CLASS_LIMIT - 1)); find_sa_element(INTER_CHAR_VAL, space_class * CHAR_CLASS_LIMIT + ((CHAR_CLASS_LIMIT - 1)), false); - if (cur_ptr != TEX_NULL) { + if (cur_ptr != TEX_NULL && ETEX_SA_ptr(cur_ptr) != TEX_NULL) { if (cur_cs == 0) { if (cur_cmd == CHAR_NUM) cur_cmd = OTHER_CHAR; @@ -17972,11 +18339,15 @@ void compare_strings(void) { str_number s1, s2; pool_pointer i1, i2, j1, j2; + int32_t save_cur_cs; + + save_cur_cs = cur_cs; { scan_toks(false, true); } s1 = tokens_to_string(def_ref); delete_token_ref(def_ref); + cur_cs = save_cur_cs; { scan_toks(false, true); } diff --git a/tectonic/xetex-xetexd.h b/tectonic/xetex-xetexd.h index c05ef85995..941bef2237 100644 --- a/tectonic/xetex-xetexd.h +++ b/tectonic/xetex-xetexd.h @@ -303,6 +303,11 @@ typedef union { #define TOKEN_LIST_ref_count(p) mem[p].b32.s0 +/* e-TeX sparse arrays for large-numebered registers, etc. */ +#define ETEX_SA_ref(p) mem[(p) + 1].b32.s0 +#define ETEX_SA_ptr(p) mem[(p) + 1].b32.s1 +#define ETEX_SA_num(p) ETEX_SA_ptr(p) + /* e-TeX extended marks stuff ... not sure where to put these */ #define ETEX_MARK_sa_top_mark(p) mem[(p) + 1].b32.s0 /* \topmarks */ #define ETEX_MARK_sa_first_mark(p) mem[(p) + 1].b32.s1 /* \firstmarks */ @@ -343,7 +348,15 @@ typedef struct { /* Functions originating in texmfmp.c */ void getmd5sum(int32_t s, bool file); -void get_date_and_time (time_t, int32_t *, int32_t *, int32_t *, int32_t *); + +void init_start_time(time_t source_date_epoch); +void get_date_and_time (time_t source_date_epoch, int32_t *minutes, int32_t *day, int32_t *month, int32_t *year); +void get_seconds_and_micros (int32_t *seconds, int32_t *micros); + +void getcreationdate(void); +void getfilemoddate(int32_t s); +void getfilesize(int32_t s); +void getfiledump(int32_t s, int offset, int length); char *gettexstring(str_number); bool is_new_source(str_number, int); @@ -425,6 +438,11 @@ extern unsigned char help_ptr; extern bool use_err_help; extern bool arith_error; extern scaled_t tex_remainder; +extern int32_t randoms[55]; +extern unsigned char j_random; +extern scaled_t random_seed; +extern int32_t two_to_the[31]; +extern int32_t spec_log[29]; extern int32_t temp_ptr; extern memory_word *mem; extern int32_t lo_mem_max; @@ -458,7 +476,6 @@ extern bool no_new_control_sequence; extern int32_t cs_count; extern b32x2 prim[501]; extern int32_t prim_used; -extern memory_word prim_eqtb[501]; extern memory_word *save_stack; extern int32_t save_ptr; extern int32_t max_save_stack; @@ -569,6 +586,8 @@ extern int32_t dead_cycles; extern bool doing_leaders; extern scaled_t rule_ht, rule_dp, rule_wd; extern scaled_t cur_h, cur_v; /* should be internal to shipout, but accessed by synctex */ +extern int32_t epochseconds; +extern int32_t microseconds; extern scaled_t total_stretch[4], total_shrink[4]; extern int32_t last_badness; extern int32_t adjust_tail; @@ -728,6 +747,7 @@ int32_t new_penalty(int32_t m); void check_mem(bool print_locs); void search_mem(int32_t p); int32_t prev_rightmost(int32_t s, int32_t e); +int32_t get_microinterval(void); scaled_t round_xn_over_d(scaled_t x, int32_t n, int32_t d); void short_display(int32_t p); void print_font_and_char(int32_t p); @@ -1099,6 +1119,9 @@ int32_t half(int32_t x); scaled_t mult_and_add(int32_t n, scaled_t x, scaled_t y, scaled_t max_answer); scaled_t x_over_n(scaled_t x, int32_t n); scaled_t xn_over_d(scaled_t x, int32_t n, int32_t d); +void init_randoms(int32_t seed); +int32_t unif_rand(int32_t x); +int32_t norm_rand(void); /* xetex-shipout */ diff --git a/tests/formats.rs b/tests/formats.rs index 87ed6161ec..1193632bc2 100644 --- a/tests/formats.rs +++ b/tests/formats.rs @@ -137,6 +137,6 @@ fn plain_format() { test_format_generation( "plain.tex", "plain.fmt", - "83684a4992274fdae8de1b142146f85b0bf1a4f3489c54a04e12739d578dd863", + "8e33c4c9af66ddb064a36749db1e0ba681bbebd1a896d2886745a0efa9a745a1", ) } diff --git a/tests/tex-outputs.rs b/tests/tex-outputs.rs index 019bc01392..424445f709 100644 --- a/tests/tex-outputs.rs +++ b/tests/tex-outputs.rs @@ -181,6 +181,27 @@ impl TestCase { // Keep these alphabetized. +#[test] +fn a4paper() { + let mut unstables = UnstableOptions::default(); + unstables.paper_size = Some(String::from("a4")); + TestCase::new("a4paper") + .with_unstables(unstables) + .check_pdf(true) + .go() +} + +#[test] +fn file_encoding() { + // Need to do this here since we call test_path unusually early. + util::set_test_root(); + + TestCase::new("file_encoding.tex") + .with_fs(&test_path(&["tex-outputs"])) + .expect(Ok(TexResult::Warnings)) + .go() +} + /// An issue triggered by a bug in how the I/O subsystem reported file offsets /// after an ungetc() call. #[test] @@ -207,6 +228,33 @@ fn otf_basic() { .go() } +#[test] +fn prim_creationdate() { + TestCase::new("prim_creationdate").go() +} + +#[test] +fn prim_filedump() { + TestCase::new("prim_filedump").go() +} + +#[test] +fn prim_filemoddate() { + // Git doesn't preserve mtimes, so manually force the mtime of the input + // file to something repeatable. + util::set_test_root(); + let path = test_path(&["tex-outputs", "prim_filemoddate.tex"]); + let t = filetime::FileTime::from_unix_time(1_603_835_905, 0); + filetime::set_file_mtime(path, t).expect("failed to set input file mtime"); + + TestCase::new("prim_filemoddate").go() +} + +#[test] +fn prim_filesize() { + TestCase::new("prim_filesize").go() +} + #[test] fn tex_logo() { TestCase::new("tex_logo").go() @@ -239,17 +287,6 @@ fn unicode_file_name() { .go() } -#[test] -fn file_encoding() { - // Need to do this here since we call test_path unusually early. - util::set_test_root(); - - TestCase::new("file_encoding.tex") - .with_fs(&test_path(&["tex-outputs"])) - .expect(Ok(TexResult::Warnings)) - .go() -} - #[test] fn tectoniccodatokens_errinside() { TestCase::new("tectoniccodatokens_errinside") @@ -269,25 +306,7 @@ fn tectoniccodatokens_ok() { TestCase::new("tectoniccodatokens_ok").go() } -// FIXME(#244): For reasons I absolutely cannot figure out, this test -// currently (2018 Oct) fails on AppVeyor's CI, while it works on both GNU and -// MSVC Windows toolchains when I (PKGW) run it manually. (The failure is that -// the observed PDF doesn't match the expected one.) Seeing as everything else -// seems to work and this test doesn't cover anything that special compared to -// the other tests in this file, just skip it on Windows so that we can keep -// on CI'ing. -#[cfg(not(target_os = "windows"))] #[test] fn the_letter_a() { TestCase::new("the_letter_a").check_pdf(true).go() } - -#[test] -fn a4paper() { - let mut unstables = UnstableOptions::default(); - unstables.paper_size = Some(String::from("a4")); - TestCase::new("a4paper") - .with_unstables(unstables) - .check_pdf(true) - .go() -} diff --git a/tests/tex-outputs/a4paper.pdf b/tests/tex-outputs/a4paper.pdf index 3c77556326..785453acfd 100644 Binary files a/tests/tex-outputs/a4paper.pdf and b/tests/tex-outputs/a4paper.pdf differ diff --git a/tests/tex-outputs/md5_of_hello.pdf b/tests/tex-outputs/md5_of_hello.pdf index 0cbed2d41b..d9deaefb50 100644 Binary files a/tests/tex-outputs/md5_of_hello.pdf and b/tests/tex-outputs/md5_of_hello.pdf differ diff --git a/tests/tex-outputs/otf_basic.log b/tests/tex-outputs/otf_basic.log index 0dbee8b45d..d654a6dfa7 100644 --- a/tests/tex-outputs/otf_basic.log +++ b/tests/tex-outputs/otf_basic.log @@ -2,4 +2,4 @@ (otf_basic.tex Missing character: There is no 𐐷 in font [lmroman12-regular]! [1] ) -Output written on otf_basic.xdv (1 page, 6300 bytes). +Output written on otf_basic.xdv (1 page, 6304 bytes). diff --git a/tests/tex-outputs/otf_basic.xdv b/tests/tex-outputs/otf_basic.xdv index 0219961d81..f416c702ab 100644 Binary files a/tests/tex-outputs/otf_basic.xdv and b/tests/tex-outputs/otf_basic.xdv differ diff --git a/tests/tex-outputs/png_formats.pdf b/tests/tex-outputs/png_formats.pdf index 60f26ce8f7..32d471b0d2 100644 Binary files a/tests/tex-outputs/png_formats.pdf and b/tests/tex-outputs/png_formats.pdf differ diff --git a/tests/tex-outputs/prim_creationdate.log b/tests/tex-outputs/prim_creationdate.log new file mode 100644 index 0000000000..ee4abe476e --- /dev/null +++ b/tests/tex-outputs/prim_creationdate.log @@ -0,0 +1,3 @@ +** +(prim_creationdate.tex [1] ) +Output written on prim_creationdate.xdv (1 page, 228 bytes). diff --git a/tests/tex-outputs/prim_creationdate.tex b/tests/tex-outputs/prim_creationdate.tex new file mode 100644 index 0000000000..a28dcbe344 --- /dev/null +++ b/tests/tex-outputs/prim_creationdate.tex @@ -0,0 +1 @@ +\creationdate\bye diff --git a/tests/tex-outputs/prim_creationdate.xdv b/tests/tex-outputs/prim_creationdate.xdv new file mode 100644 index 0000000000..b63fb08aed Binary files /dev/null and b/tests/tex-outputs/prim_creationdate.xdv differ diff --git a/tests/tex-outputs/prim_filedump.log b/tests/tex-outputs/prim_filedump.log new file mode 100644 index 0000000000..77eacd1cd2 --- /dev/null +++ b/tests/tex-outputs/prim_filedump.log @@ -0,0 +1,3 @@ +** +(prim_filedump.tex [1] ) +Output written on prim_filedump.xdv (1 page, 212 bytes). diff --git a/tests/tex-outputs/prim_filedump.tex b/tests/tex-outputs/prim_filedump.tex new file mode 100644 index 0000000000..bbc056a255 --- /dev/null +++ b/tests/tex-outputs/prim_filedump.tex @@ -0,0 +1,4 @@ +% 0123456789abcdefghijklmnopqrstuvwxyz long first line to avoid caring what EOL is +X\filedump offset 2 length 10 {prim_filedump.tex}% +Y\filedump offset 9999 length 0 {nosuchfile.tex}% +Z\bye diff --git a/tests/tex-outputs/prim_filedump.xdv b/tests/tex-outputs/prim_filedump.xdv new file mode 100644 index 0000000000..bc7a17bce2 Binary files /dev/null and b/tests/tex-outputs/prim_filedump.xdv differ diff --git a/tests/tex-outputs/prim_filemoddate.log b/tests/tex-outputs/prim_filemoddate.log new file mode 100644 index 0000000000..f95ad9af10 --- /dev/null +++ b/tests/tex-outputs/prim_filemoddate.log @@ -0,0 +1,3 @@ +** +(prim_filemoddate.tex [1] ) +Output written on prim_filemoddate.xdv (1 page, 212 bytes). diff --git a/tests/tex-outputs/prim_filemoddate.tex b/tests/tex-outputs/prim_filemoddate.tex new file mode 100644 index 0000000000..a2ad0466c3 --- /dev/null +++ b/tests/tex-outputs/prim_filemoddate.tex @@ -0,0 +1,5 @@ +% Git doesn't preserve file modification times, but the test case manually +% updates the modification time of this file before running the engine. +X\filemoddate{nosuchfile}% +Y\filemoddate{prim_filemoddate.tex}% +Z\bye diff --git a/tests/tex-outputs/prim_filemoddate.xdv b/tests/tex-outputs/prim_filemoddate.xdv new file mode 100644 index 0000000000..bc7a17bce2 Binary files /dev/null and b/tests/tex-outputs/prim_filemoddate.xdv differ diff --git a/tests/tex-outputs/prim_filesize.log b/tests/tex-outputs/prim_filesize.log new file mode 100644 index 0000000000..5523196f02 --- /dev/null +++ b/tests/tex-outputs/prim_filesize.log @@ -0,0 +1,3 @@ +** +(prim_filesize.tex [1] ) +Output written on prim_filesize.xdv (1 page, 212 bytes). diff --git a/tests/tex-outputs/prim_filesize.tex b/tests/tex-outputs/prim_filesize.tex new file mode 100644 index 0000000000..86b1038a39 --- /dev/null +++ b/tests/tex-outputs/prim_filesize.tex @@ -0,0 +1 @@ +X\filesize{nosuchfile}Y\filesize{prim_filesize.tex}Z\bye%no-EOL-newline-to-keep-size-same-on-Windows \ No newline at end of file diff --git a/tests/tex-outputs/prim_filesize.xdv b/tests/tex-outputs/prim_filesize.xdv new file mode 100644 index 0000000000..bc7a17bce2 Binary files /dev/null and b/tests/tex-outputs/prim_filesize.xdv differ diff --git a/tests/tex-outputs/redbox_png.pdf b/tests/tex-outputs/redbox_png.pdf index 4fed959721..795dcbf769 100644 Binary files a/tests/tex-outputs/redbox_png.pdf and b/tests/tex-outputs/redbox_png.pdf differ diff --git a/tests/tex-outputs/the_letter_a.pdf b/tests/tex-outputs/the_letter_a.pdf index e7076a6660..da41c743c5 100644 Binary files a/tests/tex-outputs/the_letter_a.pdf and b/tests/tex-outputs/the_letter_a.pdf differ diff --git a/tests/trip.rs b/tests/trip.rs index dff4123d06..9af57e6b9b 100644 --- a/tests/trip.rs +++ b/tests/trip.rs @@ -90,7 +90,7 @@ fn trip_test() { expected_log.test_from_collection(files); expected_xdv.test_from_collection(files); expected_os.test_from_collection(files); - expected_fot.test_data(files.get(OsStr::new("")).unwrap()); + expected_fot.test_data(&files.get(OsStr::new("")).unwrap().data); } #[test] @@ -157,5 +157,5 @@ fn etrip_test() { expected_log.test_from_collection(files); expected_xdv.test_from_collection(files); expected_out.test_from_collection(files); - expected_fot.test_data(files.get(OsStr::new("")).unwrap()); + expected_fot.test_data(&files.get(OsStr::new("")).unwrap().data); } diff --git a/tests/trip/trip.fot b/tests/trip/trip.fot index 559aadf0b1..cb002cd306 100644 --- a/tests/trip/trip.fot +++ b/tests/trip/trip.fot @@ -31,22 +31,22 @@ l.442 ...l\tracingoutput1\global\escapechar256\end {end-group character }} > 3. {Āshowthe Ādeadcycles - Āglobal Āadvance Ācountz by1Āglobal Āg... + Āglobal Āadvance Ācountz by1Āglobal Āglobalde... Āend l.442 ...l\tracingoutput1\global\escapechar256\end ! You can't use `Āend' in internal vertical mode. Āend - - ...-1 Āgdef Ālocal {}Āunvbox 255Āend + + ...efs -1 Āgdef Ālocal {}Āunvbox 255Āend Ārb } Āend l.442 ...l\tracingoutput1\global\escapechar256\end ! Unbalanced output routine. - ...gdef Ālocal {}Āunvbox 255Āend Ārb + ...-1 Āgdef Ālocal {}Āunvbox 255Āend Ārb } Āend @@ -62,7 +62,7 @@ Completed box being shipped out [-1.2.-1118806.0.11.196608.327680.1572864.10737 41823] ! Unbalanced write command. Āif 01{Āelse unbal}Āfi - + }Āendwrite diff --git a/tests/trip/trip.log b/tests/trip/trip.log index 0f82ea6ba9..04788d6973 100644 --- a/tests/trip/trip.log +++ b/tests/trip/trip.log @@ -4009,14 +4009,18 @@ Completed box being shipped out [-2.2.-1118806.0.11.196608.327680.1572864.10737 ou can't use a prefix with `\unskip'. \unskip -l.345 \newlinechar`Y\global\unskip - \show^^Y\newlinechar\lastpenalty\unpenalty... +l.345 \newlinechar` +\global\unskip + \show^^ +\newlinechar\lastpenalty\unpenalty... I'll pretend you didn't say \long or \outer or \global or \protected. {\unskip} {\show} > the character ^^Y. -l.345 \newlinechar`Y\global\unskip\show^^Y +l.345 \newlinechar` +\global\unskip\show^^ + \newlinechar\lastpenalty\unpenalty... @@ -6230,7 +6234,7 @@ my insertion and my current dilemma will both disappear. {internal vertical mode: Āshowthe} > 3. {Āshowthe Ādeadcycles - Āglobal Āadvance Ācountz by1Āglobal Āg... + Āglobal Āadvance Ācountz by1Āglobal Āglobalde... Āend l.442 ...l\tracingoutput1\global\escapechar256\end @@ -6243,8 +6247,8 @@ l.442 ...l\tracingoutput1\global\escapechar256\end {Āend} ! You can't use `Āend' in internal vertical mode. Āend - - ...-1 Āgdef Ālocal {}Āunvbox 255Āend + + ...efs -1 Āgdef Ālocal {}Āunvbox 255Āend Ārb } Āend @@ -6257,7 +6261,7 @@ return to the right one by typing `I}' or `I$' or `I\par'. {end-group character }} ! Unbalanced output routine. - ...gdef Ālocal {}Āunvbox 255Āend Ārb + ...-1 Āgdef Ālocal {}Āunvbox 255Āend Ārb } Āend @@ -6295,7 +6299,7 @@ Completed box being shipped out [-1.2.-1118806.0.11.196608.327680.1572864.10737 ! Unbalanced write command. Āif 01{Āelse unbal}Āfi - + }Āendwrite diff --git a/tests/util/mod.rs b/tests/util/mod.rs index b737bf07de..9518756c19 100644 --- a/tests/util/mod.rs +++ b/tests/util/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2018 the Tectonic Project +// Copyright 2018-2020 the Tectonic Project // Licensed under the MIT License. //! Note: we need to store this code as `tests/util/mod.rs` rather than @@ -10,18 +10,19 @@ // using this testing setup... #![allow(dead_code)] +use flate2::read::GzDecoder; +use std::{ + collections::HashSet, + default::Default, + env, + ffi::{OsStr, OsString}, + fs::File, + io::{Read, Write}, + path::{Path, PathBuf}, +}; -use ::flate2::read::GzDecoder; -use std::collections::{HashMap, HashSet}; -use std::default::Default; -use std::env; -use std::ffi::{OsStr, OsString}; -use std::fs::File; -use std::io::{Read, Write}; -use std::path::{Path, PathBuf}; - -use ::tectonic::errors::Result; -pub use ::tectonic::test_util::{test_path, TestBundle}; +pub use tectonic::test_util::{test_path, TestBundle}; +use tectonic::{errors::Result, io::memory::MemoryFileCollection}; /// Set the magic environment variable that enables the testing infrastructure /// embedded in the main Tectonic crate. This function is separated out from @@ -94,7 +95,13 @@ pub fn ensure_plain_format() -> Result { .prefix("plain_fmt") .rand_bytes(6) .tempfile_in(test_path(&[]))?; - temp_fmt.write_all(mem.files.borrow().get(OsStr::new("plain.fmt")).unwrap())?; + temp_fmt.write_all( + &mem.files + .borrow() + .get(OsStr::new("plain.fmt")) + .unwrap() + .data, + )?; temp_fmt.persist(&fmt_path)?; } @@ -194,10 +201,10 @@ impl ExpectedInfo { ); } - pub fn test_from_collection(&self, files: &HashMap>) { + pub fn test_from_collection(&self, files: &MemoryFileCollection) { if !self.gzipped { - if let Some(data) = files.get(&self.name) { - self.test_data(data) + if let Some(file) = files.get(&self.name) { + self.test_data(&file.data) } else { panic!( "{:?} not in {:?}", @@ -207,7 +214,7 @@ impl ExpectedInfo { } } else { let mut buf = Vec::new(); - let mut dec = GzDecoder::new(&files.get(&self.name).unwrap()[..]); + let mut dec = GzDecoder::new(&files.get(&self.name).unwrap().data[..]); dec.read_to_end(&mut buf).unwrap(); self.test_data(&buf); }