From fd0fbed9989911791d95292e287349aceb613ded Mon Sep 17 00:00:00 2001 From: David Lilue <2525462+dvdalilue@users.noreply.github.com> Date: Fri, 16 Jul 2021 09:55:44 +0000 Subject: [PATCH 1/7] Core support for embedded files. Name dictionary entry --- lib/pdf/core.rb | 1 + lib/pdf/core/embedded_files.rb | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 lib/pdf/core/embedded_files.rb diff --git a/lib/pdf/core.rb b/lib/pdf/core.rb index 33ee64c..fbc3445 100644 --- a/lib/pdf/core.rb +++ b/lib/pdf/core.rb @@ -4,6 +4,7 @@ require_relative 'core/annotations' require_relative 'core/byte_string' require_relative 'core/destinations' +require_relative 'core/embedded_files' require_relative 'core/filters' require_relative 'core/stream' require_relative 'core/reference' diff --git a/lib/pdf/core/embedded_files.rb b/lib/pdf/core/embedded_files.rb new file mode 100644 index 0000000..abd552e --- /dev/null +++ b/lib/pdf/core/embedded_files.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module PDF + module Core + module EmbeddedFiles #:nodoc: + # The maximum number of children to fit into a single node in the + # EmbeddedFiles tree. + NAME_TREE_CHILDREN_LIMIT = 20 #:nodoc: + + # The EmbeddedFiles name tree in the Name dictionary (see + # Prawn::Document::Internal#names). This name tree is used to store named + # embedded files (PDF spec 3.10.3). (For more on name trees, see section + # 3.8.4 in the PDF spec.) + # + def embedded_files + names.data[:EmbeddedFiles] ||= ref!( + PDF::Core::NameTree::Node.new(self, NAME_TREE_CHILDREN_LIMIT) + ) + end + + # Adds a new embedded file to the EmbeddedFiles name tree + # (see #embedded_files). The +reference+ parameter will be converted into + # a PDF::Core::Reference if it is not already one. + # + def add_embedded_file(name, reference) + reference = ref!(reference) unless reference.is_a?(PDF::Core::Reference) + embedded_files.data.add(name, reference) + end + + # Friendly method alias to attach file specifications in the catalog + alias :attach_file :add_embedded_file + end + end +end \ No newline at end of file From 503c388ee556194fe3c373ab5888607f46b0e119 Mon Sep 17 00:00:00 2001 From: David Lilue <2525462+dvdalilue@users.noreply.github.com> Date: Fri, 16 Jul 2021 09:55:44 +0000 Subject: [PATCH 2/7] Core support for embedded files. Name dictionary entry --- lib/pdf/core/embedded_files.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pdf/core/embedded_files.rb b/lib/pdf/core/embedded_files.rb index abd552e..c9c1731 100644 --- a/lib/pdf/core/embedded_files.rb +++ b/lib/pdf/core/embedded_files.rb @@ -31,4 +31,4 @@ def add_embedded_file(name, reference) alias :attach_file :add_embedded_file end end -end \ No newline at end of file +end From ea9dd93b84b793c6a531bc9fb27f7d799cb3ebd9 Mon Sep 17 00:00:00 2001 From: David Lilue <2525462+dvdalilue@users.noreply.github.com> Date: Mon, 19 Jul 2021 13:50:13 +0000 Subject: [PATCH 3/7] Alias without symbols --- lib/pdf/core/embedded_files.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pdf/core/embedded_files.rb b/lib/pdf/core/embedded_files.rb index c9c1731..47b5a69 100644 --- a/lib/pdf/core/embedded_files.rb +++ b/lib/pdf/core/embedded_files.rb @@ -28,7 +28,7 @@ def add_embedded_file(name, reference) end # Friendly method alias to attach file specifications in the catalog - alias :attach_file :add_embedded_file + alias attach_file add_embedded_file end end end From 9d6edf5f15e70985688ba4e682bc6d5886a42bb0 Mon Sep 17 00:00:00 2001 From: David Lilue <2525462+dvdalilue@users.noreply.github.com> Date: Thu, 22 Jul 2021 18:32:46 +0000 Subject: [PATCH 4/7] Bumping PDF version to 1.4 --- lib/pdf/core/embedded_files.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/pdf/core/embedded_files.rb b/lib/pdf/core/embedded_files.rb index 47b5a69..1edee92 100644 --- a/lib/pdf/core/embedded_files.rb +++ b/lib/pdf/core/embedded_files.rb @@ -13,6 +13,8 @@ module EmbeddedFiles #:nodoc: # 3.8.4 in the PDF spec.) # def embedded_files + bump_min_version + names.data[:EmbeddedFiles] ||= ref!( PDF::Core::NameTree::Node.new(self, NAME_TREE_CHILDREN_LIMIT) ) @@ -29,6 +31,15 @@ def add_embedded_file(name, reference) # Friendly method alias to attach file specifications in the catalog alias attach_file add_embedded_file + + private + + def bump_min_version + return if @min_version_bumped + + renderer.min_version(1.4) + @min_version_bumped = true + end end end end From 320268038591864c28eca69e6f69e4f006ed4050 Mon Sep 17 00:00:00 2001 From: David Lilue <2525462+dvdalilue@users.noreply.github.com> Date: Thu, 22 Jul 2021 18:33:23 +0000 Subject: [PATCH 5/7] Testing EmbeddedFiles module with mock class --- spec/pdf/core/embedded_files_spec.rb | 59 ++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 spec/pdf/core/embedded_files_spec.rb diff --git a/spec/pdf/core/embedded_files_spec.rb b/spec/pdf/core/embedded_files_spec.rb new file mode 100644 index 0000000..26f1d27 --- /dev/null +++ b/spec/pdf/core/embedded_files_spec.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +require 'spec_helper' + +class EmbeddedFiles + include PDF::Core::EmbeddedFiles + + class InnerRenderer; def min_version(value); end; end + + attr_reader :renderer + + def initialize + @size = 0 + @root = ref!(Type: :Catalog) + @renderer = InnerRenderer.new + end + + def names + @root.data[:Names] ||= ref!(Type: :Names) + end + + def ref!(data) + @size += 1 + + PDF::Core::Reference.new(@size, data) + end +end + +RSpec.describe EmbeddedFiles do + it 'has an empty catalog object' do + t = described_class.new + pdf_object = "2 0 obj\n<< /Type /Names\n>>\nendobj\n" + expect(t.names.object).to eq pdf_object + end + + it 'has an embedded files object with no names' do + t = described_class.new + pdf_object = "3 0 obj\n<< /Names []\n>>\nendobj\n" + expect(t.embedded_files.object).to eq pdf_object + end + + it 'has a catalog object with an embedded files reference' do + t = described_class.new + t.embedded_files + + pdf_object = "2 0 obj\n<< /Type /Names\n/EmbeddedFiles 3 0 R\n>>\nendobj\n" + expect(t.names.object).to eq pdf_object + end + + it 'has an embedded files object with one name reference' do + t = described_class.new + file_name = PDF::Core::LiteralString.new('my_file') + + t.add_embedded_file(file_name, t.ref!(Type: :Filespec)) + + pdf_object = "4 0 obj\n<< /Names [(my_file) 2 0 R]\n>>\nendobj\n" + expect(t.embedded_files.object).to eq pdf_object + end +end From 9737f81a40e1a1c1927df5109cb2399a0d235e83 Mon Sep 17 00:00:00 2001 From: David Lilue <2525462+dvdalilue@users.noreply.github.com> Date: Fri, 23 Jul 2021 00:14:51 +0000 Subject: [PATCH 6/7] Bumping version on each call. Cheap operation --- lib/pdf/core/embedded_files.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/pdf/core/embedded_files.rb b/lib/pdf/core/embedded_files.rb index 1edee92..91929bf 100644 --- a/lib/pdf/core/embedded_files.rb +++ b/lib/pdf/core/embedded_files.rb @@ -35,10 +35,7 @@ def add_embedded_file(name, reference) private def bump_min_version - return if @min_version_bumped - renderer.min_version(1.4) - @min_version_bumped = true end end end From a1aa4844ea8f384505979cd0b70247a5b2abc168 Mon Sep 17 00:00:00 2001 From: David Lilue <2525462+dvdalilue@users.noreply.github.com> Date: Fri, 23 Jul 2021 15:07:00 +0000 Subject: [PATCH 7/7] Testing name tree size --- spec/pdf/core/embedded_files_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/pdf/core/embedded_files_spec.rb b/spec/pdf/core/embedded_files_spec.rb index 26f1d27..1e73966 100644 --- a/spec/pdf/core/embedded_files_spec.rb +++ b/spec/pdf/core/embedded_files_spec.rb @@ -54,6 +54,7 @@ def ref!(data) t.add_embedded_file(file_name, t.ref!(Type: :Filespec)) pdf_object = "4 0 obj\n<< /Names [(my_file) 2 0 R]\n>>\nendobj\n" + expect(t.embedded_files.data.size).to eq 1 expect(t.embedded_files.object).to eq pdf_object end end