Самый быстрый способ проверить, что PDF-файл поврежден (или просто отсутствует EOF) в Ruby?

Я ищу способ проверить, отсутствует ли в PDF символ конца файла. До сих пор я обнаружил, что могу использовать гем pdf-reader и перехватить исключение MalformedPDFError, или, конечно, я могу просто открыть весь файл и проверить, был ли последний символ EOF. Мне нужно обработать много потенциально больших PDF-файлов, и я хочу загрузить как можно меньше памяти.

Примечание: во всех файлах, которые я хочу обнаружить, будет отсутствовать маркер EOF, поэтому я чувствую, что это немного более конкретный сценарий, чем обнаружение общего "повреждения" PDF. Какой самый лучший и быстрый способ сделать это?

1 ответ

Решение

TL;DR

Находясь в поиске %%EOF, со связанными структурами или без них, является относительно быстрым, даже если вы сканируете весь файл PDF разумного размера. Однако вы можете увеличить скорость, если ограничите свой поиск последним килобайтом или последними 6 или 7 байтами, если вы просто хотите проверить это %%EOF\n это единственная вещь в последней строке PDF-файла.

Обратите внимание, что только полный анализ файла PDF может сказать вам, если файл поврежден, и только полный анализ File Trailer может полностью проверить соответствие трейлера стандартам. Однако ниже я приведу два приближения, которые являются достаточно точными и относительно быстрыми в общем случае.

Проверьте последний килобайт для File Trailer

Эта опция довольно быстрая, так как она просматривает только хвост файла и использует сравнение строк, а не совпадение с регулярным выражением. По словам Adobe:

Для просмотра Acrobat требуется, чтобы маркер %%EOF находился где-то в последних 1024 байтах файла.

Следовательно, следующее будет работать при поиске инструкции трейлера файла в этом диапазоне:

def valid_file_trailer? filename
  File.open filename { |f| f.seek -1024, :END; f.read.include? '%%EOF' }
end

Более строгая проверка файлового трейлера через Regex

Тем не менее, стандарт ISO является более сложным и гораздо более строгим. Это говорит, частично:

Последняя строка файла должна содержать только маркер конца файла, %%EOF. Две предыдущие строки должны содержать, по одной на строку и по порядку, ключевое слово startxref и смещение байта в декодированном потоке от начала файла до начала ключевого слова xref в последнем разделе перекрестных ссылок. Строке startxref должен предшествовать словарь трейлера, состоящий из ключевого слова трейлера, за которым следует серия пар ключ-значение, заключенных в двойные угловые скобки (<<… >>) (с использованием ЗНАКОВ МЕНЬШЕ (3Ch) и GREATER-THAN). ЗНАКИ (3Eh)).

Без фактического разбора PDF вы не сможете проверить это с идеальной точностью, используя регулярные выражения, но вы можете приблизиться. Например:

def valid_file_trailer? filename
  pattern = /^startxref\n\d+\n%%EOF\n\z/m
  File.open(filename) { |f| !!(f.read.scrub =~ pattern) }
end
Другие вопросы по тегам