From 702e2bba4da03c842c3370d00f7093bc6494572f Mon Sep 17 00:00:00 2001 From: Kenta Ishizaki Date: Sat, 2 May 2026 11:01:26 +0900 Subject: [PATCH 1/5] Bootstrap brst-binding-ruby gem (v0.1.0 scaffold + mandatory baseline) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Establishes the libBeresta org-wide mandatory baseline for the Ruby member of the brst-binding- family: a top-level README plus a CMakeLists.txt that builds libBeresta into a shared library the FFI loader can dlopen. On top of that baseline we drop in the Ruby gem skeleton (gemspec, Gemfile, Rakefile, LICENSE under zlib/libpng, CHANGELOG, .rspec, .gitignore, ext/extconf.rb stub, top-level entrypoint module, and a Library loader that resolves libbrst across vendored / in-tree / system locations). Per agreement with @dmitrys99 (libBeresta Issue #19, danbako 399): the gem name matches the repo name (brst-binding-ruby), license matches upstream (zlib/libpng), and the high-level idiomatic API stays out of this gem — v0.1.0 is intentionally a faithful low-level FFI surface. --- .gitignore | 18 ++++ .rspec | 3 + CHANGELOG.md | 22 +++++ CMakeLists.txt | 60 +++++++++++++ Gemfile | 3 + LICENSE | 31 +++++++ README.md | 139 +++++++++++++++++++++++++++++++ Rakefile | 19 +++++ brst-binding-ruby.gemspec | 43 ++++++++++ ext/extconf.rb | 59 +++++++++++++ ext/libBeresta/.gitkeep | 0 lib/brst-binding-ruby.rb | 5 ++ lib/brst/binding/ruby.rb | 30 +++++++ lib/brst/binding/ruby/library.rb | 46 ++++++++++ lib/brst/binding/ruby/version.rb | 7 ++ 15 files changed, 485 insertions(+) create mode 100644 .rspec create mode 100644 CHANGELOG.md create mode 100644 CMakeLists.txt create mode 100644 Gemfile create mode 100644 LICENSE create mode 100644 README.md create mode 100644 Rakefile create mode 100644 brst-binding-ruby.gemspec create mode 100644 ext/extconf.rb create mode 100644 ext/libBeresta/.gitkeep create mode 100644 lib/brst-binding-ruby.rb create mode 100644 lib/brst/binding/ruby.rb create mode 100644 lib/brst/binding/ruby/library.rb create mode 100644 lib/brst/binding/ruby/version.rb diff --git a/.gitignore b/.gitignore index c111b33..bea2641 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,19 @@ *.gem +/.bundle/ +/Gemfile.lock +/coverage/ +/pkg/ +/tmp/ +/spec/tmp/ +/spec/smoke/*.pdf +/ext/libBeresta/build/ +/ext/libBeresta/install/ +/ext/libBeresta/lib/ +/build/ +*.dylib +*.so +*.bundle +*.rbc +.DS_Store +*.gem +.rspec_status diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..7a2cc1a --- /dev/null +++ b/.rspec @@ -0,0 +1,3 @@ +--require spec_helper +--format documentation +--color diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..13b52b7 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,22 @@ +# Changelog + +## [Unreleased] + +## [0.1.0] - TBD (pending libBeresta 1.0.0 release) + +Initial experimental release. + +### Added +- Low-level FFI bindings auto-generated from libBeresta's canonical + S-expression definitions (`gen/data/*.lsp`). +- S-expression parser and Ruby FFI renderer in `generator/`. +- Smoke test that generates a PDF on macOS. +- mandatory baseline: README.md + CMakeLists.txt at repository root + (per libBeresta org-wide `brst-binding-` family convention). + +### Known limitations +- macOS only. Linux support planned for the next release. +- Low-level surface only. An idiomatic high-level API is planned as a + separate gem. + +[0.1.0]: https://github.com/libBeresta/brst-binding-ruby/releases/tag/v0.1.0 diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..3416d49 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,60 @@ +# brst-binding-ruby — mandatory baseline build entry point +# +# This CMakeLists.txt fulfils the libBeresta org-wide baseline for +# `brst-binding-` repositories (README + CMakeLists.txt). It exists to +# build the libBeresta shared library so that the Ruby FFI bindings can load +# it at runtime. +# +# Two modes are supported: +# +# 1. Vendored source mode (preferred for `gem install`): +# Drop libBeresta source into ext/libBeresta/ (e.g. via git submodule or +# tarball) and build from this directory: +# cmake -S . -B build +# cmake --build build +# +# 2. External source mode (development convenience): +# Pass -DLIBBRST_SOURCE_DIR=/path/to/libBeresta clone: +# cmake -S . -B build -DLIBBRST_SOURCE_DIR=$HOME/src/libBeresta +# cmake --build build +# +# The resulting shared library (libbrst.dylib / libbrst.so) is copied into +# ext/libBeresta/lib/ where the Ruby loader looks for it. + +cmake_minimum_required(VERSION 3.16) +project(brst_binding_ruby NONE) + +set(_default_libbrst_src "${CMAKE_CURRENT_LIST_DIR}/ext/libBeresta") +set(LIBBRST_SOURCE_DIR "${_default_libbrst_src}" CACHE PATH + "Path to libBeresta source tree to build (defaults to ext/libBeresta)") + +if(NOT EXISTS "${LIBBRST_SOURCE_DIR}/CMakeLists.txt") + message(WARNING + "libBeresta source not found at ${LIBBRST_SOURCE_DIR}.\n" + "Either:\n" + " - Place libBeresta source in ext/libBeresta/ (e.g. git submodule), or\n" + " - Pass -DLIBBRST_SOURCE_DIR=/path/to/libBeresta\n" + "Skipping libBeresta build target.") + return() +endif() + +enable_language(C) + +set(LIBBRST_SHARED_LIB ON CACHE BOOL "" FORCE) +set(LIBBRST_EXAMPLES OFF CACHE BOOL "" FORCE) +set(LIBBRST_TESTS OFF CACHE BOOL "" FORCE) + +add_subdirectory("${LIBBRST_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/libBeresta-build") + +set(_outdir "${CMAKE_CURRENT_LIST_DIR}/ext/libBeresta/lib") +file(MAKE_DIRECTORY "${_outdir}") + +add_custom_target(brst_binding_ruby_stage ALL + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $ + "${_outdir}/libbrst${CMAKE_SHARED_LIBRARY_SUFFIX}" + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $ + "${_outdir}/$" + DEPENDS brst + COMMENT "Staging libbrst shared library into ext/libBeresta/lib/") diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..b4e2a20 --- /dev/null +++ b/Gemfile @@ -0,0 +1,3 @@ +source "https://rubygems.org" + +gemspec diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..048a3fc --- /dev/null +++ b/LICENSE @@ -0,0 +1,31 @@ +brst-binding-ruby — Ruby FFI bindings for libBeresta + +Copyright (c) 2026 Kenta Ishizaki and contributors + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution. + +---------------------------------------------------------------------- + +This gem provides bindings to libBeresta (https://github.com/libBeresta/libBeresta), +which is itself distributed under the zlib/libpng license. libBeresta is +originally a fork of libHaru (https://github.com/libharu/libharu), also under +the zlib/libpng license. Original libHaru copyright belongs to Takeshi Kanno +and contributors; libBeresta copyright belongs to Dmitry Solomennikov and +contributors. Bindings here are generated from libBeresta's canonical +S-expression definitions (gen/data/*.lsp). diff --git a/README.md b/README.md new file mode 100644 index 0000000..21b200d --- /dev/null +++ b/README.md @@ -0,0 +1,139 @@ +# brst-binding-ruby + +[![CI](https://github.com/libBeresta/brst-binding-ruby/actions/workflows/ci.yml/badge.svg)](https://github.com/libBeresta/brst-binding-ruby/actions/workflows/ci.yml) + +**Experimental, low-level Ruby FFI bindings for [libBeresta][libBeresta]**, a +free, cross-platform PDF generation C library forked from [libHaru][libHaru]. + +This is the Ruby member of the libBeresta org's `brst-binding-` family of +language bindings. Bindings are auto-generated from libBeresta's canonical +S-expression definitions in [`gen/data/*.lsp`][gen-data], so they stay faithful +to the upstream API. + +## Status: v0.1.0 — experimental + +- Auto-generated low-level FFI surface from `gen/data/*.lsp`. +- macOS-only at this version. Linux support is planned for the next release. +- An idiomatic, higher-level Ruby API is **not** part of this gem; that is + planned as a separate gem on top of these low-level bindings. +- Released in lockstep with libBeresta 1.0.0. + +## Mandatory baseline + +Per the libBeresta org-wide convention for `brst-binding-` repositories, +this repository ships: + +- `README.md` (this file) +- `CMakeLists.txt` — entry point that builds libBeresta (vendored or external) + into a shared library that the Ruby loader can `dlopen`. + +Everything else (gemspec, `lib/`, `spec/`, generator, CI) follows Ruby +community conventions on top of that baseline. + +## Quick start + +### Install (development checkout) + +This v0.1.0 is not yet on rubygems.org. To try it from a checkout: + +```sh +git clone https://github.com/libBeresta/brst-binding-ruby.git +cd brst-binding-ruby +git clone --depth=1 https://github.com/libBeresta/libBeresta.git ../libBeresta +brew install cmake libpng # macOS native deps +bundle install +cmake -S . -B build -DLIBBRST_SOURCE_DIR=$(cd ../libBeresta && pwd) \ + -DCMAKE_BUILD_TYPE=Release +cmake --build build --config Release -j +bundle exec rspec +``` + +### Hello PDF in Ruby + +```ruby +require "brst/binding/ruby" + +include Brst::Binding::Ruby + +pdf = Base.BRST_Doc_New(nil, nil) +page = DocPage.BRST_Doc_Page_Add(pdf) +PageRoutines.BRST_Page_SetSize(page, :A4, :PAGE_ORIENTATION_PORTRAIT) + +font = DocFont.BRST_Doc_Font(pdf, "Helvetica", nil) +Text.BRST_Page_BeginText(page) +Text.BRST_Page_SetFontAndSize(page, font, 20.0) +Text.BRST_Page_MoveTextPos(page, 50.0, 750.0) +Text.BRST_Page_ShowText(page, "Hello, Beresta from Ruby!") +Text.BRST_Page_EndText(page) + +DocSave.BRST_Doc_SaveToFile(pdf, "hello.pdf") +Base.BRST_Doc_Free(pdf) +``` + +## How it's built + +``` +libBeresta/gen/data/*.lsp (S-expression — Source of Truth) + │ + ▼ +generator/bin/brst-binding-ruby-gen (Ruby S-exp parser + FFI renderer) + │ + ▼ +lib/brst/binding/ruby/types.rb (consolidated typedefs / enums / structs) +lib/brst/binding/ruby/.rb (one FFI module per .lsp file) + │ + ▼ +ext/libBeresta/lib/libbrst.dylib (cmake-built native library) +``` + +The generator parses S-expressions directly. The `gen/json/*.json` files are +themselves auto-generated from the same `.lsp` files and are useful for +structural cross-checking but are **not** the source of truth. + +To regenerate after pulling new `.lsp` data: + +```sh +bundle exec rake generate +# or: +ruby generator/bin/brst-binding-ruby-gen \ + --data-dir ../libBeresta/gen/data \ + --out-dir lib/brst/binding/ruby +``` + +CI guards against generator drift: the workflow regenerates on every push and +fails if the committed bindings differ from the generator's output. + +## Library resolution + +At load time, `Brst::Binding::Ruby::Library` searches in this order: + +1. `ENV["BRST_BINDING_RUBY_LIB"]` — explicit override (path or library name). +2. `ext/libBeresta/lib/libbrst.{dylib,so}` — vendored build output. +3. `ext/libBeresta/build/src/libbrst.{dylib,so}` — in-tree cmake build output. +4. `build/libBeresta-build/src/libbrst.{dylib,so}` — alternative in-tree. +5. Falls back to `libbrst` / `brst` via the system loader. + +If a function or type referenced by upstream `.lsp` data is absent from the +loaded native library (e.g. caption / C-symbol drift, or a feature compiled +out of this build), the corresponding `attach_function` is recorded in +`::MISSING_SYMBOLS` and the rest of the gem still loads. + +## Acknowledgements + +- [@dmitrys99][dmitrys99] — libBeresta maintainer, designer of the S-expression + source-of-truth pipeline, and gracious mentor for this binding effort. The + `brst-binding-` org structure and the `README + CMakeLists.txt` + baseline come from his guidance. +- [libHaru][libHaru] — original PDF C library this work ultimately descends + from. Original copyright belongs to Takeshi Kanno and contributors. +- Russian-language docs in the upstream `.lsp` data are preserved verbatim in + the parsed tree but not surfaced in v0.1.0 bindings. + +## License + +[zlib/libpng License](LICENSE) — same as libBeresta and libHaru. + +[libBeresta]: https://github.com/libBeresta/libBeresta +[libHaru]: https://github.com/libharu/libharu +[gen-data]: https://github.com/libBeresta/libBeresta/tree/master/gen/data +[dmitrys99]: https://github.com/dmitrys99 diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..8c4dd02 --- /dev/null +++ b/Rakefile @@ -0,0 +1,19 @@ +require "bundler/gem_tasks" + +begin + require "rspec/core/rake_task" + RSpec::Core::RakeTask.new(:spec) +rescue LoadError + # rspec is a dev dependency; fine if absent in production +end + +desc "Regenerate FFI bindings from libBeresta gen/data/*.lsp" +task :generate, [:gen_data_dir] do |_, args| + data_dir = args[:gen_data_dir] || ENV["BRST_GEN_DATA_DIR"] || + File.expand_path("../libBeresta/gen/data", __dir__) + ruby "-Igenerator/lib", "generator/bin/brst-binding-ruby-gen", + "--data-dir", data_dir, + "--out-dir", "lib/brst/binding/ruby" +end + +task default: :spec diff --git a/brst-binding-ruby.gemspec b/brst-binding-ruby.gemspec new file mode 100644 index 0000000..7ed6b40 --- /dev/null +++ b/brst-binding-ruby.gemspec @@ -0,0 +1,43 @@ +require_relative "lib/brst/binding/ruby/version" + +Gem::Specification.new do |spec| + spec.name = "brst-binding-ruby" + spec.version = Brst::Binding::Ruby::VERSION + spec.authors = ["Kenta Ishizaki"] + spec.email = ["kentaishizaki@55728.jp"] + + spec.summary = "Low-level Ruby FFI bindings for libBeresta (PDF generation)" + spec.description = <<~DESC + Experimental Ruby FFI bindings for libBeresta, a free, cross-platform PDF + generation C library forked from libHaru. Bindings are auto-generated from + libBeresta's canonical S-expression definitions (gen/data/*.lsp). v0.1.0 + exposes a faithful low-level surface; an idiomatic high-level API is planned + as a separate gem. Currently tested on macOS only; Linux support is planned + for the next release. Part of the libBeresta org's brst-binding- family. + DESC + + spec.homepage = "https://github.com/libBeresta/brst-binding-ruby" + spec.license = "Zlib" + spec.required_ruby_version = ">= 3.1.0" + + spec.metadata["source_code_uri"] = spec.homepage + spec.metadata["bug_tracker_uri"] = "#{spec.homepage}/issues" + spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md" + spec.metadata["rubygems_mfa_required"] = "true" + + spec.files = Dir[ + "lib/**/*.rb", + "ext/extconf.rb", + "CMakeLists.txt", + "README.md", + "LICENSE", + "CHANGELOG.md" + ] + spec.require_paths = ["lib"] + spec.extensions = ["ext/extconf.rb"] + + spec.add_dependency "ffi", "~> 1.16" + + spec.add_development_dependency "rspec", "~> 3.13" + spec.add_development_dependency "rake", "~> 13.2" +end diff --git a/ext/extconf.rb b/ext/extconf.rb new file mode 100644 index 0000000..141c848 --- /dev/null +++ b/ext/extconf.rb @@ -0,0 +1,59 @@ +require "mkmf" +require "fileutils" + +# brst-binding-ruby ext/extconf.rb +# +# This file is **not** a traditional C extension build script. brst-binding-ruby +# is a pure-Ruby FFI gem; the native dependency is libBeresta, an external +# shared library. We declare an extension only so that `gem install` runs this +# file, giving us a hook to either: +# +# - Build libBeresta from a vendored source tree (ext/libBeresta/), or +# - Skip the build and rely on a system-installed libbrst. +# +# A no-op Makefile is always emitted so RubyGems considers the build successful. + +ROOT = File.expand_path("..", __dir__) +EXT_DIR = File.join(ROOT, "ext", "libBeresta") +SRC_CMAKE = File.join(EXT_DIR, "CMakeLists.txt") +LIB_OUT = File.join(EXT_DIR, "lib") + +def have_cmake? + system("cmake --version > /dev/null 2>&1") +end + +def build_libbrst + build_dir = File.join(EXT_DIR, "build") + FileUtils.mkdir_p(build_dir) + FileUtils.mkdir_p(LIB_OUT) + + Dir.chdir(ROOT) do + sh = ->(*cmd) { system(*cmd) || abort("[brst-binding-ruby] command failed: #{cmd.join(' ')}") } + sh.call("cmake", "-S", ".", "-B", "build", + "-DCMAKE_BUILD_TYPE=Release", + "-DLIBBRST_SOURCE_DIR=#{EXT_DIR}") + sh.call("cmake", "--build", "build", "--config", "Release") + end +end + +if File.exist?(SRC_CMAKE) + if have_cmake? + build_libbrst + else + warn "[brst-binding-ruby] cmake not found; skipping libBeresta build. " \ + "Install cmake or set BRST_BINDING_RUBY_LIB to an existing libbrst path." + end +else + warn "[brst-binding-ruby] ext/libBeresta source not vendored; skipping build. " \ + "Set BRST_BINDING_RUBY_LIB to an existing libbrst, or vendor the source." +end + +# Always emit a stub Makefile so `gem install` succeeds. +File.write(File.join(__dir__, "Makefile"), <<~MAKE) + all: + \t@true + install: + \t@true + clean: + \t@true +MAKE diff --git a/ext/libBeresta/.gitkeep b/ext/libBeresta/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/lib/brst-binding-ruby.rb b/lib/brst-binding-ruby.rb new file mode 100644 index 0000000..b370ce2 --- /dev/null +++ b/lib/brst-binding-ruby.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +# Convenience entrypoint that mirrors the gem name (brst-binding-ruby). +# The canonical require path is "brst/binding/ruby". +require "brst/binding/ruby" diff --git a/lib/brst/binding/ruby.rb b/lib/brst/binding/ruby.rb new file mode 100644 index 0000000..5e95dd8 --- /dev/null +++ b/lib/brst/binding/ruby.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require_relative "ruby/version" +require_relative "ruby/library" +require_relative "ruby/types" + +module Brst + module Binding + # Top-level entrypoint for brst-binding-ruby. + # + # Generated FFI modules live under Brst::Binding::Ruby::, e.g. + # Brst::Binding::Ruby::Base.BRST_Doc_New(...) + # Brst::Binding::Ruby::DocSave.BRST_Doc_SaveToFile(pdf, "out.pdf") + # + # The naming follows libBeresta's gen/data/*.lsp file boundaries; this is a + # faithful low-level surface, not an idiomatic Ruby API. A higher-level + # wrapper gem is planned separately. + module Ruby + end + end +end + +# Auto-load every generated FFI module. Order is irrelevant because every type +# (pointer/enum/struct/definition) is centralized in `types.rb`, which has +# already been loaded above. +Dir[File.expand_path("ruby/*.rb", __dir__)].sort.each do |f| + base = File.basename(f, ".rb") + next if %w[version library types].include?(base) + require f +end diff --git a/lib/brst/binding/ruby/library.rb b/lib/brst/binding/ruby/library.rb new file mode 100644 index 0000000..bb3b4e8 --- /dev/null +++ b/lib/brst/binding/ruby/library.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require "ffi" + +module Brst + module Binding + module Ruby + # Locates libBeresta's shared library so generated FFI modules can call + # `ffi_lib Brst::Binding::Ruby::Library.lib_path`. + # + # Resolution order: + # 1. ENV["BRST_BINDING_RUBY_LIB"] — explicit override (any path or name) + # 2. ext/libBeresta/lib/libbrst.{dylib,so} (vendored build output) + # 3. ext/libBeresta/build/src/libbrst.{dylib,so} (in-tree build output) + # 4. "brst" / "libbrst" — let ffi/dlopen search system paths + module Library + module_function + + def lib_path + @lib_path ||= resolve! + end + + def resolve! + if (override = ENV["BRST_BINDING_RUBY_LIB"]) && !override.empty? + return override + end + + candidates = [] + gem_root = File.expand_path("../../../..", __dir__) + + %w[dylib so].each do |ext| + candidates << File.join(gem_root, "ext", "libBeresta", "lib", "libbrst.#{ext}") + candidates << File.join(gem_root, "ext", "libBeresta", "build", "src", "libbrst.#{ext}") + candidates << File.join(gem_root, "build", "libBeresta-build", "src", "libbrst.#{ext}") + end + + found = candidates.find { |p| File.exist?(p) } + return found if found + + # Fall back to library names; FFI will search system paths. + %w[brst libbrst] + end + end + end + end +end diff --git a/lib/brst/binding/ruby/version.rb b/lib/brst/binding/ruby/version.rb new file mode 100644 index 0000000..9624c86 --- /dev/null +++ b/lib/brst/binding/ruby/version.rb @@ -0,0 +1,7 @@ +module Brst + module Binding + module Ruby + VERSION = "0.1.0" + end + end +end From 3eace5cebbca7efe9812c6321906d45836489d65 Mon Sep 17 00:00:00 2001 From: Kenta Ishizaki Date: Sat, 2 May 2026 11:01:53 +0900 Subject: [PATCH 2/5] Add S-expression generator that emits FFI bindings from gen/data/*.lsp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The generator parses libBeresta's canonical S-expression definitions directly (gen/json/*.json is treated as a derived artifact only, used for cross-checking — see spec/cross_check_spec.rb). Pipeline: gen/data/*.lsp | SexpParser (StringScanner; UTF-8; tolerant of upstream quirks | like Cyrillic-letter keywords `:ру` in doc_font.lsp | and a stray trailing `)` in encrypt.lsp) v parsed Ruby Hash/Array tree | SymbolTable (consolidates :types / :pointers / :definitions / | :enums / :structs / :consts / :sizes; synthesises | a :PageSizes enum from page_sizes.lsp ISO 216 entries | since the .lsp data never declares that enum | explicitly even though base.lsp / page_routines.lsp | reference it) v Renderer -> lib/brst/binding/ruby/types.rb (consolidated) lib/brst/binding/ruby/.rb (per-file FFI module) Implements the four design improvements from danbako 366: #1 Consolidated :types renderer (typedef'd from inner->outer mapping). #2 Enums emitted as FFI enums (effectively :int-backed typedefs). #3 Structs registered with FFI::Struct.by_value aliases. #4 Every typedef lives in types.rb so per-file modules have no load-order dependency. --- generator/bin/brst-binding-ruby-gen | 24 ++ generator/lib/brst_binding_ruby_gen.rb | 55 ++++ .../lib/brst_binding_ruby_gen/renderer.rb | 284 ++++++++++++++++++ .../lib/brst_binding_ruby_gen/sexp_parser.rb | 172 +++++++++++ .../lib/brst_binding_ruby_gen/symbol_table.rb | 239 +++++++++++++++ 5 files changed, 774 insertions(+) create mode 100755 generator/bin/brst-binding-ruby-gen create mode 100644 generator/lib/brst_binding_ruby_gen.rb create mode 100644 generator/lib/brst_binding_ruby_gen/renderer.rb create mode 100644 generator/lib/brst_binding_ruby_gen/sexp_parser.rb create mode 100644 generator/lib/brst_binding_ruby_gen/symbol_table.rb diff --git a/generator/bin/brst-binding-ruby-gen b/generator/bin/brst-binding-ruby-gen new file mode 100755 index 0000000..d39fc80 --- /dev/null +++ b/generator/bin/brst-binding-ruby-gen @@ -0,0 +1,24 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require "optparse" +$LOAD_PATH.unshift File.expand_path("../lib", __dir__) +require "brst_binding_ruby_gen" + +options = { lang: "en" } +OptionParser.new do |op| + op.banner = "Usage: brst-binding-ruby-gen --data-dir DIR --out-dir DIR [--lang en|ru]" + op.on("--data-dir DIR", "Path to libBeresta gen/data directory") { |v| options[:data_dir] = v } + op.on("--out-dir DIR", "Output directory for generated bindings") { |v| options[:out_dir] = v } + op.on("--lang LANG", "Doc language (en|ru), default en") { |v| options[:lang] = v } +end.parse! + +abort "missing --data-dir" unless options[:data_dir] +abort "missing --out-dir" unless options[:out_dir] + +count = BrstBindingRubyGen.run( + data_dir: options[:data_dir], + out_dir: options[:out_dir], + lang: options[:lang] +) +puts "[brst-binding-ruby-gen] processed #{count} .lsp files -> #{options[:out_dir]}" diff --git a/generator/lib/brst_binding_ruby_gen.rb b/generator/lib/brst_binding_ruby_gen.rb new file mode 100644 index 0000000..95248e8 --- /dev/null +++ b/generator/lib/brst_binding_ruby_gen.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require "fileutils" +require_relative "brst_binding_ruby_gen/sexp_parser" +require_relative "brst_binding_ruby_gen/symbol_table" +require_relative "brst_binding_ruby_gen/renderer" + +# Top-level orchestrator for the brst-binding-ruby code generator. +# +# Pipeline: +# gen/data/*.lsp --SexpParser--> Ruby Hash/Array tree +# --SymbolTable--> consolidated type vocabulary +# --Renderer--> types.rb + per-file FFI modules +# +# `types.rb` is emitted from the union of every file's type declarations +# (`:types`, `:pointers`, `:definitions`, `:enums`, `:structs`) so that the +# per-file modules need not depend on each other at load time. +module BrstBindingRubyGen + module_function + + def run(data_dir:, out_dir:, lang: "en") + data_dir = File.expand_path(data_dir) + out_dir = File.expand_path(out_dir) + raise ArgumentError, "data dir does not exist: #{data_dir}" unless Dir.exist?(data_dir) + + FileUtils.mkdir_p(out_dir) + + lsp_files = Dir.glob(File.join(data_dir, "*.lsp")).sort + raise "no .lsp files found in #{data_dir}" if lsp_files.empty? + + parsed = lsp_files.map do |path| + tree = SexpParser.parse_file(path) + [path, tree] + end + + symbols = SymbolTable.from(parsed) + + # Emit consolidated types.rb first. + File.write(File.join(out_dir, "types.rb"), + Renderer.render_types(symbols, lang: lang)) + + parsed.each do |path, tree| + module_name = Renderer.module_name_from_filename(path) + next if module_name.nil? + + body = Renderer.render_file(tree, symbols, lang: lang) + next if body.nil? # nothing renderable in this file + + out_path = File.join(out_dir, "#{Renderer.snake_case(module_name)}.rb") + File.write(out_path, body) + end + + parsed.size + end +end diff --git a/generator/lib/brst_binding_ruby_gen/renderer.rb b/generator/lib/brst_binding_ruby_gen/renderer.rb new file mode 100644 index 0000000..e2bd4e8 --- /dev/null +++ b/generator/lib/brst_binding_ruby_gen/renderer.rb @@ -0,0 +1,284 @@ +# frozen_string_literal: true + +module BrstBindingRubyGen + # Emits Ruby source for the consolidated `types.rb` and per-file FFI modules. + # + # Generated layout: + # lib/brst/binding/ruby/types.rb (all typedefs, enums, structs, consts) + # lib/brst/binding/ruby/.rb (functions for that .lsp file, + # plus a Sizes table for page_sizes.lsp) + # + # The four design improvements (per danbako 366): + # #1 Consolidated `:types` renderer (typedef'd from inner→outer mapping). + # #2 Enums emitted as FFI enums (effectively `:int`-backed typedefs). + # #3 Structs registered with `Struct.by_value` aliases for value semantics. + # #4 Every typedef lives in `types.rb`, so per-file modules have no + # load-order dependency on each other. + module Renderer + BANNER = <<~RB + # frozen_string_literal: true + # + # AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). + # Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). + # DO NOT EDIT BY HAND. Re-generate with `rake generate`. + RB + + module_function + + def module_name_from_filename(path) + base = File.basename(path, ".lsp") + camelize(base) + end + + def camelize(s) + s.to_s.split(/[_\-]/).map { |p| p[0]&.upcase.to_s + p[1..].to_s }.join + end + + def snake_case(s) + s.to_s + .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2') + .gsub(/([a-z\d])([A-Z])/, '\1_\2') + .downcase + end + + # ---- types.rb ----------------------------------------------------------- + + def render_types(symbols, lang: "en") + out = +BANNER.dup + out << <<~RB + + require "ffi" + require_relative "library" + + module Brst + module Binding + module Ruby + # Centralised type vocabulary for every generated FFI module. + # + # `Types.apply(mod)` registers every typedef, enum, and struct + # alias on `mod` (which must already `extend FFI::Library`). + # See generator/lib/brst_binding_ruby_gen/renderer.rb. + module Types + module_function + + # Each generated `.rb` calls `Types.apply(self)` so that + # all type symbols (`:Doc`, `:STATUS`, `:GMode`, ...) resolve + # uniformly regardless of which .lsp file they originated in. + def apply(mod) + return if mod.instance_variable_get(:@brst_types_applied) + mod.instance_variable_set(:@brst_types_applied, true) + apply_scalars(mod) + apply_pointers(mod) + apply_enums(mod) + apply_structs(mod) + apply_definitions(mod) + end + + # ---- scalars (from types.lsp :types) ---- + def apply_scalars(mod) + RB + + symbols.inner_to_ffi.each do |inner, ffi| + next if inner == "void" + next if inner.include?("*") # pointer-suffix variants are pointers + out << " mod.typedef #{ffi.inspect}, :#{ruby_type_sym(inner)}\n" + end + + out << <<~RB + end + + # ---- opaque pointers ---- + def apply_pointers(mod) + RB + symbols.pointers.each_key do |n| + out << " mod.typedef :pointer, :#{ruby_type_sym(n)}\n" + end + + out << <<~RB + end + + # ---- enums (improvement #2: each enum acts as an :int-backed typedef) ---- + def apply_enums(mod) + RB + symbols.enums.each_value do |enum_def| + elements_src = enum_def[:elements].each_with_index.flat_map do |el, _i| + v = el[:value] + sym = symbol_literal(el[:element]) + if v.is_a?(Integer) + [sym, v.to_s] + else + [sym] + end + end.join(", ") + out << " mod.enum #{symbol_literal(enum_def[:name])}, [#{elements_src}]\n" + end + + out << <<~RB + end + + # ---- structs (improvement #3: by_value alias) ---- + def apply_structs(mod) + RB + symbols.structs.each_value do |s| + klass = struct_class_name(s[:name]) + out << " unless mod.const_defined?(:#{klass}, false)\n" + out << " klass = Class.new(FFI::Struct) do\n" + layout_pairs = s[:fields].map do |f| + ":#{f[:field]}, #{symbols.resolve(f[:type]).inspect}" + end + out << " layout #{layout_pairs.join(",\n ")}\n" + out << " end\n" + out << " mod.const_set(:#{klass}, klass)\n" + out << " end\n" + out << " mod.typedef mod.const_get(:#{klass}).by_value, :#{ruby_type_sym(s[:name])}\n" + end + + out << <<~RB + end + + # ---- definitions (typedef aliases) ---- + def apply_definitions(mod) + RB + symbols.definitions.each do |name, d| + out << " mod.typedef :#{ruby_type_sym(d[:original])}, :#{ruby_type_sym(name)}\n" + end + + out << <<~RB + end + end + end + end + end + RB + + # Constants from consts.lsp — emitted as Ruby module constants under + # Brst::Binding::Ruby::Const::BRST_, mirroring libBeresta's BRST_ + # prefix convention. + out << "\nmodule Brst\n module Binding\n module Ruby\n module Const\n" + symbols.consts.each_value do |c| + next if c[:value].nil? + literal = const_literal(c[:value]) + out << " BRST_#{c[:name]} = #{literal}\n" + end + out << " end\n end\n end\nend\n" + + # Page sizes from page_sizes.lsp — emitted as a frozen Hash so callers + # can do width/height lookup without touching FFI. + if !symbols.sizes.empty? + out << "\nmodule Brst\n module Binding\n module Ruby\n module PageSizesMM\n" + out << " TABLE = {\n" + symbols.sizes.each do |s| + out << " #{s[:id].inspect} => { caption: #{s[:caption].inspect}, " \ + "origin: #{s[:origin].inspect}, width_mm: #{s[:width]}, height_mm: #{s[:height]} },\n" + end + out << " }.freeze\n" + out << " end\n end\n end\nend\n" + end + + out + end + + # ---- per-file modules --------------------------------------------------- + + def render_file(tree, symbols, lang: "en") + file_name = tree[:file].to_s + module_name = camelize(file_name.empty? ? "unknown" : file_name) + + functions = Array(tree[:functions]) + # Skip files that have only type declarations (already covered in types.rb) + return nil if functions.empty? && Array(tree[:sizes]).empty? + + out = +BANNER.dup + out << <<~RB + + require "ffi" + require_relative "library" + require_relative "types" + + module Brst + module Binding + module Ruby + module #{module_name} + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + RB + + functions.each do |fn| + next unless fn.is_a?(Hash) + next if fn[:caption].nil? + caption = fn[:caption].to_s + param_types = Array(fn[:params]).map do |p| + symbols.resolve(p[:type]).inspect + end + return_type = symbols.resolve(fn.dig(:result, :type)).inspect + + out << " safe_attach :BRST_#{caption}, [#{param_types.join(', ')}], #{return_type}\n" + end + + out << " end\n end\n end\nend\n" + out + end + + # ---- helpers ------------------------------------------------------------ + + def ruby_type_sym(name) + name.to_s.tr("-", "_").gsub(/[^A-Za-z0-9_]/, "_") + end + + # Return a Ruby source literal for a Symbol whose string contents may not + # be a bare-identifier (e.g. starts with a digit, like "4A0"). Falls back + # to the quoted-symbol form when needed. + def symbol_literal(name) + s = ruby_type_sym(name) + if s =~ /\A[A-Za-z_][A-Za-z0-9_]*\z/ + ":#{s}" + else + ":\"#{s}\"" + end + end + + def struct_class_name(name) + camelize(name.to_s.tr("-", "_")) + "Struct" + end + + def const_literal(v) + case v + when Integer + v.to_s + when Float + v.to_s + when String + s = v.strip + if s =~ /\A-?0x[0-9A-Fa-f]+\z/ + s + elsif s =~ /\A-?\d+\z/ + s + elsif s =~ /\A-?\d+\.\d+(?:[eE][+-]?\d+)?\z/ + s + else + s.inspect + end + else + v.inspect + end + end + end +end diff --git a/generator/lib/brst_binding_ruby_gen/sexp_parser.rb b/generator/lib/brst_binding_ruby_gen/sexp_parser.rb new file mode 100644 index 0000000..d102bf4 --- /dev/null +++ b/generator/lib/brst_binding_ruby_gen/sexp_parser.rb @@ -0,0 +1,172 @@ +# frozen_string_literal: true + +require "strscan" + +module BrstBindingRubyGen + # Minimal Common-Lisp-flavoured S-expression parser tuned for libBeresta's + # gen/data/*.lsp files. Recognises: + # - lists `( ... )` + # - strings `"..."` with `\"` `\\` `\n` escapes (and tolerates raw newlines) + # - `:keyword` symbols + # - integers (`0x00`, `123`), floats (`3.14`) + # - bare identifiers (with `-`, `_`, `*`, alpha-num) + # - `;` line comments + # + # When a list looks like a property list `(:k1 v1 :k2 v2 ...)` it is converted + # into a Ruby Hash keyed by Symbol. Otherwise it stays an Array. + module SexpParser + module_function + + Sym = Struct.new(:name) do + def to_s + name + end + + def inspect + ":#{name}" + end + end + + Bare = Struct.new(:name) do + def to_s + name + end + + def inspect + name + end + end + + def parse_file(path) + parse(File.read(path, encoding: "UTF-8")) + end + + def parse(source) + sc = StringScanner.new(source) + result = read_form(sc) + skip_ws_and_comments(sc) + # Be lenient about a stray trailing `)` (encrypt.lsp ships with one + # extra close paren upstream). Warn but don't fail the whole pipeline. + while sc.peek(1) == ")" + warn "[brst-binding-ruby-gen] ignoring stray ')' at byte #{sc.pos}" + sc.getch + skip_ws_and_comments(sc) + end + raise "trailing content at offset #{sc.pos}" unless sc.eos? + plist_to_hash(result) + end + + def read_form(sc) + skip_ws_and_comments(sc) + raise "unexpected EOF" if sc.eos? + + case sc.peek(1) + when "(" + sc.getch + read_list(sc) + when ")" + raise "unexpected ')' at #{sc.pos}" + when '"' + read_string(sc) + when ":" + read_keyword(sc) + else + read_atom(sc) + end + end + + def read_list(sc) + items = [] + loop do + skip_ws_and_comments(sc) + raise "unterminated list" if sc.eos? + if sc.peek(1) == ")" + sc.getch + return items + end + items << read_form(sc) + end + end + + def read_string(sc) + sc.getch # consume opening quote + buf = +"" + loop do + raise "unterminated string at #{sc.pos}" if sc.eos? + ch = sc.getch + if ch == '"' + return buf + elsif ch == "\\" + esc = sc.getch + buf << case esc + when "n" then "\n" + when "t" then "\t" + when "r" then "\r" + when '"' then '"' + when "\\" then "\\" + when "c" then "\\c" # Doxygen \c — keep verbatim + else "\\#{esc}" + end + else + buf << ch + end + end + end + + # Permissive keyword: anything after `:` until whitespace / paren / quote / + # comment. Some libBeresta .lsp files mistakenly use Cyrillic letters in + # keyword names (e.g. `:ру` in doc_font.lsp instead of `:ru`); we don't + # want to crash on those — we just expose them as-is. + KEYWORD_RE = /:[^\s()";]+/.freeze + ATOM_RE = /[^\s()";]+/.freeze + + def read_keyword(sc) + tok = sc.scan(KEYWORD_RE) or raise "bad keyword at #{sc.pos}" + Sym.new(tok[1..]) + end + + def read_atom(sc) + tok = sc.scan(ATOM_RE) or raise "bad atom at #{sc.pos}: #{sc.peek(20).inspect}" + classify_atom(tok) + end + + def classify_atom(tok) + case tok + when /\A-?0x[0-9A-Fa-f]+\z/ then Integer(tok, 16) + when /\A-?\d+\z/ then tok.to_i + when /\A-?\d+\.\d+(?:[eE][+-]?\d+)?\z/ then tok.to_f + when "T", "t" then true + when "NIL", "nil" then nil + else Bare.new(tok) + end + end + + def skip_ws_and_comments(sc) + loop do + sc.skip(/\s+/) + if sc.peek(1) == ";" + sc.skip(/[^\n]*/) + else + break + end + end + end + + # If `arr` is a property list `(:k v :k v ...)` (even-length, every other + # element is a Sym), convert to Hash. Otherwise recurse and return Array. + def plist_to_hash(arr) + return arr unless arr.is_a?(Array) + + converted = arr.map { |e| plist_to_hash(e) } + + if converted.length.even? && converted.length.positive? && + converted.each_slice(2).all? { |k, _| k.is_a?(Sym) } + h = {} + converted.each_slice(2) { |k, v| h[k.name.to_sym] = v } + h + else + converted + end + end + end +end diff --git a/generator/lib/brst_binding_ruby_gen/symbol_table.rb b/generator/lib/brst_binding_ruby_gen/symbol_table.rb new file mode 100644 index 0000000..5c021dd --- /dev/null +++ b/generator/lib/brst_binding_ruby_gen/symbol_table.rb @@ -0,0 +1,239 @@ +# frozen_string_literal: true + +module BrstBindingRubyGen + # Aggregates all type vocabulary from every parsed .lsp file: + # - inner→outer scalar mappings from types.lsp + # - opaque pointers (`:pointers`) + # - aliases (`:definitions`) + # - enums (`:enums`) + # - structs (`:structs`) + # - hex/decimal constants (`:consts`) + # - page-size table (`:sizes` from page_sizes.lsp) + # + # Used both by the renderer (to emit types.rb) and to resolve function + # parameter / result types across files. + class SymbolTable + DEFAULT_INNER_MAP = { + "void" => :void + }.freeze + + attr_reader :inner_to_ffi, :pointers, :definitions, :enums, :structs, :consts, :sizes, + :enum_lookup_by_value + + def self.from(parsed_files) + st = new + parsed_files.each { |_path, tree| st.absorb(tree) } + st.finalize! + st + end + + def initialize + @inner_to_ffi = DEFAULT_INNER_MAP.dup + @pointers = {} # name(String) -> {name:} + @definitions = {} # name(String) -> {name:, original:} + @enums = {} # name(String) -> {name:, elements: [{element:, value:}]} + @structs = {} # name(String) -> {name:, fields: [{field:, type:}]} + @consts = {} # name(String) -> {name:, value:, en?, ru?} + @sizes = [] + @enum_lookup_by_value = {} # value(Integer) -> [enum_name, element] + end + + def absorb(tree) + return unless tree.is_a?(Hash) + + absorb_types(tree[:types]) if tree[:types] + absorb_pointers(tree[:pointers]) if tree[:pointers] + absorb_definitions(tree[:definitions]) if tree[:definitions] + absorb_enums(tree[:enums]) if tree[:enums] + absorb_structs(tree[:structs]) if tree[:structs] + absorb_consts(tree[:consts]) if tree[:consts] + absorb_sizes(tree[:sizes]) if tree[:sizes] + end + + # Resolve a libBeresta type name to a Ruby FFI type (Symbol). + # Falls back to `:pointer` for unknown `T*` names. + def resolve(raw) + return :void if raw.nil? + n = raw.to_s.strip + + if (mapped = @inner_to_ffi[n]) + return mapped + end + + # Hyphen↔underscore equivalence for inner mappings. + under = n.tr("-", "_") + hy = n.tr("_", "-") + [under, hy].each do |alt| + return @inner_to_ffi[alt] if @inner_to_ffi.key?(alt) + end + + # Pointer-suffix fallback: `BYTE*`, `Foo*` → :pointer + if n.end_with?("*") + return :pointer + end + + # Anything else: assume a typedef'd FFI symbol matching the name itself. + n.to_sym + end + + # All type names that get emitted as `typedef ..., :Name` in types.rb, + # in dependency order (types.lsp inner names first, then pointers, + # definitions, enums, structs). + def emitted_typedefs + out = [] + @inner_to_ffi.each do |inner, ffi| + next if inner == "void" + out << [inner, :scalar, ffi] + end + @pointers.each_key { |n| out << [n, :pointer, :pointer] } + @definitions.each { |n, d| out << [n, :alias, d[:original]] } + out + end + + def finalize! + # Merge `_`/`-` variants so resolution is symmetric (Doc_New uses + # "Error_Handler" while types.lsp registers "Error-Handler"). + additions = {} + @inner_to_ffi.each do |inner, ffi| + next if inner == "void" + under = inner.tr("-", "_") + additions[under] = ffi unless @inner_to_ffi.key?(under) + hy = inner.tr("_", "-") + additions[hy] = ffi unless @inner_to_ffi.key?(hy) + end + @inner_to_ffi.merge!(additions) + end + + private + + def absorb_types(rows) + Array(rows).each do |row| + next unless row.is_a?(Hash) + inner = row[:inner].to_s + outer = row[:outer].to_s + @inner_to_ffi[inner] = outer_to_ffi_symbol(outer) + end + end + + def outer_to_ffi_symbol(outer) + case outer + when "string" then :string + when "pointer" then :pointer + when "void" then :void + when /\Aint(8|16|32|64)?\z/, /\Auint(8|16|32|64)?\z/ then outer.to_sym + when "float" then :float + when "double" then :double + when "size_t" then :size_t + when "bool" then :bool + else outer.to_sym + end + end + + def absorb_pointers(rows) + Array(rows).each do |row| + next unless row.is_a?(Hash) + name = row[:name].to_s + @pointers[name] = { name: name } + end + end + + def absorb_definitions(rows) + Array(rows).each do |row| + next unless row.is_a?(Hash) + name = row[:name].to_s + original = row[:original].to_s + @definitions[name] = { name: name, original: original } + end + end + + def absorb_enums(rows) + Array(rows).each do |row| + next unless row.is_a?(Hash) + name = row[:name].to_s + elements = Array(row[:elements]).map do |el| + { + element: el[:element].to_s, + value: parse_numeric(el[:value]), + en: el[:en].to_s, + ru: el[:ru].to_s + } + end + @enums[name] = { name: name, elements: elements, en: row[:en].to_s, ru: row[:ru].to_s } + elements.each do |el| + next if el[:value].nil? + @enum_lookup_by_value[[name, el[:value]]] = el + end + end + end + + def absorb_structs(rows) + Array(rows).each do |row| + next unless row.is_a?(Hash) + name = row[:name].to_s + fields = Array(row[:fields]).map do |f| + { field: f[:field].to_s, type: f[:type].to_s, en: f[:en].to_s, ru: f[:ru].to_s } + end + @structs[name] = { name: name, fields: fields, en: row[:en].to_s, ru: row[:ru].to_s } + end + end + + def absorb_consts(rows) + Array(rows).each do |row| + next unless row.is_a?(Hash) + name = row[:name].to_s + @consts[name] = { name: name, value: row[:value], en: row[:en].to_s, ru: row[:ru].to_s } + end + end + + def absorb_sizes(rows) + Array(rows).each do |row| + next unless row.is_a?(Hash) + @sizes << { + caption: row[:caption].to_s, + id: row[:id].to_s, + origin: row[:origin].to_s, + width: row[:width].to_f, + height: row[:height].to_f + } + end + synthesize_page_sizes_enum! + end + + # `PageSizes` is referenced by functions in base.lsp and page_routines.lsp, + # but the .lsp files never declare it as an :enum. Upstream's C header + # `brst_page_sizes_iso_216.h` (used when LIBBRST_ISO_216_ONLY=ON, the + # default build mode) auto-numbers ISO 216 entries from 0 in the same + # source order they appear in page_sizes.lsp. Synthesise the matching + # FFI enum so callers can pass `:A4` instead of a magic integer. + def synthesize_page_sizes_enum! + iso216 = @sizes.select { |s| s[:origin] == "ISO 216" } + return if iso216.empty? + elements = iso216.each_with_index.map do |s, i| + { element: s[:id], value: i, en: "", ru: "" } + end + elements << { element: "EOF", value: iso216.size, en: "", ru: "" } + @enums["PageSizes"] = { + name: "PageSizes", + elements: elements, + en: "ISO 216 page size enum (synthesised from page_sizes.lsp).", + ru: "" + } + end + + def parse_numeric(v) + return nil if v.nil? + return v if v.is_a?(Numeric) + s = v.to_s.strip + return nil if s.empty? + if s =~ /\A-?0x[0-9A-Fa-f]+\z/ + Integer(s, 16) + elsif s =~ /\A-?\d+\z/ + s.to_i + elsif s =~ /\A-?\d+\.\d+/ + s.to_f + else + s + end + end + end +end From e8f04996b028a853eb186ebda8a7106777893b7e Mon Sep 17 00:00:00 2001 From: Kenta Ishizaki Date: Sat, 2 May 2026 11:02:32 +0900 Subject: [PATCH 3/5] Generate FFI bindings, add smoke + cross-check specs and macOS CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Generated from libBeresta master @ HEAD (post-#26 merge, gen/data layout): - 56 .lsp files processed - lib/brst/binding/ruby/types.rb consolidates 39 enums, 22 pointers, 8 definitions, 3 structs, 6 constants, plus the synthesised :PageSizes enum (ISO 216 build). - 36 per-file modules, 246 attached_function bindings; 22 captions are skipped with a recorded MISSING_SYMBOLS entry (mostly Asian font captions whose .lsp caption drifted from the C symbol, plus PNG image loaders compiled out of the default macOS build, plus the `Image` opaque type which upstream never declared in .lsp data). Smoke specs port demo/minimal.c to RSpec and add a "Hello, Beresta from Ruby!" text-write test using the built-in Helvetica path. Both produce a real %PDF-marked file on disk via libbrst.dylib. Cross-check spec asserts that our parser's per-file counts of functions / enums / pointers / definitions / structs / consts / sizes match libBeresta's auto-generated gen/json/*.json view of the same data — a structural sanity net that doesn't make us depend on JSON. CI runs on macos-14 across Ruby 3.2 / 3.3 / 3.4: clones libBeresta, builds the dylib, regenerates bindings, fails if the regeneration diff is non-empty (drift guard), runs rspec, then `gem build`. --- .github/workflows/ci.yml | 60 ++ lib/brst/binding/ruby/asian.rb | 46 ++ lib/brst/binding/ruby/base.rb | 50 ++ lib/brst/binding/ruby/date.rb | 42 ++ lib/brst/binding/ruby/destination.rb | 46 ++ lib/brst/binding/ruby/doc_compression.rb | 39 ++ lib/brst/binding/ruby/doc_embedded_file.rb | 39 ++ lib/brst/binding/ruby/doc_encoder.rb | 41 ++ lib/brst/binding/ruby/doc_encoding_utf.rb | 39 ++ lib/brst/binding/ruby/doc_ext_gstate.rb | 39 ++ lib/brst/binding/ruby/doc_font.rb | 43 ++ lib/brst/binding/ruby/doc_image_jpeg.rb | 40 ++ lib/brst/binding/ruby/doc_image_png.rb | 41 ++ lib/brst/binding/ruby/doc_image_tiff.rb | 41 ++ lib/brst/binding/ruby/doc_info.rb | 40 ++ lib/brst/binding/ruby/doc_matrix.rb | 46 ++ lib/brst/binding/ruby/doc_output_intent.rb | 40 ++ lib/brst/binding/ruby/doc_page.rb | 48 ++ lib/brst/binding/ruby/doc_page_pattern.rb | 46 ++ lib/brst/binding/ruby/doc_pattern.rb | 40 ++ lib/brst/binding/ruby/doc_pdfa.rb | 41 ++ lib/brst/binding/ruby/doc_save.rb | 40 ++ lib/brst/binding/ruby/doc_security.rb | 41 ++ lib/brst/binding/ruby/doc_viewer.rb | 41 ++ lib/brst/binding/ruby/doc_xobject.rb | 41 ++ lib/brst/binding/ruby/error.rb | 43 ++ lib/brst/binding/ruby/ext_gstate.rb | 41 ++ lib/brst/binding/ruby/font.rb | 40 ++ lib/brst/binding/ruby/geometry.rb | 93 ++++ lib/brst/binding/ruby/page_routines.rb | 56 ++ lib/brst/binding/ruby/page_sizes.rb | 38 ++ lib/brst/binding/ruby/page_xobject.rb | 40 ++ lib/brst/binding/ruby/stream_geometry.rb | 81 +++ lib/brst/binding/ruby/stream_text.rb | 48 ++ lib/brst/binding/ruby/text.rb | 67 +++ lib/brst/binding/ruby/types.rb | 618 +++++++++++++++++++++ lib/brst/binding/ruby/unicode_glyph.rb | 40 ++ lib/brst/binding/ruby/xobject.rb | 39 ++ spec/cross_check_spec.rb | 46 ++ spec/smoke/minimal_spec.rb | 89 +++ spec/spec_helper.rb | 17 + 41 files changed, 2466 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 lib/brst/binding/ruby/asian.rb create mode 100644 lib/brst/binding/ruby/base.rb create mode 100644 lib/brst/binding/ruby/date.rb create mode 100644 lib/brst/binding/ruby/destination.rb create mode 100644 lib/brst/binding/ruby/doc_compression.rb create mode 100644 lib/brst/binding/ruby/doc_embedded_file.rb create mode 100644 lib/brst/binding/ruby/doc_encoder.rb create mode 100644 lib/brst/binding/ruby/doc_encoding_utf.rb create mode 100644 lib/brst/binding/ruby/doc_ext_gstate.rb create mode 100644 lib/brst/binding/ruby/doc_font.rb create mode 100644 lib/brst/binding/ruby/doc_image_jpeg.rb create mode 100644 lib/brst/binding/ruby/doc_image_png.rb create mode 100644 lib/brst/binding/ruby/doc_image_tiff.rb create mode 100644 lib/brst/binding/ruby/doc_info.rb create mode 100644 lib/brst/binding/ruby/doc_matrix.rb create mode 100644 lib/brst/binding/ruby/doc_output_intent.rb create mode 100644 lib/brst/binding/ruby/doc_page.rb create mode 100644 lib/brst/binding/ruby/doc_page_pattern.rb create mode 100644 lib/brst/binding/ruby/doc_pattern.rb create mode 100644 lib/brst/binding/ruby/doc_pdfa.rb create mode 100644 lib/brst/binding/ruby/doc_save.rb create mode 100644 lib/brst/binding/ruby/doc_security.rb create mode 100644 lib/brst/binding/ruby/doc_viewer.rb create mode 100644 lib/brst/binding/ruby/doc_xobject.rb create mode 100644 lib/brst/binding/ruby/error.rb create mode 100644 lib/brst/binding/ruby/ext_gstate.rb create mode 100644 lib/brst/binding/ruby/font.rb create mode 100644 lib/brst/binding/ruby/geometry.rb create mode 100644 lib/brst/binding/ruby/page_routines.rb create mode 100644 lib/brst/binding/ruby/page_sizes.rb create mode 100644 lib/brst/binding/ruby/page_xobject.rb create mode 100644 lib/brst/binding/ruby/stream_geometry.rb create mode 100644 lib/brst/binding/ruby/stream_text.rb create mode 100644 lib/brst/binding/ruby/text.rb create mode 100644 lib/brst/binding/ruby/types.rb create mode 100644 lib/brst/binding/ruby/unicode_glyph.rb create mode 100644 lib/brst/binding/ruby/xobject.rb create mode 100644 spec/cross_check_spec.rb create mode 100644 spec/smoke/minimal_spec.rb create mode 100644 spec/spec_helper.rb diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..4c8bac1 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,60 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + +jobs: + macos: + name: macOS / Ruby ${{ matrix.ruby }} + runs-on: macos-14 + strategy: + fail-fast: false + matrix: + ruby: ['3.2', '3.3', '3.4'] + steps: + - uses: actions/checkout@v4 + + - name: Clone libBeresta (read-only) for codegen + native build + run: | + git clone --depth=1 https://github.com/libBeresta/libBeresta.git ../libBeresta + + - name: Install build deps (cmake, libpng, zlib, pkg-config) + run: | + brew update + brew install cmake libpng pkg-config + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + + - name: Build libBeresta.dylib + run: | + cmake -S . -B build \ + -DLIBBRST_SOURCE_DIR=$(cd ../libBeresta && pwd) \ + -DCMAKE_BUILD_TYPE=Release + cmake --build build --config Release -j + + - name: Regenerate FFI bindings from .lsp + run: | + ruby generator/bin/brst-binding-ruby-gen \ + --data-dir ../libBeresta/gen/data \ + --out-dir lib/brst/binding/ruby + + - name: Verify regeneration is idempotent (no diff) + run: | + if ! git diff --quiet -- lib/brst/binding/ruby; then + echo "Regeneration produced a diff — committed bindings drifted from generator output:" + git diff --stat -- lib/brst/binding/ruby + git diff -- lib/brst/binding/ruby + exit 1 + fi + + - name: Run tests + run: bundle exec rspec + + - name: Build gem + run: gem build brst-binding-ruby.gemspec diff --git a/lib/brst/binding/ruby/asian.rb b/lib/brst/binding/ruby/asian.rb new file mode 100644 index 0000000..bcfc02a --- /dev/null +++ b/lib/brst/binding/ruby/asian.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module Asian + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_UseJPFonts, [:Doc], :uint32 + safe_attach :BRST_UseKRFonts, [:Doc], :uint32 + safe_attach :BRST_UseCNSFonts, [:Doc], :uint32 + safe_attach :BRST_UseCNTFonts, [:Doc], :uint32 + safe_attach :BRST_UseJPEncodings, [:Doc], :uint32 + safe_attach :BRST_UseKREncodings, [:Doc], :uint32 + safe_attach :BRST_UseCNSEncodings, [:Doc], :uint32 + safe_attach :BRST_UseCNTEncodings, [:Doc], :uint32 + end + end + end +end diff --git a/lib/brst/binding/ruby/base.rb b/lib/brst/binding/ruby/base.rb new file mode 100644 index 0000000..d376c11 --- /dev/null +++ b/lib/brst/binding/ruby/base.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module Base + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Doc_New_Ex, [:pointer, :pointer, :pointer, :uint32, :pointer], :Doc + safe_attach :BRST_Version, [], :string + safe_attach :BRST_Doc_New, [:pointer, :pointer], :Doc + safe_attach :BRST_Doc_New_Empty, [], :Doc + safe_attach :BRST_Doc_Initialize, [:Doc], :uint32 + safe_attach :BRST_Doc_Destroy, [:Doc], :void + safe_attach :BRST_Doc_Initialized, [:Doc], :int32 + safe_attach :BRST_Doc_Destroy_All, [:Doc], :void + safe_attach :BRST_Doc_MMgr, [:Doc], :MMgr + safe_attach :BRST_Doc_Free, [:Doc], :void + safe_attach :BRST_PageSize_Width, [:PageSizes, :PageOrientation], :float + safe_attach :BRST_PageSize_Height, [:PageSizes, :PageOrientation], :float + end + end + end +end diff --git a/lib/brst/binding/ruby/date.rb b/lib/brst/binding/ruby/date.rb new file mode 100644 index 0000000..0298317 --- /dev/null +++ b/lib/brst/binding/ruby/date.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module Date + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Date_Now, [:Doc], :Date + safe_attach :BRST_Date_Part, [:Date, :Date_Parts], :int32 + safe_attach :BRST_Date_Validate, [:Date], :uint32 + safe_attach :BRST_Date_Free, [:Date], :void + end + end + end +end diff --git a/lib/brst/binding/ruby/destination.rb b/lib/brst/binding/ruby/destination.rb new file mode 100644 index 0000000..f710cae --- /dev/null +++ b/lib/brst/binding/ruby/destination.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module Destination + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Destination_SetXYZ, [:Destination, :float, :float, :float], :uint32 + safe_attach :BRST_Destination_SetFit, [:Destination], :uint32 + safe_attach :BRST_Destination_SetFitH, [:Destination, :float], :uint32 + safe_attach :BRST_Destination_SetFitV, [:Destination, :float], :uint32 + safe_attach :BRST_Destination_SetFitR, [:Destination, :float, :float, :float, :float], :uint32 + safe_attach :BRST_Destination_SetFitB, [:Destination], :uint32 + safe_attach :BRST_Destination_SetFitBH, [:Destination, :float], :uint32 + safe_attach :BRST_Destination_SetFitBV, [:Destination, :float], :uint32 + end + end + end +end diff --git a/lib/brst/binding/ruby/doc_compression.rb b/lib/brst/binding/ruby/doc_compression.rb new file mode 100644 index 0000000..c130212 --- /dev/null +++ b/lib/brst/binding/ruby/doc_compression.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module DocCompression + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Doc_SetCompressionMode, [:Doc, :CompressionMode], :uint32 + end + end + end +end diff --git a/lib/brst/binding/ruby/doc_embedded_file.rb b/lib/brst/binding/ruby/doc_embedded_file.rb new file mode 100644 index 0000000..a47a1fe --- /dev/null +++ b/lib/brst/binding/ruby/doc_embedded_file.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module DocEmbeddedFile + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Doc_AttachFile, [:Doc, :string], :EmbeddedFile + end + end + end +end diff --git a/lib/brst/binding/ruby/doc_encoder.rb b/lib/brst/binding/ruby/doc_encoder.rb new file mode 100644 index 0000000..31d7c31 --- /dev/null +++ b/lib/brst/binding/ruby/doc_encoder.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module DocEncoder + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Doc_Encoder_SetCurrent, [:Doc, :string], :uint32 + safe_attach :BRST_Doc_Encoder_Prepare, [:Doc, :string], :Encoder + safe_attach :BRST_Doc_Encoder_Current, [:Doc], :Encoder + end + end + end +end diff --git a/lib/brst/binding/ruby/doc_encoding_utf.rb b/lib/brst/binding/ruby/doc_encoding_utf.rb new file mode 100644 index 0000000..f5f7dd8 --- /dev/null +++ b/lib/brst/binding/ruby/doc_encoding_utf.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module DocEncodingUtf + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Doc_UseUTFEncodings, [:Doc], :uint32 + end + end + end +end diff --git a/lib/brst/binding/ruby/doc_ext_gstate.rb b/lib/brst/binding/ruby/doc_ext_gstate.rb new file mode 100644 index 0000000..cd5851b --- /dev/null +++ b/lib/brst/binding/ruby/doc_ext_gstate.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module DocExtGstate + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Doc_Create_ExtGState, [:Doc], :ExtGState + end + end + end +end diff --git a/lib/brst/binding/ruby/doc_font.rb b/lib/brst/binding/ruby/doc_font.rb new file mode 100644 index 0000000..9732353 --- /dev/null +++ b/lib/brst/binding/ruby/doc_font.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module DocFont + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Doc_Font, [:Doc, :string, :string], :Font + safe_attach :BRST_Doc_TTFont_LoadFromFile, [:Doc, :string, :int32], :Font + safe_attach :BRST_Doc_Type1Font_LoadFromFile, [:Doc, :string, :string], :string + safe_attach :BRST_Doc_TTFont_LoadFromFile2, [:Doc, :string, :uint32, :int32], :string + safe_attach :BRST_Doc_TTFont_LoadFromMemory, [:Doc, :pointer, :uint32, :int32], :string + end + end + end +end diff --git a/lib/brst/binding/ruby/doc_image_jpeg.rb b/lib/brst/binding/ruby/doc_image_jpeg.rb new file mode 100644 index 0000000..a202c18 --- /dev/null +++ b/lib/brst/binding/ruby/doc_image_jpeg.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module DocImageJpeg + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Doc_Image_Jpeg_LoadFromFile, [:Doc, :string], :Image + safe_attach :BRST_Doc_Image_Jpeg_LoadFromMemory, [:Doc, :pointer, :uint32], :Image + end + end + end +end diff --git a/lib/brst/binding/ruby/doc_image_png.rb b/lib/brst/binding/ruby/doc_image_png.rb new file mode 100644 index 0000000..d0e25ce --- /dev/null +++ b/lib/brst/binding/ruby/doc_image_png.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module DocImagePng + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Doc_Image_Png_LoadFromMemory, [:Doc, :pointer, :uint32], :Image + safe_attach :BRST_Doc_Image_Png_LoadFromFile, [:Doc, :string], :Image + safe_attach :BRST_Doc_Image_Png_LoadFromFile2, [:Doc, :string], :Image + end + end + end +end diff --git a/lib/brst/binding/ruby/doc_image_tiff.rb b/lib/brst/binding/ruby/doc_image_tiff.rb new file mode 100644 index 0000000..56fdde5 --- /dev/null +++ b/lib/brst/binding/ruby/doc_image_tiff.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module DocImageTiff + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Doc_Image_Raw1Bit_LoadFromMemory, [:Doc, :pointer, :uint32, :uint32, :uint32, :int32, :int32], :Image + safe_attach :BRST_Doc_Image_Raw_LoadFromFile, [:Doc, :string, :uint32, :uint32, :ColorSpace], :Image + safe_attach :BRST_Doc_Image_Raw_LoadFromMemory, [:Doc, :pointer, :uint32, :uint32, :ColorSpace, :uint32], :Image + end + end + end +end diff --git a/lib/brst/binding/ruby/doc_info.rb b/lib/brst/binding/ruby/doc_info.rb new file mode 100644 index 0000000..f47e017 --- /dev/null +++ b/lib/brst/binding/ruby/doc_info.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module DocInfo + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Doc_SetInfoAttr, [:Doc, :InfoType, :string], :uint32 + safe_attach :BRST_Doc_SetInfoDateAttr, [:Doc, :InfoType, :Date], :uint32 + end + end + end +end diff --git a/lib/brst/binding/ruby/doc_matrix.rb b/lib/brst/binding/ruby/doc_matrix.rb new file mode 100644 index 0000000..8570cb5 --- /dev/null +++ b/lib/brst/binding/ruby/doc_matrix.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module DocMatrix + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Doc_Matrix_Identity, [:Doc], :Matrix + safe_attach :BRST_Doc_Matrix_Free, [:Matrix], :void + safe_attach :BRST_Doc_Matrix_Multiply, [:Doc, :Matrix, :Matrix], :Matrix + safe_attach :BRST_Doc_Matrix_Translate, [:Doc, :Matrix, :float, :float], :Matrix + safe_attach :BRST_Doc_Matrix_Scale, [:Doc, :Matrix, :float, :float], :Matrix + safe_attach :BRST_Doc_Matrix_Rotate, [:Doc, :Matrix, :float], :Matrix + safe_attach :BRST_Doc_Matrix_RotateDeg, [:Doc, :Matrix, :float], :Matrix + safe_attach :BRST_Doc_Matrix_Skew, [:Doc, :Matrix, :float, :float], :Matrix + end + end + end +end diff --git a/lib/brst/binding/ruby/doc_output_intent.rb b/lib/brst/binding/ruby/doc_output_intent.rb new file mode 100644 index 0000000..51028f3 --- /dev/null +++ b/lib/brst/binding/ruby/doc_output_intent.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module DocOutputIntent + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Doc_OutputIntent_New, [:Doc, :string, :string, :string, :string, :Array], :OutputIntent + safe_attach :BRST_Doc_OutputIntent_Add, [:Doc, :OutputIntent], :uint32 + end + end + end +end diff --git a/lib/brst/binding/ruby/doc_page.rb b/lib/brst/binding/ruby/doc_page.rb new file mode 100644 index 0000000..83241c8 --- /dev/null +++ b/lib/brst/binding/ruby/doc_page.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module DocPage + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Doc_Pages_SetConfiguration, [:Doc, :uint32], :uint32 + safe_attach :BRST_Doc_Page_ByIndex, [:Doc, :uint32], :Page + safe_attach :BRST_Doc_Page_Layout, [:Doc], :PageLayout + safe_attach :BRST_Doc_Page_SetLayout, [:Doc, :PageLayout], :uint32 + safe_attach :BRST_Doc_Page_Mode, [:Doc], :PageMode + safe_attach :BRST_Doc_Page_SetMode, [:Doc, :PageMode], :uint32 + safe_attach :BRST_Doc_Page_Current, [:Doc], :Page + safe_attach :BRST_Doc_Page_Add, [:Doc], :Page + safe_attach :BRST_Doc_Page_Insert, [:Doc, :Page], :Page + safe_attach :BRST_Doc_Page_AddLabel, [:Doc, :uint32, :PageNumStyle, :uint32, :string], :uint32 + end + end + end +end diff --git a/lib/brst/binding/ruby/doc_page_pattern.rb b/lib/brst/binding/ruby/doc_page_pattern.rb new file mode 100644 index 0000000..171cb98 --- /dev/null +++ b/lib/brst/binding/ruby/doc_page_pattern.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module DocPagePattern + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Doc_Pattern_Tiling_Create, [:Doc, :float, :float, :float, :float, :float, :float, :Matrix], :Pattern + safe_attach :BRST_Doc_Pattern_Stream, [:Pattern], :Stream + safe_attach :BRST_Doc_Dict_RGBPatternFill_Select, [:Doc, :Dict, :float, :float, :float, :Pattern], :uint32 + safe_attach :BRST_Doc_Dict_RGBPatternFillUint_Select, [:Doc, :Dict, :uint8, :uint8, :uint8, :Pattern], :uint32 + safe_attach :BRST_Doc_Dict_RGBPatternFillHex_Select, [:Doc, :Dict, :uint8, :Pattern], :uint32 + safe_attach :BRST_Doc_Page_RGBPatternFill_Select, [:Doc, :Page, :float, :float, :float, :Pattern], :uint32 + safe_attach :BRST_Doc_Page_RGBPatternFillUint_Select, [:Doc, :Page, :uint8, :uint8, :uint8, :Pattern], :uint32 + safe_attach :BRST_Doc_Page_RGBPatternFillHex_Select, [:Doc, :Page, :uint8, :Pattern], :uint32 + end + end + end +end diff --git a/lib/brst/binding/ruby/doc_pattern.rb b/lib/brst/binding/ruby/doc_pattern.rb new file mode 100644 index 0000000..cba87e1 --- /dev/null +++ b/lib/brst/binding/ruby/doc_pattern.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module DocPattern + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Doc_Pattern_Tiling_Create, [:Doc, :float, :float, :float, :float, :float, :float, :Matrix], :Pattern + safe_attach :BRST_Doc_Pattern_Stream, [:Pattern], :Stream + end + end + end +end diff --git a/lib/brst/binding/ruby/doc_pdfa.rb b/lib/brst/binding/ruby/doc_pdfa.rb new file mode 100644 index 0000000..8deff6c --- /dev/null +++ b/lib/brst/binding/ruby/doc_pdfa.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module DocPdfa + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Doc_PDFA_SetConformance, [:Doc, :PDFAType], :uint32 + safe_attach :BRST_Doc_PDFA_AddXmpExtension, [:Doc, :string], :uint32 + safe_attach :BRST_Doc_PDFA_AppendOutputIntents, [:Doc, :string, :Dict], :uint32 + end + end + end +end diff --git a/lib/brst/binding/ruby/doc_save.rb b/lib/brst/binding/ruby/doc_save.rb new file mode 100644 index 0000000..88c978a --- /dev/null +++ b/lib/brst/binding/ruby/doc_save.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module DocSave + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Doc_SaveToStream, [:Doc], :uint32 + safe_attach :BRST_Doc_SaveToFile, [:Doc, :string], :uint32 + end + end + end +end diff --git a/lib/brst/binding/ruby/doc_security.rb b/lib/brst/binding/ruby/doc_security.rb new file mode 100644 index 0000000..1a89bfe --- /dev/null +++ b/lib/brst/binding/ruby/doc_security.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module DocSecurity + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Doc_SetPassword, [:Doc, :string, :string], :uint32 + safe_attach :BRST_Doc_SetPermission, [:Doc, :Permission], :uint32 + safe_attach :BRST_Doc_SetEncryptionMode, [:Doc, :EncryptMode, :uint32], :uint32 + end + end + end +end diff --git a/lib/brst/binding/ruby/doc_viewer.rb b/lib/brst/binding/ruby/doc_viewer.rb new file mode 100644 index 0000000..e76deef --- /dev/null +++ b/lib/brst/binding/ruby/doc_viewer.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module DocViewer + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Doc_SetOpenAction, [:Doc, :Destination], :uint32 + safe_attach :BRST_Doc_ViewerPreference, [:Doc], :ViewerPreference + safe_attach :BRST_Doc_SetViewerPreference, [:Doc, :ViewerPreference], :uint32 + end + end + end +end diff --git a/lib/brst/binding/ruby/doc_xobject.rb b/lib/brst/binding/ruby/doc_xobject.rb new file mode 100644 index 0000000..0ad85da --- /dev/null +++ b/lib/brst/binding/ruby/doc_xobject.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module DocXobject + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Doc_XObject_CreateFromImage, [:Doc, :Rect, :Image, :int32], :XObject + safe_attach :BRST_Doc_XObject_CreateAsWhiteRect, [:Doc, :Rect], :XObject + safe_attach :BRST_Doc_XObject_Create, [:Doc, :float, :float, :float, :float], :XObject + end + end + end +end diff --git a/lib/brst/binding/ruby/error.rb b/lib/brst/binding/ruby/error.rb new file mode 100644 index 0000000..e1c53d3 --- /dev/null +++ b/lib/brst/binding/ruby/error.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module Error + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Error_Check, [:Error], :uint32 + safe_attach :BRST_Doc_Error_Code, [:Doc], :uint32 + safe_attach :BRST_Doc_Error_DetailCode, [:Doc], :uint32 + safe_attach :BRST_Doc_Error_Reset, [:Doc], :void + safe_attach :BRST_Doc_Error_SetHandler, [:Doc, :pointer], :uint32 + end + end + end +end diff --git a/lib/brst/binding/ruby/ext_gstate.rb b/lib/brst/binding/ruby/ext_gstate.rb new file mode 100644 index 0000000..1b69bdd --- /dev/null +++ b/lib/brst/binding/ruby/ext_gstate.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module ExtGstate + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_ExtGState_SetAlphaStroke, [:ExtGState, :float], :uint32 + safe_attach :BRST_ExtGState_SetAlphaFill, [:ExtGState, :float], :uint32 + safe_attach :BRST_ExtGState_SetBlendMode, [:ExtGState, :BlendMode], :uint32 + end + end + end +end diff --git a/lib/brst/binding/ruby/font.rb b/lib/brst/binding/ruby/font.rb new file mode 100644 index 0000000..4b04895 --- /dev/null +++ b/lib/brst/binding/ruby/font.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module Font + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Font_Descent, [:Font, :float], :float + safe_attach :BRST_Font_TextWidth2, [:Font, :float, :float, :float, :string], :float + end + end + end +end diff --git a/lib/brst/binding/ruby/geometry.rb b/lib/brst/binding/ruby/geometry.rb new file mode 100644 index 0000000..b986447 --- /dev/null +++ b/lib/brst/binding/ruby/geometry.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module Geometry + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Page_GSave, [:Page], :uint32 + safe_attach :BRST_Page_GRestore, [:Page], :uint32 + safe_attach :BRST_Page_Concat, [:Page, :float, :float, :float, :float, :float, :float], :uint32 + safe_attach :BRST_Page_Translate, [:Page, :float, :float], :uint32 + safe_attach :BRST_Page_Scale, [:Page, :float, :float], :uint32 + safe_attach :BRST_Page_RotateDeg, [:Page, :float], :uint32 + safe_attach :BRST_Page_Rotate, [:Page, :float], :uint32 + safe_attach :BRST_Page_Skew, [:Page, :float, :float], :uint32 + safe_attach :BRST_Page_Circle, [:Page, :float, :float, :float], :uint32 + safe_attach :BRST_Page_Ellipse, [:Page, :float, :float, :float, :float], :uint32 + safe_attach :BRST_Page_Arc, [:Page, :float, :float, :float, :float, :float], :uint32 + safe_attach :BRST_Page_SetGrayFill, [:Page, :float], :uint32 + safe_attach :BRST_Page_SetGrayStroke, [:Page, :float], :uint32 + safe_attach :BRST_Page_SetRGBFill, [:Page, :float, :float, :float], :uint32 + safe_attach :BRST_Page_SetRGBFillUint, [:Page, :uint8, :uint8, :uint8], :uint32 + safe_attach :BRST_Page_SetRGBFillHex, [:Page, :uint32], :uint32 + safe_attach :BRST_Page_SetRGBStroke, [:Page, :float, :float, :float], :uint32 + safe_attach :BRST_Page_SetRGBStrokeUint, [:Page, :uint8, :uint8, :uint8], :uint32 + safe_attach :BRST_Page_SetRGBStrokeHex, [:Page, :uint32], :uint32 + safe_attach :BRST_Page_SetCMYKFill, [:Page, :float, :float, :float, :float], :uint32 + safe_attach :BRST_Page_SetCMYKStroke, [:Page, :float, :float, :float, :float], :uint32 + safe_attach :BRST_Page_Clip, [:Page], :uint32 + safe_attach :BRST_Page_Eoclip, [:Page], :uint32 + safe_attach :BRST_Page_Stroke, [:Page], :uint32 + safe_attach :BRST_Page_ClosePathStroke, [:Page], :uint32 + safe_attach :BRST_Page_Fill, [:Page], :uint32 + safe_attach :BRST_Page_Eofill, [:Page], :uint32 + safe_attach :BRST_Page_FillStroke, [:Page], :uint32 + safe_attach :BRST_Page_EofillStroke, [:Page], :uint32 + safe_attach :BRST_Page_ClosePathFillStroke, [:Page], :uint32 + safe_attach :BRST_Page_ClosePathEofillStroke, [:Page], :uint32 + safe_attach :BRST_Page_EndPath, [:Page], :uint32 + safe_attach :BRST_Page_MoveTo, [:Page, :float, :float], :uint32 + safe_attach :BRST_Page_LineTo, [:Page, :float, :float], :uint32 + safe_attach :BRST_Page_CurveTo, [:Page, :float, :float, :float, :float, :float, :float], :uint32 + safe_attach :BRST_Page_CurveTo2, [:Page, :float, :float, :float, :float], :uint32 + safe_attach :BRST_Page_CurveTo3, [:Page, :float, :float, :float, :float], :uint32 + safe_attach :BRST_Page_ClosePath, [:Page], :uint32 + safe_attach :BRST_Page_Rectangle, [:Page, :float, :float, :float, :float], :uint32 + safe_attach :BRST_Page_SetLineWidth, [:Page, :float], :uint32 + safe_attach :BRST_Page_SetLineCap, [:Page, :LineCap], :uint32 + safe_attach :BRST_Page_SetLineJoin, [:Page, :LineJoin], :uint32 + safe_attach :BRST_Page_SetMiterLimit, [:Page, :float], :uint32 + safe_attach :BRST_Page_SetDash, [:Page, :pointer, :uint32, :float], :uint32 + safe_attach :BRST_Page_SetFlat, [:Page, :float], :uint32 + safe_attach :BRST_Page_GrayFill, [:Page], :float + safe_attach :BRST_Page_GrayStroke, [:Page], :float + safe_attach :BRST_Page_StrokeColorSpace, [:Page], :ColorSpace + safe_attach :BRST_Page_FillColorSpace, [:Page], :ColorSpace + safe_attach :BRST_Page_LineWidth, [:Page], :float + safe_attach :BRST_Page_LineCap, [:Page], :LineCap + safe_attach :BRST_Page_LineJoin, [:Page], :LineJoin + safe_attach :BRST_Page_MiterLimit, [:Page], :float + safe_attach :BRST_Page_Flat, [:Page], :float + safe_attach :BRST_Page_Matrix, [:Page], :Matrix + end + end + end +end diff --git a/lib/brst/binding/ruby/page_routines.rb b/lib/brst/binding/ruby/page_routines.rb new file mode 100644 index 0000000..a29f3d4 --- /dev/null +++ b/lib/brst/binding/ruby/page_routines.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module PageRoutines + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Page_SetWidth, [:Page, :float], :uint32 + safe_attach :BRST_Page_SetHeight, [:Page, :float], :uint32 + safe_attach :BRST_Page_SetBoundary, [:Page, :PageBoundary, :float, :float, :float, :float], :uint32 + safe_attach :BRST_Page_SetSize, [:Page, :PageSizes, :PageOrientation], :uint32 + safe_attach :BRST_Page_SetRotate, [:Page, :uint16], :uint32 + safe_attach :BRST_Page_SetSlideShow, [:Page, :PageTransition, :float, :float], :uint32 + safe_attach :BRST_Page_SetHorizontalScaling, [:Page, :float], :uint32 + safe_attach :BRST_Page_GStateDepth, [:Page], :uint32 + safe_attach :BRST_Page_HorizontalScaling, [:Page], :float + safe_attach :BRST_Page_SetZoom, [:Page, :float], :uint32 + safe_attach :BRST_Page_Width, [:Page], :float + safe_attach :BRST_Page_Height, [:Page], :float + safe_attach :BRST_Page_GMode, [:Page], :uint16 + safe_attach :BRST_Page_MMgr, [:Page], :MMgr + safe_attach :BRST_Page_Insert_Shared_Content_Stream, [:Page, :Dict], :uint32 + safe_attach :BRST_Page_RawWrite, [:Page, :string], :uint32 + safe_attach :BRST_Page_SetExtGState, [:Page, :ExtGState], :uint32 + safe_attach :BRST_Page_CreateDestination, [:Page], :Destination + end + end + end +end diff --git a/lib/brst/binding/ruby/page_sizes.rb b/lib/brst/binding/ruby/page_sizes.rb new file mode 100644 index 0000000..a65e3ad --- /dev/null +++ b/lib/brst/binding/ruby/page_sizes.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module PageSizes + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + end + end + end +end diff --git a/lib/brst/binding/ruby/page_xobject.rb b/lib/brst/binding/ruby/page_xobject.rb new file mode 100644 index 0000000..ccd5bbe --- /dev/null +++ b/lib/brst/binding/ruby/page_xobject.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module PageXobject + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Page_XObject_Execute, [:Page, :XObject], :uint32 + safe_attach :BRST_Dict_XObject_Execute, [:Dict, :XObject], :uint32 + end + end + end +end diff --git a/lib/brst/binding/ruby/stream_geometry.rb b/lib/brst/binding/ruby/stream_geometry.rb new file mode 100644 index 0000000..d6245b6 --- /dev/null +++ b/lib/brst/binding/ruby/stream_geometry.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module StreamGeometry + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Stream_GSave, [:Stream], :uint32 + safe_attach :BRST_Stream_GRestore, [:Stream], :uint32 + safe_attach :BRST_Stream_Concat, [:Stream, :float, :float, :float, :float, :float, :float], :uint32 + safe_attach :BRST_Stream_Translate, [:Stream, :float, :float], :uint32 + safe_attach :BRST_Stream_Scale, [:Stream, :float, :float], :uint32 + safe_attach :BRST_Stream_RotateDeg, [:Stream, :float], :uint32 + safe_attach :BRST_Stream_Rotate, [:Stream, :float], :uint32 + safe_attach :BRST_Stream_Skew, [:Stream, :float, :float], :uint32 + safe_attach :BRST_Stream_Circle, [:Stream, :float, :float, :float], :uint32 + safe_attach :BRST_Stream_SetGrayFill, [:Stream, :float], :uint32 + safe_attach :BRST_Stream_SetGrayStroke, [:Stream, :float], :uint32 + safe_attach :BRST_Stream_SetRGBFill, [:Stream, :float, :float, :float], :uint32 + safe_attach :BRST_Stream_SetRGBFillUint, [:Stream, :uint8, :uint8, :uint8], :uint32 + safe_attach :BRST_Stream_SetRGBFillHex, [:Stream, :uint32], :uint32 + safe_attach :BRST_Stream_SetRGBStroke, [:Stream, :float, :float, :float], :uint32 + safe_attach :BRST_Stream_SetRGBStrokeUint, [:Stream, :uint8, :uint8, :uint8], :uint32 + safe_attach :BRST_Stream_SetRGBStrokeHex, [:Stream, :uint32], :uint32 + safe_attach :BRST_Stream_SetCMYKFill, [:Stream, :float, :float, :float, :float], :uint32 + safe_attach :BRST_Stream_SetCMYKStroke, [:Stream, :float, :float, :float, :float], :uint32 + safe_attach :BRST_Stream_Clip, [:Stream], :uint32 + safe_attach :BRST_Stream_Eoclip, [:Stream], :uint32 + safe_attach :BRST_Stream_Stroke, [:Stream], :uint32 + safe_attach :BRST_Stream_ClosePathStroke, [:Stream], :uint32 + safe_attach :BRST_Stream_Fill, [:Stream], :uint32 + safe_attach :BRST_Stream_Eofill, [:Stream], :uint32 + safe_attach :BRST_Stream_FillStroke, [:Stream], :uint32 + safe_attach :BRST_Stream_EofillStroke, [:Stream], :uint32 + safe_attach :BRST_Stream_ClosePathFillStroke, [:Stream], :uint32 + safe_attach :BRST_Stream_ClosePathEofillStroke, [:Stream], :uint32 + safe_attach :BRST_Stream_EndPath, [:Stream], :uint32 + safe_attach :BRST_Stream_MoveTo, [:Stream, :float, :float], :uint32 + safe_attach :BRST_Stream_LineTo, [:Stream, :float, :float], :uint32 + safe_attach :BRST_Stream_CurveTo, [:Stream, :float, :float, :float, :float, :float, :float], :uint32 + safe_attach :BRST_Stream_CurveTo2, [:Stream, :float, :float, :float, :float], :uint32 + safe_attach :BRST_Stream_CurveTo3, [:Stream, :float, :float, :float, :float], :uint32 + safe_attach :BRST_Stream_ClosePath, [:Stream], :uint32 + safe_attach :BRST_Stream_Rectangle, [:Stream, :float, :float, :float, :float], :uint32 + safe_attach :BRST_Stream_SetLineWidth, [:Stream, :float], :uint32 + safe_attach :BRST_Stream_SetLineCap, [:Stream, :LineCap], :uint32 + safe_attach :BRST_Stream_SetLineJoin, [:Stream, :LineJoin], :uint32 + safe_attach :BRST_Stream_SetMiterLimit, [:Stream, :float], :uint32 + safe_attach :BRST_Stream_SetDash, [:Stream, :pointer, :uint32, :float], :uint32 + safe_attach :BRST_Stream_SetFlat, [:Stream, :float], :uint32 + end + end + end +end diff --git a/lib/brst/binding/ruby/stream_text.rb b/lib/brst/binding/ruby/stream_text.rb new file mode 100644 index 0000000..8a235d5 --- /dev/null +++ b/lib/brst/binding/ruby/stream_text.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module StreamText + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Stream_BeginText, [:Stream], :uint32 + safe_attach :BRST_Stream_EndText, [:Stream], :uint32 + safe_attach :BRST_Stream_SetTextLeading, [:Stream, :float], :uint32 + safe_attach :BRST_Stream_SetTextRenderingMode, [:Stream, :TextRenderingMode], :uint32 + safe_attach :BRST_Stream_MoveTextPos, [:Stream, :float, :float], :uint32 + safe_attach :BRST_Stream_MoveTextPos2, [:Stream, :float, :float], :uint32 + safe_attach :BRST_Stream_SetTextMatrix, [:Stream, :float, :float, :float, :float, :float, :float], :uint32 + safe_attach :BRST_Stream_ShowText, [:Stream, :Font, :string], :uint32 + safe_attach :BRST_Stream_TextOut, [:Stream, :Font, :float, :float, :string], :uint32 + safe_attach :BRST_Stream_MoveToNextLine, [:Stream], :uint32 + end + end + end +end diff --git a/lib/brst/binding/ruby/text.rb b/lib/brst/binding/ruby/text.rb new file mode 100644 index 0000000..cb0f82d --- /dev/null +++ b/lib/brst/binding/ruby/text.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module Text + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_Page_BeginText, [:Page], :uint32 + safe_attach :BRST_Page_EndText, [:Page], :uint32 + safe_attach :BRST_Page_SetTextLeading, [:Page, :float], :uint32 + safe_attach :BRST_Page_SetFontAndSize, [:Page, :Font, :float], :uint32 + safe_attach :BRST_Dict_SetFontAndSize, [:Dict, :Font, :float], :uint32 + safe_attach :BRST_Page_SetTextRenderingMode, [:Page, :TextRenderingMode], :uint32 + safe_attach :BRST_Page_SetTextRise, [:Page, :float], :uint32 + safe_attach :BRST_Page_MoveTextPos, [:Page, :float, :float], :uint32 + safe_attach :BRST_Page_MoveTextPos2, [:Page, :float, :float], :uint32 + safe_attach :BRST_Page_SetTextMatrix, [:Page, :float, :float, :float, :float, :float, :float], :uint32 + safe_attach :BRST_Page_MoveToNextLine, [:Page], :uint32 + safe_attach :BRST_Page_ShowText, [:Page, :string], :uint32 + safe_attach :BRST_Page_ShowTextNextLine, [:Page, :string], :uint32 + safe_attach :BRST_Page_ShowTextNextLineEx, [:Page, :float, :float, :string], :uint32 + safe_attach :BRST_Page_TextOut, [:Page, :float, :float, :string], :uint32 + safe_attach :BRST_Page_TextRect, [:Page, :float, :float, :float, :float, :string, :TextAlignment, :pointer], :uint32 + safe_attach :BRST_Page_SetCharSpace, [:Page, :float], :uint32 + safe_attach :BRST_Page_SetWordSpace, [:Page, :float], :uint32 + safe_attach :BRST_Page_TextMatrix, [:Page], :Matrix + safe_attach :BRST_Page_TextLeading, [:Page], :float + safe_attach :BRST_Page_TextRenderingMode, [:Page], :TextRenderingMode + safe_attach :BRST_Page_TextRise, [:Page], :float + safe_attach :BRST_Page_CharSpace, [:Page], :float + safe_attach :BRST_Page_WordSpace, [:Page], :float + safe_attach :BRST_Page_CurrentTextPos2, [:Page, :pointer], :uint32 + safe_attach :BRST_Page_CurrentFont, [:Page], :Font + safe_attach :BRST_Page_CurrentFontSize, [:Page], :float + safe_attach :BRST_Page_TextWidth, [:Page, :string], :float + safe_attach :BRST_Page_MeasureText, [:Page, :string, :float, :int32, :pointer], :uint32 + end + end + end +end diff --git a/lib/brst/binding/ruby/types.rb b/lib/brst/binding/ruby/types.rb new file mode 100644 index 0000000..93b135e --- /dev/null +++ b/lib/brst/binding/ruby/types.rb @@ -0,0 +1,618 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" + +module Brst + module Binding + module Ruby + # Centralised type vocabulary for every generated FFI module. + # + # `Types.apply(mod)` registers every typedef, enum, and struct + # alias on `mod` (which must already `extend FFI::Library`). + # See generator/lib/brst_binding_ruby_gen/renderer.rb. + module Types + module_function + + # Each generated `.rb` calls `Types.apply(self)` so that + # all type symbols (`:Doc`, `:STATUS`, `:GMode`, ...) resolve + # uniformly regardless of which .lsp file they originated in. + def apply(mod) + return if mod.instance_variable_get(:@brst_types_applied) + mod.instance_variable_set(:@brst_types_applied, true) + apply_scalars(mod) + apply_pointers(mod) + apply_enums(mod) + apply_structs(mod) + apply_definitions(mod) + end + + # ---- scalars (from types.lsp :types) ---- + def apply_scalars(mod) + mod.typedef :string, :CSTR + mod.typedef :int32, :INT + mod.typedef :uint32, :UINT + mod.typedef :int64, :INT64 + mod.typedef :uint64, :UINT64 + mod.typedef :int32, :INT32 + mod.typedef :uint32, :UINT32 + mod.typedef :int16, :INT16 + mod.typedef :uint16, :UINT16 + mod.typedef :int8, :INT8 + mod.typedef :uint8, :UINT8 + mod.typedef :uint8, :BYTE + mod.typedef :float, :REAL + mod.typedef :double, :DOUBLE + mod.typedef :int32, :BOOL + mod.typedef :uint32, :STATUS + mod.typedef :uint16, :CID + mod.typedef :uint16, :UNICODE + mod.typedef :pointer, :RAW_POINTER + mod.typedef :pointer, :DASH_PATTERN + mod.typedef :pointer, :Error_Handler + mod.typedef :pointer, :Alloc_Func + mod.typedef :pointer, :Free_Func + mod.typedef :pointer, :RAW_POINTER + mod.typedef :pointer, :DASH_PATTERN + mod.typedef :pointer, :Error_Handler + mod.typedef :pointer, :Alloc_Func + mod.typedef :pointer, :Free_Func +end + +# ---- opaque pointers ---- +def apply_pointers(mod) + mod.typedef :pointer, :Array + mod.typedef :pointer, :Date + mod.typedef :pointer, :Dict + mod.typedef :pointer, :Doc + mod.typedef :pointer, :Error + mod.typedef :pointer, :FontDef + mod.typedef :pointer, :Matrix + mod.typedef :pointer, :MMgr + mod.typedef :pointer, :Stream + mod.typedef :pointer, :Xref +end + +# ---- enums (improvement #2: each enum acts as an :int-backed typedef) ---- +def apply_enums(mod) + mod.enum :AnnotType, [:ANNOT_TEXT, :ANNOT_LINK, :ANNOT_FREE_TEXT, :ANNOT_LINE, :ANNOT_SQUARE, :ANNOT_CIRCLE, :ANNOT_POLYGON, :ANNOT_POLYLINE, :ANNOT_HIGHLIGHT, :ANNOT_UNDERLINE, :ANNOT_SQUIGGLY, :ANNOT_STRIKEOUT, :ANNOT_STAMP, :ANNOT_CARET, :ANNOT_INK, :ANNOT_POPUP, :ANNOT_FILE_ATTACHMENT, :ANNOT_SOUND, :ANNOT_MOVIE, :ANNOT_WIDGET, :ANNOT_SCREEN, :ANNOT_PRINTER_MARK, :ANNOT_TRAPNET, :ANNOT_WATERMARK, :ANNOT_3D, :ANNOT_REDACT] + mod.enum :AnnotFlags, [:ANNOT_FLAG_INVISIBLE, :ANNOT_FLAG_HIDDEN, :ANNOT_FLAG_PRINT, :ANNOT_FLAG_NOZOOM, :ANNOT_FLAG_NOROTATE, :ANNOT_FLAG_NOVIEW, :ANNOT_FLAG_READONLY, :ANNOT_FLAG_LOCKED, :ANNOT_FLAG_TOGGLE_NOVIEW, :ANNOT_FLAG_LOCKED_CONTENT] + mod.enum :AnnotHighlightMode, [:ANNOT_HIGHLIGHT_MODE_NONE, :ANNOT_HIGHLIGHT_MODE_INVERT, :ANNOT_HIGHLIGHT_MODE_OUTLINE, :ANNOT_HIGHLIGHT_MODE_PUSH] + mod.enum :AnnotIcon, [:ANNOT_ICON_COMMENT, :ANNOT_ICON_KEY, :ANNOT_ICON_NOTE, :ANNOT_ICON_HELP, :ANNOT_ICON_NEW_PARAGRAPH, :ANNOT_ICON_PARAGRAPH, :ANNOT_ICON_INSERT] + mod.enum :AnnotLineEnd, [:ANNOT_LINE_END_NONE, :ANNOT_LINE_END_SQUARE, :ANNOT_LINE_END_CIRCLE, :ANNOT_LINE_END_DIAMOND, :ANNOT_LINE_END_OPENARROW, :ANNOT_LINE_END_CLOSEDARROW, :ANNOT_LINE_END_BUTT, :ANNOT_LINE_END_ROPENARROW, :ANNOT_LINE_END_RCLOSEDARROW, :ANNOT_LINE_END_SLASH] + mod.enum :AnnotLineCapPosition, [:ANNOT_LINE_CAP_INLINE, :ANNOT_LINE_CAP_TOP] + mod.enum :AnnotStampStyle, [:ANNOT_STAMP_APPROVED, :ANNOT_STAMP_EXPERIMENTAL, :ANNOT_STAMP_NOTAPPROVED, :ANNOT_STAMP_ASIS, :ANNOT_STAMP_EXPIRED, :ANNOT_STAMP_NOTFORPUBLICRELEASE, :ANNOT_STAMP_CONFIDENTIAL, :ANNOT_STAMP_FINAL, :ANNOT_STAMP_SOLD, :ANNOT_STAMP_DEPARTMENTAL, :ANNOT_STAMP_FORCOMMENT, :ANNOT_STAMP_TOPSECRET, :ANNOT_STAMP_DRAFT, :ANNOT_STAMP_FORPUBLICRELEASE] + mod.enum :GMode, [:GMODE_PAGE_DESCRIPTION, 1, :GMODE_PATH_OBJECT, 2, :GMODE_TEXT_OBJECT, 4, :GMODE_CLIPPING_PATH, 8, :GMODE_SHADING, 16, :GMODE_INLINE_IMAGE, 32, :GMODE_EXTERNAL_OBJECT, 64] + mod.enum :CompressionMode, [:COMP_MODE_NONE, 0, :COMP_MODE_TEXT, 1, :COMP_MODE_IMAGE, 2, :COMP_MODE_METADATA, 4, :COMP_MODE_ALL, 15] + mod.enum :Permission, [:ENABLE_READ, 0, :ENABLE_PRINT, 4, :ENABLE_EDIT_ALL, 8, :ENABLE_COPY, 16, :ENABLE_EDIT, 32] + mod.enum :ViewerPreference, [:HIDE_TOOLBAR, 1, :HIDE_MENUBAR, 2, :HIDE_WINDOW_UI, 4, :FIT_WINDOW, 8, :CENTER_WINDOW, 16, :PRINT_SCALING_NONE, 32, :DISPLAY_DOC_TITLE, 64] + mod.enum :Date_Parts, [:DATE_PART_YEAR, :DATE_PART_MONTH, :DATE_PART_DAY, :DATE_PART_HOUR, :DATE_PART_MINUTE, :DATE_PART_SECOND, :DATE_PART_HOUR_OFFSET, :DATE_PART_MINUTE_OFFSET, :DATE_PART_UT_RELATIONSHIP] + mod.enum :UT_Relationship, [:UT_RELATIONSHIP_NONE, :UT_RELATIONSHIP_PLUS, :UT_RELATIONSHIP_MINUS, :UT_RELATIONSHIP_ZERO] + mod.enum :PdfVer, [:VER_10, :VER_11, :VER_12, :VER_13, :VER_14, :VER_15, :VER_16, :VER_17, :VER_20] + mod.enum :InfoType, [:INFO_CREATION_DATE, :INFO_MOD_DATE, :INFO_AUTHOR, :INFO_CREATOR, :INFO_PRODUCER, :INFO_TITLE, :INFO_SUBJECT, :INFO_KEYWORDS, :INFO_TRAPPED, :INFO_GTS_PDFX] + mod.enum :EncryptMode, [:ENCRYPT_R0, 0, :ENCRYPT_R1, 1, :ENCRYPT_R2, 2, :ENCRYPT_R3, 3, :ENCRYPT_R4, 4] + mod.enum :ErrorKind, [:ARRAY_COUNT_ERR, 4097, :ARRAY_ITEM_NOT_FOUND, 4098, :ARRAY_ITEM_UNEXPECTED_TYPE, 4099, :BINARY_LENGTH_ERR, 4100, :CANNOT_GET_PALETTE, 4101, :DICT_COUNT_ERR, 4103, :DICT_ITEM_NOT_FOUND, 4104, :DICT_ITEM_UNEXPECTED_TYPE, 4105, :DICT_STREAM_LENGTH_NOT_FOUND, 4106, :DOC_ENCRYPTDICT_NOT_FOUND, 4107, :DOC_INVALID_OBJECT, 4108, :DUPLICATE_REGISTRATION, 4110, :EXCEED_JWW_CODE_NUM_LIMIT, 4111, :ENCRYPT_INVALID_PASSWORD, 4113, :ERR_UNKNOWN_CLASS, 4115, :EXCEED_GSTATE_LIMIT, 4116, :FAILED_TO_ALLOC_MEM, 4117, :FILE_IO_ERROR, 4118, :FILE_OPEN_ERROR, 4119, :FONT_EXISTS, 4121, :FONT_INVALID_WIDTH_TABLE, 4122, :INVALID_AFM_HEADER, 4123, :INVALID_ANNOTATION, 4124, :INVALID_BIT_PER_COMPONENT, 4126, :INVALID_CHAR_MATRIX_DATA, 4127, :INVALID_COLOR_SPACE, 4128, :INVALID_COMPRESSION_MODE, 4129, :INVALID_DATE_TIME, 4130, :INVALID_DESTINATION, 4131, :INVALID_DOCUMENT, 4133, :INVALID_DOCUMENT_STATE, 4134, :INVALID_ENCODER, 4135, :INVALID_ENCODER_TYPE, 4136, :INVALID_ENCODING_NAME, 4139, :INVALID_ENCRYPT_KEY_LEN, 4140, :INVALID_FONTDEF_DATA, 4141, :INVALID_FONTDEF_TYPE, 4142, :INVALID_FONT_NAME, 4143, :INVALID_IMAGE, 4144, :INVALID_JPEG_DATA, 4145, :INVALID_N_DATA, 4146, :INVALID_OBJECT, 4147, :INVALID_OBJ_ID, 4148, :INVALID_OPERATION, 4149, :INVALID_OUTLINE, 4150, :INVALID_PAGE, 4151, :INVALID_PAGES, 4152, :INVALID_PARAMETER, 4153, :INVALID_PNG_IMAGE, 4155, :INVALID_STREAM, 4156, :MISSING_FILE_NAME_ENTRY, 4157, :INVALID_TTC_FILE, 4159, :INVALID_TTC_INDEX, 4160, :INVALID_WX_DATA, 4161, :ITEM_NOT_FOUND, 4162, :LIBPNG_ERROR, 4163, :NAME_INVALID_VALUE, 4164, :NAME_OUT_OF_RANGE, 4165, :PAGES_MISSING_KIDS_ENTRY, 4169, :PAGE_CANNOT_FIND_OBJECT, 4170, :PAGE_CANNOT_GET_ROOT_PAGES, 4171, :PAGE_CANNOT_RESTORE_GSTATE, 4172, :PAGE_CANNOT_SET_PARENT, 4173, :PAGE_FONT_NOT_FOUND, 4174, :PAGE_INVALID_FONT, 4175, :PAGE_INVALID_FONT_SIZE, 4176, :PAGE_INVALID_GMODE, 4177, :PAGE_INVALID_INDEX, 4178, :PAGE_INVALID_ROTATE_VALUE, 4179, :PAGE_INVALID_SIZE, 4180, :PAGE_INVALID_XOBJECT, 4181, :PAGE_OUT_OF_RANGE, 4182, :REAL_OUT_OF_RANGE, 4183, :STREAM_EOF, 4184, :STREAM_READLN_CONTINUE, 4185, :STRING_OUT_OF_RANGE, 4187, :THIS_FUNC_WAS_SKIPPED, 4188, :TTF_CANNOT_EMBED_FONT, 4189, :TTF_INVALID_CMAP, 4190, :TTF_INVALID_FORMAT, 4191, :TTF_MISSING_TABLE, 4192, :UNSUPPORTED_FONT_TYPE, 4193, :UNSUPPORTED_JPEG_FORMAT, 4195, :UNSUPPORTED_TYPE1_FONT, 4196, :XREF_COUNT_ERR, 4197, :ZLIB_ERROR, 4198, :INVALID_PAGE_INDEX, 4199, :INVALID_URI, 4200, :PAGE_LAYOUT_OUT_OF_RANGE, 4201, :PAGE_MODE_OUT_OF_RANGE, 4208, :PAGE_NUM_STYLE_OUT_OF_RANGE, 4209, :ANNOT_INVALID_ICON, 4210, :ANNOT_INVALID_BORDER_STYLE, 4211, :PAGE_INVALID_DIRECTION, 4212, :PAGE_INSUFFICIENT_SPACE, 4214, :PAGE_INVALID_DISPLAY_TIME, 4215, :PAGE_INVALID_TRANSITION_TIME, 4216, :INVALID_PAGE_SLIDESHOW_TYPE, 4217, :EXT_GSTATE_OUT_OF_RANGE, 4224, :INVALID_EXT_GSTATE, 4225, :EXT_GSTATE_READ_ONLY, 4226, :INVALID_ICC_COMPONENT_NUM, 4229, :PAGE_INVALID_BOUNDARY, 4230, :INVALID_SHADING_TYPE, 4232] + mod.enum :LineCap, [:BUTT_CAP, :ROUND_CAP, :PROJECTING_SQUARE_CAP] + mod.enum :LineJoin, [:MITER_JOIN, :ROUND_JOIN, :BEVEL_JOIN] + mod.enum :BorderStyle, [:BORDERSTYLE_SOLID, :BORDERSTYLE_DASHED, :BORDERSTYLE_BEVELED, :BORDERSTYLE_INSET, :BORDERSTYLE_UNDERLINED] + mod.enum :BlendMode, [:BLENDMODE_NORMAL, :BLENDMODE_COMPATIBLE, :BLENDMODE_MULTIPLY, :BLENDMODE_SCREEN, :BLENDMODE_OVERLAY, :BLENDMODE_DARKEN, :BLENDMODE_LIGHTEN, :BLENDMODE_COLOR_DODGE, :BLENDMODE_COLOR_BURN, :BLENDMODE_HARD_LIGHT, :BLENDMODE_SOFT_LIGHT, :BLENDMODE_DIFFERENCE, :BLENDMODE_EXCLUSION] + mod.enum :ColorSpace, [:COLORSPACE_DEVICEGRAY, :COLORSPACE_DEVICERGB, :COLORSPACE_DEVICECMYK, :COLORSPACE_CALGRAY, :COLORSPACE_CALRGB, :COLORSPACE_LAB, :COLORSPACE_ICCBASED, :COLORSPACE_SEPARATION, :COLORSPACE_DEVICEN, :COLORSPACE_INDEXED, :COLORSPACE_PATTERN] + mod.enum :PageLayout, [:PAGE_LAYOUT_SINGLE, :PAGE_LAYOUT_ONE_COLUMN, :PAGE_LAYOUT_TWO_COLUMN_LEFT, :PAGE_LAYOUT_TWO_COLUMN_RIGHT, :PAGE_LAYOUT_TWO_PAGE_LEFT, :PAGE_LAYOUT_TWO_PAGE_RIGHT] + mod.enum :PageMode, [:PAGE_MODE_USE_NONE, :PAGE_MODE_USE_OUTLINE, :PAGE_MODE_USE_THUMBS, :PAGE_MODE_FULL_SCREEN, :PAGE_MODE_USE_OC, :PAGE_MODE_USE_ATTACHMENTS] + mod.enum :PageNum, [:PAGE_NUM_DECIMAL, :PAGE_NUM_UPPER_ROMAN, :PAGE_NUM_LOWER_ROMAN, :PAGE_NUM_UPPER_LETTERS, :PAGE_NUM_LOWER_LETTERS] + mod.enum :PageBoundary, [:PAGE_MEDIABOX, :PAGE_CROPBOX, :PAGE_BLEEDBOX, :PAGE_TRIMBOX, :PAGE_ARTBOX] + mod.enum :PageTransition, [:PAGE_TRANSITION_WIPE_RIGHT, :PAGE_TRANSITION_WIPE_UP, :PAGE_TRANSITION_WIPE_LEFT, :PAGE_TRANSITION_WIPE_DOWN, :PAGE_TRANSITION_BARN_DOORS_HORIZONTAL_OUT, :PAGE_TRANSITION_BARN_DOORS_HORIZONTAL_IN, :PAGE_TRANSITION_BARN_DOORS_VERTICAL_OUT, :PAGE_TRANSITION_BARN_DOORS_VERTICAL_IN, :PAGE_TRANSITION_BOX_OUT, :PAGE_TRANSITION_BOX_IN, :PAGE_TRANSITION_BLINDS_HORIZONTAL, :PAGE_TRANSITION_BLINDS_VERTICAL, :PAGE_TRANSITION_DISSOLVE, :PAGE_TRANSITION_GLITTER_RIGHT, :PAGE_TRANSITION_GLITTER_DOWN, :PAGE_TRANSITION_GLITTER_TOP_LEFT_TO_BOTTOM_RIGHT, :PAGE_TRANSITION_REPLACE] + mod.enum :PageOrientation, [:PAGE_ORIENTATION_PORTRAIT, :PAGE_ORIENTATION_LANDSCAPE] + mod.enum :PageSizes, [:"4A0", 0, :"2A0", 1, :A0, 2, :A0_PLUS, 3, :A1, 4, :A1_PLUS, 5, :A2, 6, :A3, 7, :A3_PLUS, 8, :A4, 9, :A5, 10, :A6, 11, :A7, 12, :A8, 13, :A9, 14, :A10, 15, :B0, 16, :B0_PLUS, 17, :B1, 18, :B1_PLUS, 19, :B2, 20, :B2_PLUS, 21, :B3, 22, :B4, 23, :B5, 24, :B6, 25, :B7, 26, :B8, 27, :B9, 28, :B10, 29, :B11, 30, :B12, 31, :B13, 32, :C0, 33, :C1, 34, :C2, 35, :C3, 36, :C4, 37, :C5, 38, :C6, 39, :C7, 40, :C8, 41, :C9, 42, :C10, 43, :EOF, 44] + mod.enum :TextRenderingMode, [:TEXT_RENDERING_MODE_FILL, :TEXT_RENDERING_MODE_STROKE, :TEXT_RENDERING_MODE_FILL_THEN_STROKE, :TEXT_RENDERING_MODE_INVISIBLE, :TEXT_RENDERING_MODE_FILL_CLIPPING, :TEXT_RENDERING_MODE_STROKE_CLIPPING, :TEXT_RENDERING_MODE_FILL_STROKE_CLIPPING, :TEXT_RENDERING_MODE_CLIPPING] + mod.enum :TextAlignment, [:TEXT_ALIGN_LEFT, :TEXT_ALIGN_RIGHT, :TEXT_ALIGN_CENTER, :TEXT_ALIGN_JUSTIFY] + mod.enum :WritingMode, [:WRITING_MODE_HORIZONTAL, :WRITING_MODE_VERTICAL] +end + +# ---- structs (improvement #3: by_value alias) ---- +def apply_structs(mod) + unless mod.const_defined?(:RGBColorStruct, false) + klass = Class.new(FFI::Struct) do + layout :r, :float, + :g, :float, + :b, :float + end + mod.const_set(:RGBColorStruct, klass) + end + mod.typedef mod.const_get(:RGBColorStruct).by_value, :RGBColor + unless mod.const_defined?(:CMYKColorStruct, false) + klass = Class.new(FFI::Struct) do + layout :c, :float, + :m, :float, + :y, :float, + :k, :float + end + mod.const_set(:CMYKColorStruct, klass) + end + mod.typedef mod.const_get(:CMYKColorStruct).by_value, :CMYKColor + unless mod.const_defined?(:PointStruct, false) + klass = Class.new(FFI::Struct) do + layout :x, :float, + :y, :float + end + mod.const_set(:PointStruct, klass) + end + mod.typedef mod.const_get(:PointStruct).by_value, :Point + unless mod.const_defined?(:RectStruct, false) + klass = Class.new(FFI::Struct) do + layout :left, :float, + :bottom, :float, + :right, :float, + :top, :float + end + mod.const_set(:RectStruct, klass) + end + mod.typedef mod.const_get(:RectStruct).by_value, :Rect + unless mod.const_defined?(:TextWidthStruct, false) + klass = Class.new(FFI::Struct) do + layout :numchars, :uint32, + :numwords, :uint32, + :width, :uint32, + :numspace, :uint32 + end + mod.const_set(:TextWidthStruct, klass) + end + mod.typedef mod.const_get(:TextWidthStruct).by_value, :TextWidth +end + +# ---- definitions (typedef aliases) ---- +def apply_definitions(mod) + mod.typedef :Dict, :Annotation + mod.typedef :Array, :Destination + mod.typedef :Dict, :OutputIntent + mod.typedef :Dict, :ExData + mod.typedef :Dict, :ExtGState + mod.typedef :Dict, :Font + mod.typedef :Dict, :JavaScript + mod.typedef :Dict, :Page + mod.typedef :Dict, :Pattern + mod.typedef :Dict, :XObject + end + end + end + end +end + +module Brst + module Binding + module Ruby + module Const + BRST_TRUE = 1 + BRST_FALSE = 0 + BRST_OK = 0 + BRST_PI = 3.14159265358979323846 + BRST_MM = 2.834646 + BRST_IN = 72.00000 + end + end + end +end + +module Brst + module Binding + module Ruby + module PageSizesMM + TABLE = { + "US_LETTER" => { caption: "Letter", origin: "US Loose", width_mm: 216.0, height_mm: 279.0 }, + "US_LEGAL" => { caption: "Legal", origin: "US Loose", width_mm: 216.0, height_mm: 356.0 }, + "US_TABLOID" => { caption: "Tabloid", origin: "US Loose", width_mm: 279.0, height_mm: 432.0 }, + "US_LEDGER" => { caption: "Ledger", origin: "US Loose", width_mm: 432.0, height_mm: 279.0 }, + "US_JUNIOR_LEGAL" => { caption: "Junior Legal", origin: "US Loose", width_mm: 127.0, height_mm: 203.0 }, + "US_HALF_LETTER" => { caption: "Half Letter", origin: "US Loose", width_mm: 140.0, height_mm: 216.0 }, + "US_GOVERNMENT_LETTER" => { caption: "Government Letter", origin: "US Loose", width_mm: 203.0, height_mm: 267.0 }, + "US_GOVERNMENT_LEGAL" => { caption: "Government Legal", origin: "US Loose", width_mm: 216.0, height_mm: 330.0 }, + "US_ANSI_A" => { caption: "ANSI A", origin: "US ANSI", width_mm: 216.0, height_mm: 279.0 }, + "US_ANSI_B" => { caption: "ANSI B", origin: "US ANSI", width_mm: 279.0, height_mm: 432.0 }, + "US_ANSI_C" => { caption: "ANSI C", origin: "US ANSI", width_mm: 432.0, height_mm: 559.0 }, + "US_ANSI_D" => { caption: "ANSI D", origin: "US ANSI", width_mm: 559.0, height_mm: 864.0 }, + "US_ANSI_E" => { caption: "ANSI E", origin: "US ANSI", width_mm: 864.0, height_mm: 1118.0 }, + "US_ARCH_A" => { caption: "Arch A", origin: "US Arch", width_mm: 229.0, height_mm: 305.0 }, + "US_ARCH_B" => { caption: "Arch B", origin: "US Arch", width_mm: 305.0, height_mm: 457.0 }, + "US_ARCH_C" => { caption: "Arch C", origin: "US Arch", width_mm: 457.0, height_mm: 610.0 }, + "US_ARCH_D" => { caption: "Arch D", origin: "US Arch", width_mm: 610.0, height_mm: 914.0 }, + "US_ARCH_E" => { caption: "Arch E", origin: "US Arch", width_mm: 914.0, height_mm: 1219.0 }, + "US_ARCH_E1" => { caption: "Arch E1", origin: "US Arch", width_mm: 762.0, height_mm: 1067.0 }, + "US_ARCH_E2" => { caption: "Arch E2", origin: "US Arch", width_mm: 660.0, height_mm: 965.0 }, + "US_ARCH_E3" => { caption: "Arch E3", origin: "US Arch", width_mm: 686.0, height_mm: 991.0 }, + "4A0" => { caption: "4A0", origin: "ISO 216", width_mm: 1682.0, height_mm: 2378.0 }, + "2A0" => { caption: "2A0", origin: "ISO 216", width_mm: 1189.0, height_mm: 1682.0 }, + "A0" => { caption: "A0", origin: "ISO 216", width_mm: 841.0, height_mm: 1189.0 }, + "A0_PLUS" => { caption: "A0+", origin: "ISO 216", width_mm: 914.0, height_mm: 1292.0 }, + "A1" => { caption: "A1", origin: "ISO 216", width_mm: 594.0, height_mm: 841.0 }, + "A1_PLUS" => { caption: "A1+", origin: "ISO 216", width_mm: 609.0, height_mm: 914.0 }, + "A2" => { caption: "A2", origin: "ISO 216", width_mm: 420.0, height_mm: 594.0 }, + "A3" => { caption: "A3", origin: "ISO 216", width_mm: 297.0, height_mm: 420.0 }, + "A3_PLUS" => { caption: "A3+", origin: "ISO 216", width_mm: 329.0, height_mm: 483.0 }, + "A4" => { caption: "A4", origin: "ISO 216", width_mm: 210.0, height_mm: 297.0 }, + "A5" => { caption: "A5", origin: "ISO 216", width_mm: 148.0, height_mm: 210.0 }, + "A6" => { caption: "A6", origin: "ISO 216", width_mm: 105.0, height_mm: 148.0 }, + "A7" => { caption: "A7", origin: "ISO 216", width_mm: 74.0, height_mm: 105.0 }, + "A8" => { caption: "A8", origin: "ISO 216", width_mm: 52.0, height_mm: 74.0 }, + "A9" => { caption: "A9", origin: "ISO 216", width_mm: 37.0, height_mm: 52.0 }, + "A10" => { caption: "A10", origin: "ISO 216", width_mm: 26.0, height_mm: 37.0 }, + "B0" => { caption: "B0", origin: "ISO 216", width_mm: 1000.0, height_mm: 1414.0 }, + "B0_PLUS" => { caption: "B0+", origin: "ISO 216", width_mm: 1118.0, height_mm: 1580.0 }, + "B1" => { caption: "B1", origin: "ISO 216", width_mm: 707.0, height_mm: 1000.0 }, + "B1_PLUS" => { caption: "B1+", origin: "ISO 216", width_mm: 720.0, height_mm: 1020.0 }, + "B2" => { caption: "B2", origin: "ISO 216", width_mm: 500.0, height_mm: 707.0 }, + "B2_PLUS" => { caption: "B2+", origin: "ISO 216", width_mm: 520.0, height_mm: 720.0 }, + "B3" => { caption: "B3", origin: "ISO 216", width_mm: 353.0, height_mm: 500.0 }, + "B4" => { caption: "B4", origin: "ISO 216", width_mm: 250.0, height_mm: 353.0 }, + "B5" => { caption: "B5", origin: "ISO 216", width_mm: 176.0, height_mm: 250.0 }, + "B6" => { caption: "B6", origin: "ISO 216", width_mm: 125.0, height_mm: 176.0 }, + "B7" => { caption: "B7", origin: "ISO 216", width_mm: 88.0, height_mm: 125.0 }, + "B8" => { caption: "B8", origin: "ISO 216", width_mm: 62.0, height_mm: 88.0 }, + "B9" => { caption: "B9", origin: "ISO 216", width_mm: 44.0, height_mm: 62.0 }, + "B10" => { caption: "B10", origin: "ISO 216", width_mm: 31.0, height_mm: 44.0 }, + "B11" => { caption: "B11", origin: "ISO 216", width_mm: 22.0, height_mm: 31.0 }, + "B12" => { caption: "B12", origin: "ISO 216", width_mm: 15.0, height_mm: 22.0 }, + "B13" => { caption: "B13", origin: "ISO 216", width_mm: 11.0, height_mm: 15.0 }, + "C0" => { caption: "C0", origin: "ISO 216", width_mm: 917.0, height_mm: 1297.0 }, + "C1" => { caption: "C1", origin: "ISO 216", width_mm: 648.0, height_mm: 917.0 }, + "C2" => { caption: "C2", origin: "ISO 216", width_mm: 458.0, height_mm: 648.0 }, + "C3" => { caption: "C3", origin: "ISO 216", width_mm: 324.0, height_mm: 458.0 }, + "C4" => { caption: "C4", origin: "ISO 216", width_mm: 229.0, height_mm: 324.0 }, + "C5" => { caption: "C5", origin: "ISO 216", width_mm: 162.0, height_mm: 229.0 }, + "C6" => { caption: "C6", origin: "ISO 216", width_mm: 114.0, height_mm: 162.0 }, + "C7" => { caption: "C7", origin: "ISO 216", width_mm: 81.0, height_mm: 114.0 }, + "C8" => { caption: "C8", origin: "ISO 216", width_mm: 57.0, height_mm: 81.0 }, + "C9" => { caption: "C9", origin: "ISO 216", width_mm: 40.0, height_mm: 57.0 }, + "C10" => { caption: "C10", origin: "ISO 216", width_mm: 28.0, height_mm: 40.0 }, + "BRITISH_DUKES" => { caption: "Dukes", origin: "Traditional British", width_mm: 140.0, height_mm: 178.0 }, + "BRITISH_FOOLSCAP" => { caption: "Foolscap", origin: "Traditional British", width_mm: 203.0, height_mm: 330.0 }, + "BRITISH_IMPERIAL" => { caption: "Imperial", origin: "Traditional British", width_mm: 178.0, height_mm: 229.0 }, + "BRITISH_KINGS" => { caption: "Kings", origin: "Traditional British", width_mm: 165.0, height_mm: 203.0 }, + "BRITISH_QUARTO" => { caption: "Quarto", origin: "Traditional British", width_mm: 203.0, height_mm: 254.0 }, + "US_ENVELOPE_6_1_4" => { caption: "6¼", origin: "US Commercial envelopes", width_mm: 152.0, height_mm: 89.0 }, + "US_ENVELOPE_6_3_4" => { caption: "6¾", origin: "US Commercial envelopes", width_mm: 165.0, height_mm: 92.0 }, + "US_ENVELOPE_7" => { caption: "7", origin: "US Commercial envelopes", width_mm: 172.0, height_mm: 95.0 }, + "US_ENVELOPE_7_3_4_MONARCH" => { caption: "7¾ Monarch", origin: "US Commercial envelopes", width_mm: 191.0, height_mm: 98.0 }, + "US_ENVELOPE8_5_8" => { caption: "8⅝ ", origin: "US Commercial envelopes", width_mm: 219.0, height_mm: 92.0 }, + "US_ENVELOPE_9" => { caption: "9", origin: "US Commercial envelopes", width_mm: 225.0, height_mm: 98.0 }, + "US_ENVELOPE_10" => { caption: "10", origin: "US Commercial envelopes", width_mm: 241.0, height_mm: 104.0 }, + "US_ENVELOPE_11" => { caption: "11", origin: "US Commercial envelopes", width_mm: 264.0, height_mm: 114.0 }, + "US_ENVELOPE_12" => { caption: "12", origin: "US Commercial envelopes", width_mm: 279.0, height_mm: 121.0 }, + "US_ENVELOPE_14" => { caption: "14", origin: "US Commercial envelopes", width_mm: 292.0, height_mm: 127.0 }, + "US_ENVELOPE_16" => { caption: "16", origin: "US Commercial envelopes", width_mm: 305.0, height_mm: 152.0 }, + "US_ENVELOPE_A1" => { caption: "A1", origin: "US Announcement envelopes", width_mm: 92.0, height_mm: 130.0 }, + "US_ENVELOPE_A2_LADY_GREY" => { caption: "A2 Lady Grey", origin: "US Announcement envelopes", width_mm: 146.0, height_mm: 111.0 }, + "US_ENVELOPE_A4" => { caption: "A4", origin: "US Announcement envelopes", width_mm: 159.0, height_mm: 108.0 }, + "US_ENVELOPE_A6_THOMPSON_S_STANDARD" => { caption: "A6 Thompson's Standard", origin: "US Announcement envelopes", width_mm: 165.0, height_mm: 121.0 }, + "US_ENVELOPE_A7_BESSELHEIM" => { caption: "A7 Besselheim", origin: "US Announcement envelopes", width_mm: 184.0, height_mm: 133.0 }, + "US_ENVELOPE_A8_CARR_S" => { caption: "A8 Carr's", origin: "US Announcement envelopes", width_mm: 206.0, height_mm: 140.0 }, + "US_ENVELOPE_A9_DIPLOMAT" => { caption: "A9 Diplomat", origin: "US Announcement envelopes", width_mm: 222.0, height_mm: 146.0 }, + "US_ENVELOPE_A10_WILLOW" => { caption: "A10 Willow", origin: "US Announcement envelopes", width_mm: 241.0, height_mm: 152.0 }, + "US_ENVELOPE_A_LONG" => { caption: "A Long", origin: "US Announcement envelopes", width_mm: 225.0, height_mm: 98.0 }, + "US_ENVELOPE_1" => { caption: "1", origin: "US Catalog envelopes", width_mm: 229.0, height_mm: 152.0 }, + "US_ENVELOPE_1_3_4" => { caption: "1¾", origin: "US Catalog envelopes", width_mm: 241.0, height_mm: 152.0 }, + "US_ENVELOPE_3" => { caption: "3", origin: "US Catalog envelopes", width_mm: 254.0, height_mm: 178.0 }, + "US_ENVELOPE_6" => { caption: "6", origin: "US Catalog envelopes", width_mm: 267.0, height_mm: 191.0 }, + "US_ENVELOPE_8" => { caption: "8", origin: "US Catalog envelopes", width_mm: 286.0, height_mm: 210.0 }, + "US_ENVELOPE_9_3_4" => { caption: "9¾", origin: "US Catalog envelopes", width_mm: 286.0, height_mm: 222.0 }, + "US_ENVELOPE_10_1_2" => { caption: "10½", origin: "US Catalog envelopes", width_mm: 305.0, height_mm: 229.0 }, + "US_ENVELOPE_12_1_2" => { caption: "12½", origin: "US Catalog envelopes", width_mm: 318.0, height_mm: 241.0 }, + "US_ENVELOPE_13_1_2" => { caption: "13½", origin: "US Catalog envelopes", width_mm: 330.0, height_mm: 254.0 }, + "US_ENVELOPE_14_1_2" => { caption: "14½", origin: "US Catalog envelopes", width_mm: 368.0, height_mm: 292.0 }, + "US_ENVELOPE_15" => { caption: "15", origin: "US Catalog envelopes", width_mm: 381.0, height_mm: 254.0 }, + "US_ENVELOPE_15_1_2" => { caption: "15½", origin: "US Catalog envelopes", width_mm: 394.0, height_mm: 305.0 }, + "ENVELOPE_DL" => { caption: "DL", origin: "ISO 269", width_mm: 110.0, height_mm: 220.0 }, + "ENVELOPE_B4" => { caption: "B4", origin: "ISO 269", width_mm: 250.0, height_mm: 353.0 }, + "ENVELOPE_B5" => { caption: "B5", origin: "ISO 269", width_mm: 176.0, height_mm: 250.0 }, + "ENVELOPE_B6" => { caption: "B6", origin: "ISO 269", width_mm: 125.0, height_mm: 176.0 }, + "ENVELOPE_C3" => { caption: "C3", origin: "ISO 269", width_mm: 324.0, height_mm: 458.0 }, + "ENVELOPE_C4" => { caption: "C4", origin: "ISO 269", width_mm: 229.0, height_mm: 324.0 }, + "ENVELOPE_C4M" => { caption: "C4M", origin: "ISO 269", width_mm: 318.0, height_mm: 229.0 }, + "ENVELOPE_C5" => { caption: "C5", origin: "ISO 269", width_mm: 162.0, height_mm: 229.0 }, + "ENVELOPE_C6_C5" => { caption: "C6/C5", origin: "ISO 269", width_mm: 114.0, height_mm: 229.0 }, + "ENVELOPE_C6" => { caption: "C6", origin: "ISO 269", width_mm: 114.0, height_mm: 162.0 }, + "ENVELOPE_C64M" => { caption: "C64M", origin: "ISO 269", width_mm: 318.0, height_mm: 114.0 }, + "ENVELOPE_C7_C6" => { caption: "C7/C6", origin: "ISO 269", width_mm: 81.0, height_mm: 162.0 }, + "ENVELOPE_C7" => { caption: "C7", origin: "ISO 269", width_mm: 81.0, height_mm: 114.0 }, + "ENVELOPE_CE4" => { caption: "CE4", origin: "ISO 269", width_mm: 229.0, height_mm: 310.0 }, + "ENVELOPE_CE64" => { caption: "CE64", origin: "ISO 269", width_mm: 114.0, height_mm: 310.0 }, + "ENVELOPE_E4" => { caption: "E4", origin: "ISO 269", width_mm: 220.0, height_mm: 312.0 }, + "ENVELOPE_EC45" => { caption: "EC45", origin: "ISO 269", width_mm: 220.0, height_mm: 229.0 }, + "ENVELOPE_EC5" => { caption: "EC5", origin: "ISO 269", width_mm: 155.0, height_mm: 229.0 }, + "ENVELOPE_E5" => { caption: "E5", origin: "ISO 269", width_mm: 115.0, height_mm: 220.0 }, + "ENVELOPE_E56" => { caption: "E56", origin: "ISO 269", width_mm: 155.0, height_mm: 155.0 }, + "ENVELOPE_E6" => { caption: "E6", origin: "ISO 269", width_mm: 110.0, height_mm: 155.0 }, + "ENVELOPE_E65" => { caption: "E65", origin: "ISO 269", width_mm: 110.0, height_mm: 220.0 }, + "ENVELOPE_R7" => { caption: "R7", origin: "ISO 269", width_mm: 120.0, height_mm: 135.0 }, + "ENVELOPE_S4" => { caption: "S4", origin: "ISO 269", width_mm: 250.0, height_mm: 330.0 }, + "ENVELOPE_S5" => { caption: "S5", origin: "ISO 269", width_mm: 185.0, height_mm: 255.0 }, + "ENVELOPE_S65" => { caption: "S65", origin: "ISO 269", width_mm: 110.0, height_mm: 225.0 }, + "ENVELOPE_X5" => { caption: "X5", origin: "ISO 269", width_mm: 105.0, height_mm: 216.0 }, + "ENVELOPE_EX5" => { caption: "EX5", origin: "ISO 269", width_mm: 155.0, height_mm: 216.0 }, + "PHOTO_PASSPORT" => { caption: "Passport", origin: "Photography", width_mm: 35.0, height_mm: 45.0 }, + "PHOTO_2R" => { caption: "2R", origin: "Photography", width_mm: 64.0, height_mm: 89.0 }, + "PHOTO_LD" => { caption: "LD", origin: "Photography", width_mm: 89.0, height_mm: 119.0 }, + "PHOTO_DSC" => { caption: "DSC", origin: "Photography", width_mm: 89.0, height_mm: 119.0 }, + "PHOTO_3R" => { caption: "3R", origin: "Photography", width_mm: 89.0, height_mm: 127.0 }, + "PHOTO_L" => { caption: "L", origin: "Photography", width_mm: 89.0, height_mm: 127.0 }, + "PHOTO_LW" => { caption: "LW", origin: "Photography", width_mm: 89.0, height_mm: 133.0 }, + "PHOTO_KGD" => { caption: "KGD", origin: "Photography", width_mm: 102.0, height_mm: 136.0 }, + "PHOTO_KG" => { caption: "KG", origin: "Photography", width_mm: 102.0, height_mm: 152.0 }, + "PHOTO_4R" => { caption: "4R", origin: "Photography", width_mm: 102.0, height_mm: 152.0 }, + "PHOTO_2LD" => { caption: "2LD", origin: "Photography", width_mm: 127.0, height_mm: 169.0 }, + "PHOTO_DSCW" => { caption: "DSCW", origin: "Photography", width_mm: 127.0, height_mm: 169.0 }, + "PHOTO_2L" => { caption: "2L", origin: "Photography", width_mm: 127.0, height_mm: 178.0 }, + "PHOTO_5R" => { caption: "5R", origin: "Photography", width_mm: 127.0, height_mm: 178.0 }, + "PHOTO_2LW" => { caption: "2LW", origin: "Photography", width_mm: 127.0, height_mm: 190.0 }, + "PHOTO_6R" => { caption: "6R", origin: "Photography", width_mm: 152.0, height_mm: 203.0 }, + "PHOTO_8R" => { caption: "8R", origin: "Photography", width_mm: 203.0, height_mm: 254.0 }, + "PHOTO_6P" => { caption: "6P", origin: "Photography", width_mm: 203.0, height_mm: 254.0 }, + "PHOTO_6PW" => { caption: "6PW", origin: "Photography", width_mm: 203.0, height_mm: 305.0 }, + "PHOTO_S8R" => { caption: "S8R", origin: "Photography", width_mm: 203.0, height_mm: 305.0 }, + "PHOTO_11R" => { caption: "11R", origin: "Photography", width_mm: 279.0, height_mm: 356.0 }, + "PHOTO_A3_PLUS" => { caption: "A3+ Super B", origin: "Photography", width_mm: 330.0, height_mm: 483.0 }, + "NEWSPAPER_BERLINER" => { caption: "Berliner", origin: "Newspaper", width_mm: 315.0, height_mm: 470.0 }, + "NEWSPAPER_BROADSHEET" => { caption: "Broadsheet", origin: "Newspaper", width_mm: 597.0, height_mm: 749.0 }, + "NEWSPAPER_US_BROADSHEET" => { caption: "US Broadsheet", origin: "Newspaper", width_mm: 381.0, height_mm: 578.0 }, + "NEWSPAPER_BRITISH_BROADSHEET" => { caption: "British Broadsheet", origin: "Newspaper", width_mm: 375.0, height_mm: 597.0 }, + "NEWSPAPER_SOUTH_AFRICAN_BROADSHEET" => { caption: "South African Broadsheet", origin: "Newspaper", width_mm: 410.0, height_mm: 578.0 }, + "NEWSPAPER_CINER" => { caption: "Ciner", origin: "Newspaper", width_mm: 350.0, height_mm: 500.0 }, + "NEWSPAPER_COMPACT" => { caption: "Compact", origin: "Newspaper", width_mm: 280.0, height_mm: 430.0 }, + "NEWSPAPER_NORDISCH" => { caption: "Nordisch", origin: "Newspaper", width_mm: 400.0, height_mm: 570.0 }, + "NEWSPAPER_RHENISH" => { caption: "Rhenish", origin: "Newspaper", width_mm: 350.0, height_mm: 520.0 }, + "NEWSPAPER_SWISS" => { caption: "Swiss", origin: "Newspaper", width_mm: 320.0, height_mm: 475.0 }, + "NEWSPAPER_TABLOID" => { caption: "Tabloid", origin: "Newspaper", width_mm: 280.0, height_mm: 430.0 }, + "NEWSPAPER_CANADIAN_TABLOID" => { caption: "Canadian Tabloid", origin: "Newspaper", width_mm: 260.0, height_mm: 368.0 }, + "NEWSPAPER_NORWEGIAN_TABLOID" => { caption: "Norwegian Tabloid", origin: "Newspaper", width_mm: 280.0, height_mm: 400.0 }, + "NEWSPAPER_NEW_YOUR_TIMES" => { caption: "New York Times", origin: "Newspaper", width_mm: 305.0, height_mm: 559.0 }, + "NEWSPAPER_WALL_STREET_JOURNAL" => { caption: "Wall Street Journal", origin: "Newspaper", width_mm: 305.0, height_mm: 578.0 }, + "BOOK_FOLIO" => { caption: "Folio", origin: "Book", width_mm: 304.8, height_mm: 482.6 }, + "BOOK_QUARTO" => { caption: "Quarto", origin: "Book", width_mm: 241.3, height_mm: 304.8 }, + "BOOK_IMPERIAL_OCTAVO" => { caption: "Imperial Octavo", origin: "Book", width_mm: 209.6, height_mm: 292.1 }, + "BOOK_SUPER_OCTAVO" => { caption: "Super Octavo", origin: "Book", width_mm: 177.8, height_mm: 279.4 }, + "BOOK_ROYAL_OCTAVO" => { caption: "Royal Octavo", origin: "Book", width_mm: 165.1, height_mm: 254.0 }, + "BOOK_MEDIUM_OCTAVO" => { caption: "Medium Octavo", origin: "Book", width_mm: 165.1, height_mm: 234.9 }, + "BOOK_OCTAVO" => { caption: "Octavo", origin: "Book", width_mm: 152.4, height_mm: 228.6 }, + "BOOK_CROWN_OCTAVO" => { caption: "Crown Octavo", origin: "Book", width_mm: 136.5, height_mm: 203.2 }, + "BOOK_12MO" => { caption: "12mo", origin: "Book", width_mm: 127.0, height_mm: 187.3 }, + "BOOK_16MO" => { caption: "16mo", origin: "Book", width_mm: 101.6, height_mm: 171.4 }, + "BOOK_18MO" => { caption: "18mo", origin: "Book", width_mm: 101.6, height_mm: 165.1 }, + "BOOK_32MO" => { caption: "32mo", origin: "Book", width_mm: 88.9, height_mm: 139.7 }, + "BOOK_48MO" => { caption: "48mo", origin: "Book", width_mm: 63.5, height_mm: 101.6 }, + "BOOK_64MO" => { caption: "64mo", origin: "Book", width_mm: 50.8, height_mm: 76.2 }, + "BOOK_A_FORMAT" => { caption: "A Format", origin: "Book", width_mm: 110.0, height_mm: 178.0 }, + "BOOK_B_FORMAT" => { caption: "B Format", origin: "Book", width_mm: 129.0, height_mm: 198.0 }, + "BOOK_C_FORMAT" => { caption: "C Format", origin: "Book", width_mm: 135.0, height_mm: 216.0 }, + "BUSINESS_CARD_ISO_216" => { caption: "ISO 216", origin: "Business Card", width_mm: 74.0, height_mm: 52.0 }, + "BUSINESS_CARD_US_CANADA" => { caption: "US/Canada", origin: "Business Card", width_mm: 88.9, height_mm: 50.8 }, + "BUSINESS_CARD_EUROPEAN" => { caption: "European", origin: "Business Card", width_mm: 85.0, height_mm: 55.0 }, + "BUSINESS_CARD_SCANDINAVIA" => { caption: "Scandinavia", origin: "Business Card", width_mm: 90.0, height_mm: 55.0 }, + "BUSINESS_CARD_CHINA" => { caption: "China", origin: "Business Card", width_mm: 90.0, height_mm: 54.0 }, + "BUSINESS_CARD_JAPAN" => { caption: "Japan", origin: "Business Card", width_mm: 91.0, height_mm: 55.0 }, + "BUSINESS_CARD_IRAN" => { caption: "Iran", origin: "Business Card", width_mm: 85.0, height_mm: 48.0 }, + "BUSINESS_CARD_HUNGARY" => { caption: "Hungary", origin: "Business Card", width_mm: 90.0, height_mm: 50.0 }, + "BUSINESS_CARD_ISO_7810_ID_1" => { caption: "ISO 7810 ID-1", origin: "Business Card", width_mm: 85.6, height_mm: 54.0 }, + "RAW_RA0" => { caption: "RA0", origin: "ISO 217:1995", width_mm: 860.0, height_mm: 1220.0 }, + "RAW_RA1" => { caption: "RA1", origin: "ISO 217:1995", width_mm: 610.0, height_mm: 860.0 }, + "RAW_RA2" => { caption: "RA2", origin: "ISO 217:1995", width_mm: 430.0, height_mm: 610.0 }, + "RAW_RA3" => { caption: "RA3", origin: "ISO 217:1995", width_mm: 305.0, height_mm: 430.0 }, + "RAW_RA4" => { caption: "RA4", origin: "ISO 217:1995", width_mm: 215.0, height_mm: 305.0 }, + "RAW_SRA0" => { caption: "SRA0", origin: "ISO 217:1995", width_mm: 900.0, height_mm: 1280.0 }, + "RAW_SRA1" => { caption: "SRA1", origin: "ISO 217:1995", width_mm: 640.0, height_mm: 900.0 }, + "RAW_SRA2" => { caption: "SRA2", origin: "ISO 217:1995", width_mm: 450.0, height_mm: 640.0 }, + "RAW_SRA3" => { caption: "SRA3", origin: "ISO 217:1995", width_mm: 320.0, height_mm: 450.0 }, + "RAW_SRA4" => { caption: "SRA4", origin: "ISO 217:1995", width_mm: 225.0, height_mm: 320.0 }, + "RAW_SRA1_PLUS" => { caption: "SRA1+", origin: "ISO 217:1995", width_mm: 660.0, height_mm: 920.0 }, + "RAW_SRA2_PLUS" => { caption: "SRA2+", origin: "ISO 217:1995", width_mm: 480.0, height_mm: 650.0 }, + "RAW_SRA3_PLUS" => { caption: "SRA3+", origin: "ISO 217:1995", width_mm: 320.0, height_mm: 460.0 }, + "RAW_SRA3_PLUS_PLUS" => { caption: "SRA3++", origin: "ISO 217:1995", width_mm: 320.0, height_mm: 464.0 }, + "RAW_A0U" => { caption: "A0U", origin: "ISO 217:1995", width_mm: 880.0, height_mm: 1230.0 }, + "RAW_A1U" => { caption: "A1U", origin: "ISO 217:1995", width_mm: 625.0, height_mm: 880.0 }, + "RAW_A2U" => { caption: "A2U", origin: "ISO 217:1995", width_mm: 450.0, height_mm: 625.0 }, + "RAW_A3U" => { caption: "A3U", origin: "ISO 217:1995", width_mm: 330.0, height_mm: 450.0 }, + "RAW_A4U" => { caption: "A4U", origin: "ISO 217:1995", width_mm: 240.0, height_mm: 330.0 }, + "BILLBOARD_1_SHEET" => { caption: "1 Sheet", origin: "Billboard", width_mm: 508.0, height_mm: 762.0 }, + "BILLBOARD_2_SHEET" => { caption: "2 Sheet", origin: "Billboard", width_mm: 762.0, height_mm: 1016.0 }, + "BILLBOARD_4_SHEET" => { caption: "4 Sheet", origin: "Billboard", width_mm: 1016.0, height_mm: 1524.0 }, + "BILLBOARD_6_SHEET" => { caption: "6 Sheet", origin: "Billboard", width_mm: 1200.0, height_mm: 1800.0 }, + "BILLBOARD_12_SHEET" => { caption: "12 Sheet", origin: "Billboard", width_mm: 3048.0, height_mm: 1524.0 }, + "BILLBOARD_16_SHEET" => { caption: "16 Sheet", origin: "Billboard", width_mm: 2032.0, height_mm: 3048.0 }, + "BILLBOARD_32_SHEET" => { caption: "32 Sheet", origin: "Billboard", width_mm: 4064.0, height_mm: 3048.0 }, + "BILLBOARD_48_SHEET" => { caption: "48 Sheet", origin: "Billboard", width_mm: 6096.0, height_mm: 3048.0 }, + "BILLBOARD_64_SHEET" => { caption: "64 Sheet", origin: "Billboard", width_mm: 8128.0, height_mm: 3048.0 }, + "BILLBOARD_96_SHEET" => { caption: "96 Sheet", origin: "Billboard", width_mm: 12192.0, height_mm: 3048.0 }, + "JAPANESE_JB0" => { caption: "JB0", origin: "Japanese JIS", width_mm: 1030.0, height_mm: 1456.0 }, + "JAPANESE_JB1" => { caption: "JB1", origin: "Japanese JIS", width_mm: 728.0, height_mm: 1030.0 }, + "JAPANESE_JB2" => { caption: "JB2", origin: "Japanese JIS", width_mm: 515.0, height_mm: 728.0 }, + "JAPANESE_JB3" => { caption: "JB3", origin: "Japanese JIS", width_mm: 364.0, height_mm: 515.0 }, + "JAPANESE_JB4" => { caption: "JB4", origin: "Japanese JIS", width_mm: 257.0, height_mm: 364.0 }, + "JAPANESE_JB5" => { caption: "JB5", origin: "Japanese JIS", width_mm: 182.0, height_mm: 257.0 }, + "JAPANESE_JB6" => { caption: "JB6", origin: "Japanese JIS", width_mm: 128.0, height_mm: 182.0 }, + "JAPANESE_JB7" => { caption: "JB7", origin: "Japanese JIS", width_mm: 91.0, height_mm: 128.0 }, + "JAPANESE_JB8" => { caption: "JB8", origin: "Japanese JIS", width_mm: 64.0, height_mm: 91.0 }, + "JAPANESE_JB9" => { caption: "JB9", origin: "Japanese JIS", width_mm: 45.0, height_mm: 64.0 }, + "JAPANESE_JB10" => { caption: "JB10", origin: "Japanese JIS", width_mm: 32.0, height_mm: 45.0 }, + "JAPANESE_JB11" => { caption: "JB11", origin: "Japanese JIS", width_mm: 22.0, height_mm: 32.0 }, + "JAPANESE_JB12" => { caption: "JB12", origin: "Japanese JIS", width_mm: 16.0, height_mm: 22.0 }, + "JAPANESE_SHIROKU_BAN_4" => { caption: "Shiroku ban 4", origin: "Japanese Shiroku", width_mm: 264.0, height_mm: 379.0 }, + "JAPANESE_SHIROKU_BAN_5" => { caption: "Shiroku ban 5", origin: "Japanese Shiroku", width_mm: 189.0, height_mm: 262.0 }, + "JAPANESE_SHIROKU_BAN_6" => { caption: "Shiroku ban 6", origin: "Japanese Shiroku", width_mm: 127.0, height_mm: 188.0 }, + "JAPANESE_KIKU_4" => { caption: "Kiku 4", origin: "Japanese Kiku", width_mm: 227.0, height_mm: 306.0 }, + "JAPANESE_KIKU_5" => { caption: "Kiku 5", origin: "Japanese Kiku", width_mm: 151.0, height_mm: 227.0 }, + "CANADIAN_P1" => { caption: "P1", origin: "Canadian CAN 2-9.60M", width_mm: 560.0, height_mm: 860.0 }, + "CANADIAN_P2" => { caption: "P2", origin: "Canadian CAN 2-9.60M", width_mm: 430.0, height_mm: 560.0 }, + "CANADIAN_P3" => { caption: "P3", origin: "Canadian CAN 2-9.60M", width_mm: 280.0, height_mm: 430.0 }, + "CANADIAN_P4" => { caption: "P4", origin: "Canadian CAN 2-9.60M", width_mm: 215.0, height_mm: 280.0 }, + "CANADIAN_P5" => { caption: "P5", origin: "Canadian CAN 2-9.60M", width_mm: 140.0, height_mm: 215.0 }, + "CANADIAN_P6" => { caption: "P6", origin: "Canadian CAN 2-9.60M", width_mm: 107.0, height_mm: 140.0 }, + "DIN_D0" => { caption: "DIN D0", origin: "German DIN 476", width_mm: 771.0, height_mm: 1090.0 }, + "DIN_D1" => { caption: "DIN D1", origin: "German DIN 476", width_mm: 545.0, height_mm: 771.0 }, + "DIN_D2" => { caption: "DIN D2", origin: "German DIN 476", width_mm: 385.0, height_mm: 545.0 }, + "DIN_D3" => { caption: "DIN D3", origin: "German DIN 476", width_mm: 272.0, height_mm: 385.0 }, + "DIN_D4" => { caption: "DIN D4", origin: "German DIN 476", width_mm: 192.0, height_mm: 272.0 }, + "DIN_D5" => { caption: "DIN D5", origin: "German DIN 476", width_mm: 136.0, height_mm: 192.0 }, + "DIN_D6" => { caption: "DIN D6", origin: "German DIN 476", width_mm: 96.0, height_mm: 136.0 }, + "DIN_D7" => { caption: "DIN D7", origin: "German DIN 476", width_mm: 68.0, height_mm: 96.0 }, + "DIN_D8" => { caption: "DIN D8", origin: "German DIN 476", width_mm: 48.0, height_mm: 68.0 }, + "SIS_E0" => { caption: "SIS E0", origin: "Swedish SIS 01 47 11", width_mm: 878.0, height_mm: 1242.0 }, + "SIS_E1" => { caption: "SIS E1", origin: "Swedish SIS 01 47 11", width_mm: 621.0, height_mm: 878.0 }, + "SIS_E2" => { caption: "SIS E2", origin: "Swedish SIS 01 47 11", width_mm: 439.0, height_mm: 621.0 }, + "SIS_E3" => { caption: "SIS E3", origin: "Swedish SIS 01 47 11", width_mm: 310.0, height_mm: 439.0 }, + "SIS_E4" => { caption: "SIS E4", origin: "Swedish SIS 01 47 11", width_mm: 220.0, height_mm: 310.0 }, + "SIS_E5" => { caption: "SIS E5", origin: "Swedish SIS 01 47 11", width_mm: 155.0, height_mm: 220.0 }, + "SIS_E6" => { caption: "SIS E6", origin: "Swedish SIS 01 47 11", width_mm: 110.0, height_mm: 155.0 }, + "SIS_E7" => { caption: "SIS E7", origin: "Swedish SIS 01 47 11", width_mm: 78.0, height_mm: 110.0 }, + "SIS_E8" => { caption: "SIS E8", origin: "Swedish SIS 01 47 11", width_mm: 55.0, height_mm: 78.0 }, + "SIS_E9" => { caption: "SIS E9", origin: "Swedish SIS 01 47 11", width_mm: 39.0, height_mm: 55.0 }, + "SIS_E10" => { caption: "SIS E10", origin: "Swedish SIS 01 47 11", width_mm: 27.0, height_mm: 39.0 }, + "SIS_F0" => { caption: "SIS F0", origin: "Swedish SIS 01 47 11", width_mm: 958.0, height_mm: 1354.0 }, + "SIS_F1" => { caption: "SIS F1", origin: "Swedish SIS 01 47 11", width_mm: 677.0, height_mm: 958.0 }, + "SIS_F2" => { caption: "SIS F2", origin: "Swedish SIS 01 47 11", width_mm: 479.0, height_mm: 677.0 }, + "SIS_F3" => { caption: "SIS F3", origin: "Swedish SIS 01 47 11", width_mm: 339.0, height_mm: 479.0 }, + "SIS_F4" => { caption: "SIS F4", origin: "Swedish SIS 01 47 11", width_mm: 239.0, height_mm: 339.0 }, + "SIS_F5" => { caption: "SIS F5", origin: "Swedish SIS 01 47 11", width_mm: 169.0, height_mm: 239.0 }, + "SIS_F6" => { caption: "SIS F6", origin: "Swedish SIS 01 47 11", width_mm: 120.0, height_mm: 169.0 }, + "SIS_F7" => { caption: "SIS F7", origin: "Swedish SIS 01 47 11", width_mm: 85.0, height_mm: 120.0 }, + "SIS_F8" => { caption: "SIS F8", origin: "Swedish SIS 01 47 11", width_mm: 60.0, height_mm: 85.0 }, + "SIS_F9" => { caption: "SIS F9", origin: "Swedish SIS 01 47 11", width_mm: 42.0, height_mm: 60.0 }, + "SIS_F10" => { caption: "SIS F10", origin: "Swedish SIS 01 47 11", width_mm: 30.0, height_mm: 42.0 }, + "SIS_G0" => { caption: "SIS G0", origin: "Swedish SIS 01 47 11", width_mm: 1044.0, height_mm: 1477.0 }, + "SIS_G1" => { caption: "SIS G1", origin: "Swedish SIS 01 47 11", width_mm: 738.0, height_mm: 1044.0 }, + "SIS_G2" => { caption: "SIS G2", origin: "Swedish SIS 01 47 11", width_mm: 522.0, height_mm: 738.0 }, + "SIS_G3" => { caption: "SIS G3", origin: "Swedish SIS 01 47 11", width_mm: 369.0, height_mm: 522.0 }, + "SIS_G4" => { caption: "SIS G4", origin: "Swedish SIS 01 47 11", width_mm: 261.0, height_mm: 369.0 }, + "SIS_G5" => { caption: "SIS G5", origin: "Swedish SIS 01 47 11", width_mm: 185.0, height_mm: 261.0 }, + "SIS_G6" => { caption: "SIS G6", origin: "Swedish SIS 01 47 11", width_mm: 131.0, height_mm: 185.0 }, + "SIS_G7" => { caption: "SIS G7", origin: "Swedish SIS 01 47 11", width_mm: 92.0, height_mm: 131.0 }, + "SIS_G8" => { caption: "SIS G8", origin: "Swedish SIS 01 47 11", width_mm: 65.0, height_mm: 92.0 }, + "SIS_G9" => { caption: "SIS G9", origin: "Swedish SIS 01 47 11", width_mm: 46.0, height_mm: 65.0 }, + "SIS_G10" => { caption: "SIS G10", origin: "Swedish SIS 01 47 11", width_mm: 33.0, height_mm: 46.0 }, + "SIS_D0" => { caption: "SIS D0", origin: "Swedish SIS 01 47 11", width_mm: 1091.0, height_mm: 1542.0 }, + "SIS_D1" => { caption: "SIS D1", origin: "Swedish SIS 01 47 11", width_mm: 771.0, height_mm: 1091.0 }, + "SIS_D2" => { caption: "SIS D2", origin: "Swedish SIS 01 47 11", width_mm: 545.0, height_mm: 771.0 }, + "SIS_D3" => { caption: "SIS D3", origin: "Swedish SIS 01 47 11", width_mm: 386.0, height_mm: 545.0 }, + "SIS_D4" => { caption: "SIS D4", origin: "Swedish SIS 01 47 11", width_mm: 273.0, height_mm: 386.0 }, + "SIS_D5" => { caption: "SIS D5", origin: "Swedish SIS 01 47 11", width_mm: 193.0, height_mm: 273.0 }, + "SIS_D6" => { caption: "SIS D6", origin: "Swedish SIS 01 47 11", width_mm: 136.0, height_mm: 193.0 }, + "SIS_D7" => { caption: "SIS D7", origin: "Swedish SIS 01 47 11", width_mm: 96.0, height_mm: 136.0 }, + "SIS_D8" => { caption: "SIS D8", origin: "Swedish SIS 01 47 11", width_mm: 68.0, height_mm: 96.0 }, + "SIS_D9" => { caption: "SIS D9", origin: "Swedish SIS 01 47 11", width_mm: 48.0, height_mm: 68.0 }, + "SIS_D10" => { caption: "SIS D10", origin: "Swedish SIS 01 47 11", width_mm: 34.0, height_mm: 48.0 }, + "COLOMBIAN_CARTA" => { caption: "Carta", origin: "Colombian", width_mm: 216.0, height_mm: 279.0 }, + "COLOMBIAN_EXTRA_TABLOIDE" => { caption: "Extra Tabloide", origin: "Colombian", width_mm: 304.0, height_mm: 457.2 }, + "COLOMBIAN_OFICIO" => { caption: "Oficio", origin: "Colombian", width_mm: 216.0, height_mm: 330.0 }, + "COLOMBIAN_1_8_PLIEGO" => { caption: "1/8 pliego", origin: "Colombian", width_mm: 250.0, height_mm: 350.0 }, + "COLOMBIAN_1_4_PLIEGO" => { caption: "1/4 pliego", origin: "Colombian", width_mm: 350.0, height_mm: 500.0 }, + "COLOMBIAN_1_2_PLIEGO" => { caption: "1/2 pliego", origin: "Colombian", width_mm: 500.0, height_mm: 700.0 }, + "COLOMBIAN_PLIEGO" => { caption: "Pliego", origin: "Colombian", width_mm: 700.0, height_mm: 1000.0 }, + "CHINESE_D0" => { caption: "D0", origin: "Chinese GB/T 148-1997", width_mm: 764.0, height_mm: 1064.0 }, + "CHINESE_D1" => { caption: "D1", origin: "Chinese GB/T 148-1997", width_mm: 532.0, height_mm: 760.0 }, + "CHINESE_D2" => { caption: "D2", origin: "Chinese GB/T 148-1997", width_mm: 380.0, height_mm: 528.0 }, + "CHINESE_D3" => { caption: "D3", origin: "Chinese GB/T 148-1997", width_mm: 264.0, height_mm: 376.0 }, + "CHINESE_D4" => { caption: "D4", origin: "Chinese GB/T 148-1997", width_mm: 188.0, height_mm: 260.0 }, + "CHINESE_D5" => { caption: "D5", origin: "Chinese GB/T 148-1997", width_mm: 130.0, height_mm: 184.0 }, + "CHINESE_D6" => { caption: "D6", origin: "Chinese GB/T 148-1997", width_mm: 92.0, height_mm: 126.0 }, + "CHINESE_RD0" => { caption: "RD0", origin: "Chinese GB/T 148-1997", width_mm: 787.0, height_mm: 1092.0 }, + "CHINESE_RD1" => { caption: "RD1", origin: "Chinese GB/T 148-1997", width_mm: 546.0, height_mm: 787.0 }, + "CHINESE_RD2" => { caption: "RD2", origin: "Chinese GB/T 148-1997", width_mm: 393.0, height_mm: 546.0 }, + "CHINESE_RD3" => { caption: "RD3", origin: "Chinese GB/T 148-1997", width_mm: 273.0, height_mm: 393.0 }, + "CHINESE_RD4" => { caption: "RD4", origin: "Chinese GB/T 148-1997", width_mm: 196.0, height_mm: 273.0 }, + "CHINESE_RD5" => { caption: "RD5", origin: "Chinese GB/T 148-1997", width_mm: 136.0, height_mm: 196.0 }, + "CHINESE_RD6" => { caption: "RD6", origin: "Chinese GB/T 148-1997", width_mm: 98.0, height_mm: 136.0 }, + "TRANSITIONAL_PA0" => { caption: "PA0", origin: "Transitional PA Series", width_mm: 840.0, height_mm: 1120.0 }, + "TRANSITIONAL_PA1" => { caption: "PA1", origin: "Transitional PA Series", width_mm: 560.0, height_mm: 840.0 }, + "TRANSITIONAL_PA2" => { caption: "PA2", origin: "Transitional PA Series", width_mm: 420.0, height_mm: 560.0 }, + "TRANSITIONAL_PA3" => { caption: "PA3", origin: "Transitional PA Series", width_mm: 280.0, height_mm: 420.0 }, + "TRANSITIONAL_PA4" => { caption: "PA4", origin: "Transitional PA Series", width_mm: 210.0, height_mm: 280.0 }, + "TRANSITIONAL_PA5" => { caption: "PA5", origin: "Transitional PA Series", width_mm: 140.0, height_mm: 210.0 }, + "TRANSITIONAL_PA6" => { caption: "PA6", origin: "Transitional PA Series", width_mm: 105.0, height_mm: 140.0 }, + "TRANSITIONAL_PA7" => { caption: "PA7", origin: "Transitional PA Series", width_mm: 70.0, height_mm: 105.0 }, + "TRANSITIONAL_PA8" => { caption: "PA8", origin: "Transitional PA Series", width_mm: 52.0, height_mm: 70.0 }, + "TRANSITIONAL_PA9" => { caption: "PA9", origin: "Transitional PA Series", width_mm: 35.0, height_mm: 52.0 }, + "TRANSITIONAL_PA10" => { caption: "PA10", origin: "Transitional PA Series", width_mm: 26.0, height_mm: 35.0 }, + "TRANSITIONAL_F0" => { caption: "F0", origin: "Transitional F Series", width_mm: 841.0, height_mm: 1321.0 }, + "TRANSITIONAL_F1" => { caption: "F1", origin: "Transitional F Series", width_mm: 660.0, height_mm: 841.0 }, + "TRANSITIONAL_F2" => { caption: "F2", origin: "Transitional F Series", width_mm: 420.0, height_mm: 660.0 }, + "TRANSITIONAL_F3" => { caption: "F3", origin: "Transitional F Series", width_mm: 330.0, height_mm: 420.0 }, + "TRANSITIONAL_F4" => { caption: "F4", origin: "Transitional F Series", width_mm: 210.0, height_mm: 330.0 }, + "TRANSITIONAL_F5" => { caption: "F5", origin: "Transitional F Series", width_mm: 165.0, height_mm: 210.0 }, + "TRANSITIONAL_F6" => { caption: "F6", origin: "Transitional F Series", width_mm: 105.0, height_mm: 165.0 }, + "TRANSITIONAL_F7" => { caption: "F7", origin: "Transitional F Series", width_mm: 82.0, height_mm: 105.0 }, + "TRANSITIONAL_F8" => { caption: "F8", origin: "Transitional F Series", width_mm: 52.0, height_mm: 82.0 }, + "TRANSITIONAL_F9" => { caption: "F9", origin: "Transitional F Series", width_mm: 41.0, height_mm: 52.0 }, + "TRANSITIONAL_F10" => { caption: "F10", origin: "Transitional F Series", width_mm: 26.0, height_mm: 41.0 }, + "IMPERIAL_ANTIQUARIAN" => { caption: "Antiquarian", origin: "Imperial", width_mm: 787.0, height_mm: 1346.0 }, + "IMPERIAL_ATLAS" => { caption: "Atlas", origin: "Imperial", width_mm: 660.0, height_mm: 864.0 }, + "IMPERIAL_BRIEF" => { caption: "Brief", origin: "Imperial", width_mm: 343.0, height_mm: 406.0 }, + "IMPERIAL_BROADSHEET" => { caption: "Broadsheet", origin: "Imperial", width_mm: 457.0, height_mm: 610.0 }, + "IMPERIAL_CARTRIDGE" => { caption: "Cartridge", origin: "Imperial", width_mm: 533.0, height_mm: 660.0 }, + "IMPERIAL_COLUMBIER" => { caption: "Columbier", origin: "Imperial", width_mm: 597.0, height_mm: 876.0 }, + "IMPERIAL_COPY_DRAUGHT" => { caption: "Copy Draught", origin: "Imperial", width_mm: 406.0, height_mm: 508.0 }, + "IMPERIAL_CROWN" => { caption: "Crown", origin: "Imperial", width_mm: 381.0, height_mm: 508.0 }, + "IMPERIAL_DEMY" => { caption: "Demy", origin: "Imperial", width_mm: 445.0, height_mm: 572.0 }, + "IMPERIAL_DOUBLE_DEMY" => { caption: "Double Demy", origin: "Imperial", width_mm: 572.0, height_mm: 902.0 }, + "IMPERIAL_QUAD_DEMY" => { caption: "Quad Demy", origin: "Imperial", width_mm: 889.0, height_mm: 1143.0 }, + "IMPERIAL_ELEPHANT" => { caption: "Elephant", origin: "Imperial", width_mm: 584.0, height_mm: 711.0 }, + "IMPERIAL_DOUBLE_ELEPHANT" => { caption: "Double Elephant", origin: "Imperial", width_mm: 678.0, height_mm: 1016.0 }, + "IMPERIAL_EMPEROR" => { caption: "Emperor", origin: "Imperial", width_mm: 1219.0, height_mm: 1829.0 }, + "IMPERIAL_FOOLSCAP" => { caption: "Foolscap", origin: "Imperial", width_mm: 343.0, height_mm: 432.0 }, + "IMPERIAL_SMALL_FOOLSCAP" => { caption: "Small Foolscap", origin: "Imperial", width_mm: 337.0, height_mm: 419.0 }, + "IMPERIAL_GRAND_EAGLE" => { caption: "Grand Eagle", origin: "Imperial", width_mm: 730.0, height_mm: 1067.0 }, + "IMPERIAL_IMPERIAL" => { caption: "Imperial", origin: "Imperial", width_mm: 559.0, height_mm: 762.0 }, + "IMPERIAL_MEDIUM" => { caption: "Medium", origin: "Imperial", width_mm: 470.0, height_mm: 584.0 }, + "IMPERIAL_MONARCH" => { caption: "Monarch", origin: "Imperial", width_mm: 184.0, height_mm: 267.0 }, + "IMPERIAL_POST" => { caption: "Post", origin: "Imperial", width_mm: 394.0, height_mm: 489.0 }, + "IMPERIAL_HALF_POST" => { caption: "Sheet, Half Post", origin: "Imperial", width_mm: 495.0, height_mm: 597.0 }, + "IMPERIAL_PINCHED_POST" => { caption: "Pinched Post", origin: "Imperial", width_mm: 375.0, height_mm: 470.0 }, + "IMPERIAL_LARGE_POST" => { caption: "Large Post", origin: "Imperial", width_mm: 394.0, height_mm: 508.0 }, + "IMPERIAL_DOUBLE_LARGE_POST" => { caption: "Double Large Post", origin: "Imperial", width_mm: 533.0, height_mm: 838.0 }, + "IMPERIAL_DOUBLE_POST" => { caption: "Double Post", origin: "Imperial", width_mm: 483.0, height_mm: 762.0 }, + "IMPERIAL_POTT" => { caption: "Pott", origin: "Imperial", width_mm: 318.0, height_mm: 381.0 }, + "IMPERIAL_PRINCESS" => { caption: "Princess", origin: "Imperial", width_mm: 546.0, height_mm: 711.0 }, + "IMPERIAL_QUARTO" => { caption: "Quarto", origin: "Imperial", width_mm: 229.0, height_mm: 279.0 }, + "IMPERIAL_ROYAL" => { caption: "Royal", origin: "Imperial", width_mm: 508.0, height_mm: 635.0 }, + "IMPERIAL_SUPER_ROYAL" => { caption: "Super Royal", origin: "Imperial", width_mm: 483.0, height_mm: 686.0 }, + "FRENCH_CLOCHE" => { caption: "Cloche", origin: "French", width_mm: 300.0, height_mm: 400.0 }, + "FRENCH_POT_ECOLIER" => { caption: "Pot, écolier", origin: "French", width_mm: 310.0, height_mm: 400.0 }, + "FRENCH_TELLIERE" => { caption: "Tellière", origin: "French", width_mm: 340.0, height_mm: 440.0 }, + "FRENCH_COURONNE_ECRITURE" => { caption: "Couronne écriture", origin: "French", width_mm: 360.0, height_mm: 360.0 }, + "FRENCH_COURONNE_EDITION" => { caption: "Couronne édition", origin: "French", width_mm: 370.0, height_mm: 470.0 }, + "FRENCH_ROBERTO" => { caption: "Roberto", origin: "French", width_mm: 390.0, height_mm: 500.0 }, + "FRENCH_ECU" => { caption: "Écu", origin: "French", width_mm: 400.0, height_mm: 520.0 }, + "FRENCH_COQUILLE" => { caption: "Coquille", origin: "French", width_mm: 440.0, height_mm: 560.0 }, + "FRENCH_CARRE" => { caption: "Carré", origin: "French", width_mm: 450.0, height_mm: 560.0 }, + "FRENCH_CAVALIER" => { caption: "Cavalier", origin: "French", width_mm: 460.0, height_mm: 620.0 }, + "FRENCH_DEMI_RAISIN" => { caption: "Demi-raisin", origin: "French", width_mm: 325.0, height_mm: 500.0 }, + "FRENCH_RAISIN" => { caption: "Raisin", origin: "French", width_mm: 500.0, height_mm: 650.0 }, + "FRENCH_DOUBLE_RAISIN" => { caption: "Double Raisin", origin: "French", width_mm: 650.0, height_mm: 1000.0 }, + "FRENCH_JESUS" => { caption: "Jésus", origin: "French", width_mm: 560.0, height_mm: 760.0 }, + "FRENCH_SOLEIL" => { caption: "Soleil", origin: "French", width_mm: 600.0, height_mm: 800.0 }, + "FRENCH_COLOMBIER_AFFICHE" => { caption: "Colombier affiche", origin: "French", width_mm: 600.0, height_mm: 800.0 }, + "FRENCH_COLOMBIER_COMMERCIAL" => { caption: "Colombier commercial", origin: "French", width_mm: 630.0, height_mm: 900.0 }, + "FRENCH_PETIT_AIGLE" => { caption: "Petit Aigle", origin: "French", width_mm: 700.0, height_mm: 940.0 }, + "FRENCH_GRAND_AIGLE" => { caption: "Grand Aigle", origin: "French", width_mm: 750.0, height_mm: 1050.0 }, + "FRENCH_GRAND_MONDE" => { caption: "Grand Monde", origin: "French", width_mm: 900.0, height_mm: 1260.0 }, + "FRENCH_UNIVERS" => { caption: "Univers", origin: "French", width_mm: 1000.0, height_mm: 1130.0 }, + "RUSSIAN_60X84_8" => { caption: "60x84/8", origin: "Russian GOST 5773-90", width_mm: 205.0, height_mm: 290.0 }, + "RUSSIAN_60X84_16" => { caption: "60x84/16", origin: "Russian GOST 5773-90", width_mm: 145.0, height_mm: 200.0 }, + "RUSSIAN_60X84_32" => { caption: "60x84/32", origin: "Russian GOST 5773-90", width_mm: 100.0, height_mm: 140.0 }, + "RUSSIAN_60X90_8" => { caption: "60x90/8", origin: "Russian GOST 5773-90", width_mm: 220.0, height_mm: 290.0 }, + "RUSSIAN_60X90_16" => { caption: "60x90/16", origin: "Russian GOST 5773-90", width_mm: 145.0, height_mm: 215.0 }, + "RUSSIAN_70X100_16" => { caption: "70x100/16", origin: "Russian GOST 5773-90", width_mm: 170.0, height_mm: 240.0 }, + "RUSSIAN_70X100_32" => { caption: "70x100/32", origin: "Russian GOST 5773-90", width_mm: 120.0, height_mm: 165.0 }, + "RUSSIAN_70X108_8" => { caption: "70x108/8", origin: "Russian GOST 5773-90", width_mm: 265.0, height_mm: 340.0 }, + "RUSSIAN_70X108_16" => { caption: "70x108/16", origin: "Russian GOST 5773-90", width_mm: 170.0, height_mm: 260.0 }, + "RUSSIAN_70X108_32" => { caption: "70x108/32", origin: "Russian GOST 5773-90", width_mm: 130.0, height_mm: 165.0 }, + "RUSSIAN_70X90_16" => { caption: "70x90/16", origin: "Russian GOST 5773-90", width_mm: 170.0, height_mm: 215.0 }, + "RUSSIAN_70X90_32" => { caption: "70x90/32", origin: "Russian GOST 5773-90", width_mm: 107.0, height_mm: 165.0 }, + "RUSSIAN_75X90_32" => { caption: "75x90/32", origin: "Russian GOST 5773-90", width_mm: 107.0, height_mm: 177.0 }, + "RUSSIAN_84X108_8" => { caption: "84x108/16", origin: "Russian GOST 5773-90", width_mm: 205.0, height_mm: 260.0 }, + "RUSSIAN_84X108_32" => { caption: "84x108/32", origin: "Russian GOST 5773-90", width_mm: 130.0, height_mm: 200.0 }, + }.freeze + end + end + end +end diff --git a/lib/brst/binding/ruby/unicode_glyph.rb b/lib/brst/binding/ruby/unicode_glyph.rb new file mode 100644 index 0000000..6d699f4 --- /dev/null +++ b/lib/brst/binding/ruby/unicode_glyph.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module UnicodeGlyph + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_UnicodeToGlyphName, [:uint16], :string + safe_attach :BRST_GlyphNameToUnicode, [:string], :uint16 + end + end + end +end diff --git a/lib/brst/binding/ruby/xobject.rb b/lib/brst/binding/ruby/xobject.rb new file mode 100644 index 0000000..2f01fa7 --- /dev/null +++ b/lib/brst/binding/ruby/xobject.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true +# +# AUTO-GENERATED by brst-binding-ruby's generator (generator/bin/brst-binding-ruby-gen). +# Source of truth: libBeresta gen/data/*.lsp (S-expression definitions). +# DO NOT EDIT BY HAND. Re-generate with `rake generate`. + +require "ffi" +require_relative "library" +require_relative "types" + +module Brst + module Binding + module Ruby + module Xobject + extend FFI::Library + ffi_lib Brst::Binding::Ruby::Library.lib_path + + Brst::Binding::Ruby::Types.apply(self) + + MISSING_SYMBOLS = [] + + # Wraps `attach_function` so that captions whose actual C symbol + # is missing from the loaded libBeresta build (e.g. caption / + # symbol drift in upstream .lsp data, or features compiled + # out) — or whose declared parameter types reference a struct + # / enum the .lsp data never declared — don't break the entire + # gem load. Each miss is recorded in MISSING_SYMBOLS for + # diagnostic surfaces. + def self.safe_attach(name, args, ret) + attach_function(name, args, ret) + rescue FFI::NotFoundError, TypeError => e + MISSING_SYMBOLS << [name, e.message] + end + + safe_attach :BRST_XObject_Stream, [:XObject], :Stream + end + end + end +end diff --git a/spec/cross_check_spec.rb b/spec/cross_check_spec.rb new file mode 100644 index 0000000..9586c5a --- /dev/null +++ b/spec/cross_check_spec.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require "spec_helper" +require "json" + +# Structural cross-check: our S-expression parser must produce the same +# function / enum / pointer / definition / struct counts as libBeresta's +# auto-generated JSON view of the same .lsp data (`gen/json/*.json`, +# emitted by ECL+Djula). The JSON form is a derived artifact — we don't +# *depend* on it (Source of Truth is .lsp), but for v0.1.0 sanity it is a +# useful structural check to ensure our parser hasn't dropped or duplicated +# any top-level entity. +# +# Skipped automatically when libBeresta is not cloned at ../libBeresta. +RSpec.describe "structural cross-check vs gen/json" do + let(:data_dir) { File.expand_path("../../libBeresta/gen/data", __dir__) } + let(:json_dir) { File.expand_path("../../libBeresta/gen/json", __dir__) } + + before do + skip "libBeresta sibling clone not present" unless Dir.exist?(data_dir) && Dir.exist?(json_dir) + require_relative "../generator/lib/brst_binding_ruby_gen" + end + + it "matches function/enum/pointer/struct counts per file" do + diffs = [] + + Dir.glob(File.join(json_dir, "*.json")).sort.each do |jpath| + base = File.basename(jpath, ".json") + lpath = File.join(data_dir, "#{base}.lsp") + next unless File.exist?(lpath) + + json_tree = JSON.parse(File.read(jpath)) + lsp_tree = BrstBindingRubyGen::SexpParser.parse_file(lpath) + + %w[functions enums pointers definitions structs consts sizes].each do |key| + json_count = (json_tree[key] || []).size + lsp_count = (Array(lsp_tree[key.to_sym])).size + if json_count != lsp_count + diffs << "#{base}.#{key}: json=#{json_count} lsp_parser=#{lsp_count}" + end + end + end + + expect(diffs).to be_empty, "mismatched counts:\n #{diffs.join("\n ")}" + end +end diff --git a/spec/smoke/minimal_spec.rb b/spec/smoke/minimal_spec.rb new file mode 100644 index 0000000..f77cd23 --- /dev/null +++ b/spec/smoke/minimal_spec.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true + +require "spec_helper" +require "fileutils" +require "tmpdir" + +# Smoke test mirroring libBeresta's demo/minimal.c. Verifies that: +# 1. The gem loads its generated FFI bindings. +# 2. The libBeresta shared library can be opened. +# 3. A trivial PDF round-trip (Doc_New -> Page_Add -> SetSize -> SaveToFile) +# produces a non-empty PDF on disk. +# +# Skipped automatically when libBeresta has not been built locally; CI is +# responsible for building before running specs. +RSpec.describe "smoke: minimal PDF generation" do + before(:all) do + begin + require "brst/binding/ruby" + rescue LoadError, FFI::NotFoundError, RuntimeError => e + skip "brst-binding-ruby could not load libBeresta: #{e.message}" + end + end + + let(:tmp_pdf) do + File.join(Dir.mktmpdir("brst-binding-ruby-smoke"), "test.pdf") + end + + it "writes 'Hello, Beresta from Ruby!' to an A4 portrait page" do + base = Brst::Binding::Ruby::Base + doc_page = Brst::Binding::Ruby::DocPage + page_routines = Brst::Binding::Ruby::PageRoutines + doc_save = Brst::Binding::Ruby::DocSave + doc_font = Brst::Binding::Ruby::DocFont + text = Brst::Binding::Ruby::Text + + pdf = base.BRST_Doc_New(nil, nil) + expect(pdf).not_to be_null + + begin + page = doc_page.BRST_Doc_Page_Add(pdf) + page_routines.BRST_Page_SetSize(page, :A4, :PAGE_ORIENTATION_PORTRAIT) + + font = doc_font.BRST_Doc_Font(pdf, "Helvetica", nil) + expect(font).not_to be_null + + text.BRST_Page_BeginText(page) + text.BRST_Page_SetFontAndSize(page, font, 20.0) + text.BRST_Page_MoveTextPos(page, 50.0, 750.0) + text.BRST_Page_ShowText(page, "Hello, Beresta from Ruby!") + text.BRST_Page_EndText(page) + + status = doc_save.BRST_Doc_SaveToFile(pdf, tmp_pdf) + expect(status).to eq(0) + ensure + base.BRST_Doc_Free(pdf) + end + + expect(File.size(tmp_pdf)).to be > 100 + expect(File.read(tmp_pdf, 4)).to eq("%PDF") + end + + it "generates a non-empty A4-landscape PDF (port of demo/minimal.c)" do + base = Brst::Binding::Ruby::Base + doc_page = Brst::Binding::Ruby::DocPage + page_routines = Brst::Binding::Ruby::PageRoutines + doc_save = Brst::Binding::Ruby::DocSave + + pdf = base.BRST_Doc_New(nil, nil) + expect(pdf).not_to be_null + + begin + page = doc_page.BRST_Doc_Page_Add(pdf) + expect(page).not_to be_null + + status = page_routines.BRST_Page_SetSize(page, :A4, :PAGE_ORIENTATION_LANDSCAPE) + expect(status).to eq(0) + + status = doc_save.BRST_Doc_SaveToFile(pdf, tmp_pdf) + expect(status).to eq(0) + ensure + base.BRST_Doc_Free(pdf) + end + + expect(File).to exist(tmp_pdf) + expect(File.size(tmp_pdf)).to be > 100 + expect(File.read(tmp_pdf, 4)).to eq("%PDF") + end + +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..8501f3a --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require "fileutils" +require "tmpdir" + +# Make sure the gem is loadable before the smoke test loads any FFI module — +# but allow the smoke test itself to skip gracefully when libBeresta is not +# built locally. +$LOAD_PATH.unshift File.expand_path("../lib", __dir__) + +RSpec.configure do |config| + config.example_status_persistence_file_path = ".rspec_status" + config.disable_monkey_patching! + config.expect_with :rspec do |c| + c.syntax = :expect + end +end From aa3a2fb81f5a986fe98bad83a29645770bae26f1 Mon Sep 17 00:00:00 2001 From: Kenta Ishizaki Date: Sat, 2 May 2026 18:50:20 +0900 Subject: [PATCH 4/5] Add binding / check / bundle CMake targets Per dmitrys99's guidance (libBeresta/libBeresta#19), all brst-binding- repositories should expose three standard CMake targets for cross-language CI/CD: - binding: regenerate FFI bindings from gen/data/*.lsp - check: run rspec to verify the bindings work - bundle: build the .gem archive These are implemented as custom targets that shell out to the Ruby toolchain (ruby, bundle, gem). --- CMakeLists.txt | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3416d49..a753d7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,3 +58,38 @@ add_custom_target(brst_binding_ruby_stage ALL "${_outdir}/$" DEPENDS brst COMMENT "Staging libbrst shared library into ext/libBeresta/lib/") + +# --------------------------------------------------------------------------- +# Mandatory libBeresta org-wide CMake targets +# +# Per dmitrys99's guidance (libBeresta/libBeresta#19), every +# brst-binding- repository exposes three standard targets so that +# cross-language CI/CD pipelines can drive each binding uniformly: +# +# - binding: regenerate the FFI bindings from libBeresta/gen/data/*.lsp +# - check: run the binding's test suite +# - bundle: produce the language-native distribution archive +# +# For Ruby these shell out to ruby / bundle / gem respectively. +# --------------------------------------------------------------------------- + +set(_gen_data_dir "${LIBBRST_SOURCE_DIR}/gen/data") +set(_binding_out_dir "${CMAKE_CURRENT_LIST_DIR}/lib/brst/binding/ruby") + +add_custom_target(binding + COMMAND ruby + "${CMAKE_CURRENT_LIST_DIR}/generator/bin/brst-binding-ruby-gen" + --data-dir "${_gen_data_dir}" + --out-dir "${_binding_out_dir}" + WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}" + COMMENT "Regenerating FFI bindings from ${_gen_data_dir}") + +add_custom_target(check + COMMAND bundle exec rspec + WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}" + COMMENT "Running rspec to verify the bindings") + +add_custom_target(bundle + COMMAND gem build brst-binding-ruby.gemspec + WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}" + COMMENT "Building brst-binding-ruby .gem archive") From 55a4044835f97631145ec1fdc24824ab02d37655 Mon Sep 17 00:00:00 2001 From: Kenta Ishizaki Date: Sun, 3 May 2026 12:01:05 +0900 Subject: [PATCH 5/5] Include all page-size origins in synthesised PageSizes enum Per review feedback from @dmitrys99: the generator was filtering page_sizes.lsp entries to ISO 216 only, but should include all origins (US Letter, US Arch, JIS B, etc.) to match the full set available in the C headers. --- .../lib/brst_binding_ruby_gen/symbol_table.rb | 18 +++++++++--------- lib/brst/binding/ruby/types.rb | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/generator/lib/brst_binding_ruby_gen/symbol_table.rb b/generator/lib/brst_binding_ruby_gen/symbol_table.rb index 5c021dd..fcc71e0 100644 --- a/generator/lib/brst_binding_ruby_gen/symbol_table.rb +++ b/generator/lib/brst_binding_ruby_gen/symbol_table.rb @@ -201,21 +201,21 @@ def absorb_sizes(rows) # `PageSizes` is referenced by functions in base.lsp and page_routines.lsp, # but the .lsp files never declare it as an :enum. Upstream's C header - # `brst_page_sizes_iso_216.h` (used when LIBBRST_ISO_216_ONLY=ON, the - # default build mode) auto-numbers ISO 216 entries from 0 in the same - # source order they appear in page_sizes.lsp. Synthesise the matching - # FFI enum so callers can pass `:A4` instead of a magic integer. + # `brst_page_sizes.h` auto-numbers every entry from 0 in the same source + # order they appear in page_sizes.lsp, spanning all origins (US Loose, + # US ANSI, US Arch, ISO 216, JIS B, etc.). Synthesise the matching FFI + # enum so callers can pass `:A4` (or `:US_LETTER`, `:US_ARCH_A`, ...) + # instead of a magic integer. def synthesize_page_sizes_enum! - iso216 = @sizes.select { |s| s[:origin] == "ISO 216" } - return if iso216.empty? - elements = iso216.each_with_index.map do |s, i| + return if @sizes.empty? + elements = @sizes.each_with_index.map do |s, i| { element: s[:id], value: i, en: "", ru: "" } end - elements << { element: "EOF", value: iso216.size, en: "", ru: "" } + elements << { element: "EOF", value: @sizes.size, en: "", ru: "" } @enums["PageSizes"] = { name: "PageSizes", elements: elements, - en: "ISO 216 page size enum (synthesised from page_sizes.lsp).", + en: "Page size enum (synthesised from page_sizes.lsp, all origins).", ru: "" } end diff --git a/lib/brst/binding/ruby/types.rb b/lib/brst/binding/ruby/types.rb index 93b135e..eeb2514 100644 --- a/lib/brst/binding/ruby/types.rb +++ b/lib/brst/binding/ruby/types.rb @@ -107,7 +107,7 @@ def apply_enums(mod) mod.enum :PageBoundary, [:PAGE_MEDIABOX, :PAGE_CROPBOX, :PAGE_BLEEDBOX, :PAGE_TRIMBOX, :PAGE_ARTBOX] mod.enum :PageTransition, [:PAGE_TRANSITION_WIPE_RIGHT, :PAGE_TRANSITION_WIPE_UP, :PAGE_TRANSITION_WIPE_LEFT, :PAGE_TRANSITION_WIPE_DOWN, :PAGE_TRANSITION_BARN_DOORS_HORIZONTAL_OUT, :PAGE_TRANSITION_BARN_DOORS_HORIZONTAL_IN, :PAGE_TRANSITION_BARN_DOORS_VERTICAL_OUT, :PAGE_TRANSITION_BARN_DOORS_VERTICAL_IN, :PAGE_TRANSITION_BOX_OUT, :PAGE_TRANSITION_BOX_IN, :PAGE_TRANSITION_BLINDS_HORIZONTAL, :PAGE_TRANSITION_BLINDS_VERTICAL, :PAGE_TRANSITION_DISSOLVE, :PAGE_TRANSITION_GLITTER_RIGHT, :PAGE_TRANSITION_GLITTER_DOWN, :PAGE_TRANSITION_GLITTER_TOP_LEFT_TO_BOTTOM_RIGHT, :PAGE_TRANSITION_REPLACE] mod.enum :PageOrientation, [:PAGE_ORIENTATION_PORTRAIT, :PAGE_ORIENTATION_LANDSCAPE] - mod.enum :PageSizes, [:"4A0", 0, :"2A0", 1, :A0, 2, :A0_PLUS, 3, :A1, 4, :A1_PLUS, 5, :A2, 6, :A3, 7, :A3_PLUS, 8, :A4, 9, :A5, 10, :A6, 11, :A7, 12, :A8, 13, :A9, 14, :A10, 15, :B0, 16, :B0_PLUS, 17, :B1, 18, :B1_PLUS, 19, :B2, 20, :B2_PLUS, 21, :B3, 22, :B4, 23, :B5, 24, :B6, 25, :B7, 26, :B8, 27, :B9, 28, :B10, 29, :B11, 30, :B12, 31, :B13, 32, :C0, 33, :C1, 34, :C2, 35, :C3, 36, :C4, 37, :C5, 38, :C6, 39, :C7, 40, :C8, 41, :C9, 42, :C10, 43, :EOF, 44] + mod.enum :PageSizes, [:US_LETTER, 0, :US_LEGAL, 1, :US_TABLOID, 2, :US_LEDGER, 3, :US_JUNIOR_LEGAL, 4, :US_HALF_LETTER, 5, :US_GOVERNMENT_LETTER, 6, :US_GOVERNMENT_LEGAL, 7, :US_ANSI_A, 8, :US_ANSI_B, 9, :US_ANSI_C, 10, :US_ANSI_D, 11, :US_ANSI_E, 12, :US_ARCH_A, 13, :US_ARCH_B, 14, :US_ARCH_C, 15, :US_ARCH_D, 16, :US_ARCH_E, 17, :US_ARCH_E1, 18, :US_ARCH_E2, 19, :US_ARCH_E3, 20, :"4A0", 21, :"2A0", 22, :A0, 23, :A0_PLUS, 24, :A1, 25, :A1_PLUS, 26, :A2, 27, :A3, 28, :A3_PLUS, 29, :A4, 30, :A5, 31, :A6, 32, :A7, 33, :A8, 34, :A9, 35, :A10, 36, :B0, 37, :B0_PLUS, 38, :B1, 39, :B1_PLUS, 40, :B2, 41, :B2_PLUS, 42, :B3, 43, :B4, 44, :B5, 45, :B6, 46, :B7, 47, :B8, 48, :B9, 49, :B10, 50, :B11, 51, :B12, 52, :B13, 53, :C0, 54, :C1, 55, :C2, 56, :C3, 57, :C4, 58, :C5, 59, :C6, 60, :C7, 61, :C8, 62, :C9, 63, :C10, 64, :BRITISH_DUKES, 65, :BRITISH_FOOLSCAP, 66, :BRITISH_IMPERIAL, 67, :BRITISH_KINGS, 68, :BRITISH_QUARTO, 69, :US_ENVELOPE_6_1_4, 70, :US_ENVELOPE_6_3_4, 71, :US_ENVELOPE_7, 72, :US_ENVELOPE_7_3_4_MONARCH, 73, :US_ENVELOPE8_5_8, 74, :US_ENVELOPE_9, 75, :US_ENVELOPE_10, 76, :US_ENVELOPE_11, 77, :US_ENVELOPE_12, 78, :US_ENVELOPE_14, 79, :US_ENVELOPE_16, 80, :US_ENVELOPE_A1, 81, :US_ENVELOPE_A2_LADY_GREY, 82, :US_ENVELOPE_A4, 83, :US_ENVELOPE_A6_THOMPSON_S_STANDARD, 84, :US_ENVELOPE_A7_BESSELHEIM, 85, :US_ENVELOPE_A8_CARR_S, 86, :US_ENVELOPE_A9_DIPLOMAT, 87, :US_ENVELOPE_A10_WILLOW, 88, :US_ENVELOPE_A_LONG, 89, :US_ENVELOPE_1, 90, :US_ENVELOPE_1_3_4, 91, :US_ENVELOPE_3, 92, :US_ENVELOPE_6, 93, :US_ENVELOPE_8, 94, :US_ENVELOPE_9_3_4, 95, :US_ENVELOPE_10_1_2, 96, :US_ENVELOPE_12_1_2, 97, :US_ENVELOPE_13_1_2, 98, :US_ENVELOPE_14_1_2, 99, :US_ENVELOPE_15, 100, :US_ENVELOPE_15_1_2, 101, :ENVELOPE_DL, 102, :ENVELOPE_B4, 103, :ENVELOPE_B5, 104, :ENVELOPE_B6, 105, :ENVELOPE_C3, 106, :ENVELOPE_C4, 107, :ENVELOPE_C4M, 108, :ENVELOPE_C5, 109, :ENVELOPE_C6_C5, 110, :ENVELOPE_C6, 111, :ENVELOPE_C64M, 112, :ENVELOPE_C7_C6, 113, :ENVELOPE_C7, 114, :ENVELOPE_CE4, 115, :ENVELOPE_CE64, 116, :ENVELOPE_E4, 117, :ENVELOPE_EC45, 118, :ENVELOPE_EC5, 119, :ENVELOPE_E5, 120, :ENVELOPE_E56, 121, :ENVELOPE_E6, 122, :ENVELOPE_E65, 123, :ENVELOPE_R7, 124, :ENVELOPE_S4, 125, :ENVELOPE_S5, 126, :ENVELOPE_S65, 127, :ENVELOPE_X5, 128, :ENVELOPE_EX5, 129, :PHOTO_PASSPORT, 130, :PHOTO_2R, 131, :PHOTO_LD, 132, :PHOTO_DSC, 133, :PHOTO_3R, 134, :PHOTO_L, 135, :PHOTO_LW, 136, :PHOTO_KGD, 137, :PHOTO_KG, 138, :PHOTO_4R, 139, :PHOTO_2LD, 140, :PHOTO_DSCW, 141, :PHOTO_2L, 142, :PHOTO_5R, 143, :PHOTO_2LW, 144, :PHOTO_6R, 145, :PHOTO_8R, 146, :PHOTO_6P, 147, :PHOTO_6PW, 148, :PHOTO_S8R, 149, :PHOTO_11R, 150, :PHOTO_A3_PLUS, 151, :NEWSPAPER_BERLINER, 152, :NEWSPAPER_BROADSHEET, 153, :NEWSPAPER_US_BROADSHEET, 154, :NEWSPAPER_BRITISH_BROADSHEET, 155, :NEWSPAPER_SOUTH_AFRICAN_BROADSHEET, 156, :NEWSPAPER_CINER, 157, :NEWSPAPER_COMPACT, 158, :NEWSPAPER_NORDISCH, 159, :NEWSPAPER_RHENISH, 160, :NEWSPAPER_SWISS, 161, :NEWSPAPER_TABLOID, 162, :NEWSPAPER_CANADIAN_TABLOID, 163, :NEWSPAPER_NORWEGIAN_TABLOID, 164, :NEWSPAPER_NEW_YOUR_TIMES, 165, :NEWSPAPER_WALL_STREET_JOURNAL, 166, :BOOK_FOLIO, 167, :BOOK_QUARTO, 168, :BOOK_IMPERIAL_OCTAVO, 169, :BOOK_SUPER_OCTAVO, 170, :BOOK_ROYAL_OCTAVO, 171, :BOOK_MEDIUM_OCTAVO, 172, :BOOK_OCTAVO, 173, :BOOK_CROWN_OCTAVO, 174, :BOOK_12MO, 175, :BOOK_16MO, 176, :BOOK_18MO, 177, :BOOK_32MO, 178, :BOOK_48MO, 179, :BOOK_64MO, 180, :BOOK_A_FORMAT, 181, :BOOK_B_FORMAT, 182, :BOOK_C_FORMAT, 183, :BUSINESS_CARD_ISO_216, 184, :BUSINESS_CARD_US_CANADA, 185, :BUSINESS_CARD_EUROPEAN, 186, :BUSINESS_CARD_SCANDINAVIA, 187, :BUSINESS_CARD_CHINA, 188, :BUSINESS_CARD_JAPAN, 189, :BUSINESS_CARD_IRAN, 190, :BUSINESS_CARD_HUNGARY, 191, :BUSINESS_CARD_ISO_7810_ID_1, 192, :RAW_RA0, 193, :RAW_RA1, 194, :RAW_RA2, 195, :RAW_RA3, 196, :RAW_RA4, 197, :RAW_SRA0, 198, :RAW_SRA1, 199, :RAW_SRA2, 200, :RAW_SRA3, 201, :RAW_SRA4, 202, :RAW_SRA1_PLUS, 203, :RAW_SRA2_PLUS, 204, :RAW_SRA3_PLUS, 205, :RAW_SRA3_PLUS_PLUS, 206, :RAW_A0U, 207, :RAW_A1U, 208, :RAW_A2U, 209, :RAW_A3U, 210, :RAW_A4U, 211, :BILLBOARD_1_SHEET, 212, :BILLBOARD_2_SHEET, 213, :BILLBOARD_4_SHEET, 214, :BILLBOARD_6_SHEET, 215, :BILLBOARD_12_SHEET, 216, :BILLBOARD_16_SHEET, 217, :BILLBOARD_32_SHEET, 218, :BILLBOARD_48_SHEET, 219, :BILLBOARD_64_SHEET, 220, :BILLBOARD_96_SHEET, 221, :JAPANESE_JB0, 222, :JAPANESE_JB1, 223, :JAPANESE_JB2, 224, :JAPANESE_JB3, 225, :JAPANESE_JB4, 226, :JAPANESE_JB5, 227, :JAPANESE_JB6, 228, :JAPANESE_JB7, 229, :JAPANESE_JB8, 230, :JAPANESE_JB9, 231, :JAPANESE_JB10, 232, :JAPANESE_JB11, 233, :JAPANESE_JB12, 234, :JAPANESE_SHIROKU_BAN_4, 235, :JAPANESE_SHIROKU_BAN_5, 236, :JAPANESE_SHIROKU_BAN_6, 237, :JAPANESE_KIKU_4, 238, :JAPANESE_KIKU_5, 239, :CANADIAN_P1, 240, :CANADIAN_P2, 241, :CANADIAN_P3, 242, :CANADIAN_P4, 243, :CANADIAN_P5, 244, :CANADIAN_P6, 245, :DIN_D0, 246, :DIN_D1, 247, :DIN_D2, 248, :DIN_D3, 249, :DIN_D4, 250, :DIN_D5, 251, :DIN_D6, 252, :DIN_D7, 253, :DIN_D8, 254, :SIS_E0, 255, :SIS_E1, 256, :SIS_E2, 257, :SIS_E3, 258, :SIS_E4, 259, :SIS_E5, 260, :SIS_E6, 261, :SIS_E7, 262, :SIS_E8, 263, :SIS_E9, 264, :SIS_E10, 265, :SIS_F0, 266, :SIS_F1, 267, :SIS_F2, 268, :SIS_F3, 269, :SIS_F4, 270, :SIS_F5, 271, :SIS_F6, 272, :SIS_F7, 273, :SIS_F8, 274, :SIS_F9, 275, :SIS_F10, 276, :SIS_G0, 277, :SIS_G1, 278, :SIS_G2, 279, :SIS_G3, 280, :SIS_G4, 281, :SIS_G5, 282, :SIS_G6, 283, :SIS_G7, 284, :SIS_G8, 285, :SIS_G9, 286, :SIS_G10, 287, :SIS_D0, 288, :SIS_D1, 289, :SIS_D2, 290, :SIS_D3, 291, :SIS_D4, 292, :SIS_D5, 293, :SIS_D6, 294, :SIS_D7, 295, :SIS_D8, 296, :SIS_D9, 297, :SIS_D10, 298, :COLOMBIAN_CARTA, 299, :COLOMBIAN_EXTRA_TABLOIDE, 300, :COLOMBIAN_OFICIO, 301, :COLOMBIAN_1_8_PLIEGO, 302, :COLOMBIAN_1_4_PLIEGO, 303, :COLOMBIAN_1_2_PLIEGO, 304, :COLOMBIAN_PLIEGO, 305, :CHINESE_D0, 306, :CHINESE_D1, 307, :CHINESE_D2, 308, :CHINESE_D3, 309, :CHINESE_D4, 310, :CHINESE_D5, 311, :CHINESE_D6, 312, :CHINESE_RD0, 313, :CHINESE_RD1, 314, :CHINESE_RD2, 315, :CHINESE_RD3, 316, :CHINESE_RD4, 317, :CHINESE_RD5, 318, :CHINESE_RD6, 319, :TRANSITIONAL_PA0, 320, :TRANSITIONAL_PA1, 321, :TRANSITIONAL_PA2, 322, :TRANSITIONAL_PA3, 323, :TRANSITIONAL_PA4, 324, :TRANSITIONAL_PA5, 325, :TRANSITIONAL_PA6, 326, :TRANSITIONAL_PA7, 327, :TRANSITIONAL_PA8, 328, :TRANSITIONAL_PA9, 329, :TRANSITIONAL_PA10, 330, :TRANSITIONAL_F0, 331, :TRANSITIONAL_F1, 332, :TRANSITIONAL_F2, 333, :TRANSITIONAL_F3, 334, :TRANSITIONAL_F4, 335, :TRANSITIONAL_F5, 336, :TRANSITIONAL_F6, 337, :TRANSITIONAL_F7, 338, :TRANSITIONAL_F8, 339, :TRANSITIONAL_F9, 340, :TRANSITIONAL_F10, 341, :IMPERIAL_ANTIQUARIAN, 342, :IMPERIAL_ATLAS, 343, :IMPERIAL_BRIEF, 344, :IMPERIAL_BROADSHEET, 345, :IMPERIAL_CARTRIDGE, 346, :IMPERIAL_COLUMBIER, 347, :IMPERIAL_COPY_DRAUGHT, 348, :IMPERIAL_CROWN, 349, :IMPERIAL_DEMY, 350, :IMPERIAL_DOUBLE_DEMY, 351, :IMPERIAL_QUAD_DEMY, 352, :IMPERIAL_ELEPHANT, 353, :IMPERIAL_DOUBLE_ELEPHANT, 354, :IMPERIAL_EMPEROR, 355, :IMPERIAL_FOOLSCAP, 356, :IMPERIAL_SMALL_FOOLSCAP, 357, :IMPERIAL_GRAND_EAGLE, 358, :IMPERIAL_IMPERIAL, 359, :IMPERIAL_MEDIUM, 360, :IMPERIAL_MONARCH, 361, :IMPERIAL_POST, 362, :IMPERIAL_HALF_POST, 363, :IMPERIAL_PINCHED_POST, 364, :IMPERIAL_LARGE_POST, 365, :IMPERIAL_DOUBLE_LARGE_POST, 366, :IMPERIAL_DOUBLE_POST, 367, :IMPERIAL_POTT, 368, :IMPERIAL_PRINCESS, 369, :IMPERIAL_QUARTO, 370, :IMPERIAL_ROYAL, 371, :IMPERIAL_SUPER_ROYAL, 372, :FRENCH_CLOCHE, 373, :FRENCH_POT_ECOLIER, 374, :FRENCH_TELLIERE, 375, :FRENCH_COURONNE_ECRITURE, 376, :FRENCH_COURONNE_EDITION, 377, :FRENCH_ROBERTO, 378, :FRENCH_ECU, 379, :FRENCH_COQUILLE, 380, :FRENCH_CARRE, 381, :FRENCH_CAVALIER, 382, :FRENCH_DEMI_RAISIN, 383, :FRENCH_RAISIN, 384, :FRENCH_DOUBLE_RAISIN, 385, :FRENCH_JESUS, 386, :FRENCH_SOLEIL, 387, :FRENCH_COLOMBIER_AFFICHE, 388, :FRENCH_COLOMBIER_COMMERCIAL, 389, :FRENCH_PETIT_AIGLE, 390, :FRENCH_GRAND_AIGLE, 391, :FRENCH_GRAND_MONDE, 392, :FRENCH_UNIVERS, 393, :RUSSIAN_60X84_8, 394, :RUSSIAN_60X84_16, 395, :RUSSIAN_60X84_32, 396, :RUSSIAN_60X90_8, 397, :RUSSIAN_60X90_16, 398, :RUSSIAN_70X100_16, 399, :RUSSIAN_70X100_32, 400, :RUSSIAN_70X108_8, 401, :RUSSIAN_70X108_16, 402, :RUSSIAN_70X108_32, 403, :RUSSIAN_70X90_16, 404, :RUSSIAN_70X90_32, 405, :RUSSIAN_75X90_32, 406, :RUSSIAN_84X108_8, 407, :RUSSIAN_84X108_32, 408, :EOF, 409] mod.enum :TextRenderingMode, [:TEXT_RENDERING_MODE_FILL, :TEXT_RENDERING_MODE_STROKE, :TEXT_RENDERING_MODE_FILL_THEN_STROKE, :TEXT_RENDERING_MODE_INVISIBLE, :TEXT_RENDERING_MODE_FILL_CLIPPING, :TEXT_RENDERING_MODE_STROKE_CLIPPING, :TEXT_RENDERING_MODE_FILL_STROKE_CLIPPING, :TEXT_RENDERING_MODE_CLIPPING] mod.enum :TextAlignment, [:TEXT_ALIGN_LEFT, :TEXT_ALIGN_RIGHT, :TEXT_ALIGN_CENTER, :TEXT_ALIGN_JUSTIFY] mod.enum :WritingMode, [:WRITING_MODE_HORIZONTAL, :WRITING_MODE_VERTICAL]