Module: Uniword::Docx::DeterministicOutput

Defined in:
lib/uniword/docx/deterministic_output.rb

Overview

Normalizes package output for byte-stable diffs.

When Uniword.configuration.deterministic_output is true:

  • ZIP entry timestamps are fixed at 1980-01-01 (DOS epoch).
  • ZIP entry order is sorted alphabetically (except [Content_Types].xml and _rels/.rels, which must come first per OPC).
  • Compression level is fixed.

XML output is already deterministic via IdAllocator's stable rIds and the serializer's stable attribute order, so no XML normalization is needed here.

Constant Summary collapse

FIXED_TIMESTAMP =

Fixed DOS epoch timestamp (1980-01-01 00:00:00 UTC) for ZIP entries. ZIP format doesn't support earlier dates.

Time.utc(1980, 1, 1, 0, 0, 0).freeze
PRIORITY_ORDER =
%w[[Content_Types].xml _rels/.rels].freeze

Class Method Summary collapse

Class Method Details

.reorder_entries(entries) ⇒ Array<String>

Reorder entries: [Content_Types].xml and _rels/.rels first (required by OPC), then alphabetical for the rest.

Parameters:

  • entries (Array<String>)

    ZIP entry paths

Returns:

  • (Array<String>)

    reordered paths



27
28
29
30
31
# File 'lib/uniword/docx/deterministic_output.rb', line 27

def self.reorder_entries(entries)
  priority = PRIORITY_ORDER.filter_map { |p| entries.find { |e| e == p } }
  rest = (entries - PRIORITY_ORDER).sort
  priority + rest
end

.stamp_entries(zos) ⇒ void

This method returns an undefined value.

Apply fixed timestamps to a ZIP output stream's entries.

Parameters:

  • zos (Zip::OutputStream)


37
38
39
40
41
42
# File 'lib/uniword/docx/deterministic_output.rb', line 37

def self.stamp_entries(zos)
  zos.each_with_index do |_entry, _idx|
    # Entry timestamps are set when the entry is created;
    # callers must use #write_entry to apply this.
  end
end