Module: Marcel::Magic::Zip
- Defined in:
- lib/marcel/magic/zip.rb
Overview
Procedural refinement of ZIP-based container types.
The declarative magic tables scan a bounded prefix of the file (matchers are capped at 64KB offsets when the tables are generated), so ZIP containers whose distinguishing members are catalogued later in the archive — such as OOXML documents with [Content_Types].xml stored past the 64KB mark — fall back to their generic container type. This module instead parses the ZIP central directory, a bounded read from the end of the file, to recover the specific document type, including macro-enabled variants, which no prefix bytes can distinguish.
Constant Summary collapse
- EOCD_SIGNATURE =
"PK\x05\x06".b
- ZIP64_EOCD_SIGNATURE =
"PK\x06\x06".b
- ZIP64_EOCD_LOCATOR_SIGNATURE =
"PK\x06\x07".b
- CENTRAL_DIRECTORY_SIGNATURE =
"PK\x01\x02".b
- EOCD_SIZE =
22- ZIP64_EOCD_SIZE =
56- ZIP64_EOCD_LOCATOR_SIZE =
20- MAX_COMMENT_SIZE =
0xFFFF- MAX_EOCD_SEARCH =
The end-of-central-directory record sits at most a maximal comment from the end of the file, possibly preceded by a Zip64 locator.
EOCD_SIZE + MAX_COMMENT_SIZE + ZIP64_EOCD_LOCATOR_SIZE
- MAX_EOCD_CANDIDATES =
A malformed trailer full of EOCD signature bytes could otherwise force a quadratic backward scan; real archives find the record on the first candidate.
64- CENTRAL_DIRECTORY_HEADER_SIZE =
46- MAX_CENTRAL_DIRECTORY_READ =
1 << 20
- MAX_ENTRIES =
8192- REFINABLE_TYPES =
Container types a central directory listing can make more specific.
[ "application/zip", "application/x-tika-ooxml", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/vnd.openxmlformats-officedocument.presentationml.presentation" ].freeze
- DOCUMENT_FAMILIES =
Standardised OPC part names identifying each OOXML document family: main part, macro part, and the types each implies.
[ [ "word/document.xml", "word/vbaProject.bin", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.ms-word.document.macroenabled.12" ], [ "xl/workbook.xml", "xl/vbaProject.bin", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/vnd.ms-excel.sheet.macroenabled.12" ], [ "ppt/presentation.xml", "ppt/vbaProject.bin", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "application/vnd.ms-powerpoint.presentation.macroenabled.12" ] ].freeze
- DISCRIMINATING_PARTS =
DOCUMENT_FAMILIES.flat_map { |main, macro, *| [main, macro] }.freeze
Class Method Summary collapse
-
.refine(io, base_type) ⇒ Object
Returns a more specific type than
base_typeif the IO's ZIP central directory identifies one, orbase_typeunchanged.
Class Method Details
.refine(io, base_type) ⇒ Object
Returns a more specific type than base_type if the IO's ZIP central directory
identifies one, or base_type unchanged. Unseekable IOs, partial reads and
malformed archives refine nothing: the base type stands.
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/marcel/magic/zip.rb', line 66 def refine(io, base_type) return base_type unless REFINABLE_TYPES.include?(base_type) io = StringIO.new(io.to_s) unless io.respond_to?(:read) return base_type unless io.respond_to?(:seek) && io.respond_to?(:size) parts = begin discriminating_parts(io) rescue StandardError nil ensure begin io.rewind rescue StandardError nil end end parts ? classify(parts, base_type) : base_type end |