Понадобилось мне это для того чтобы понять в каком месте и как файл JPEG испорчен в процессе передачи.


VCDIFF — формат и алгоритм для дельта кодирования. Описан в RFC 3284.

Дельта-кодирование (англ. Delta encoding) — способ представления данных в виде разницы (дельты) между последовательными данными вместо самих данных.

Для примера я использую текстовые файлы в кодировке Windows-1251 для наглядности. Но с таким же успехом это могут быть и бинарные файлы.


Исходники:


"копия    текст    копия"       ( source.txt )
"копия    изменения    копия"   ( target.txt )

Нужно получить разницу между файлами:


"         изменения         "   ( source.txt -> target.txt )
"         текст         "       ( target.txt -> source.txt )

Я пользуюсь программой xdelta3 но думаю подойдёт любая которая работает с форматом vcdiff.


Как получить


Нам понадобится ещё один файл заполненный пробелами:


"                           " ( spaces.txt )

Он должен быть больше или равен по размеру файлу источнику ( source.txt )


Команда:


xdelta3 -e -A -n -s source.txt target.txt | xdelta3 -d -s spaces.txt

Результат:


         изменения         

Использованные флаги:
-e — создание дельты
-A — убирает лишние заголовки
-n — убирает crc (он не даёт применить дельту с другим источником)
-s [файл] — источник с которым сравнивается целевой файл и восстанавливается
-d — получение целевого файла из дельты и источника


Как это работает


Если выполнить команду:


xdelta3 -e -A -n -s source.txt target.txt | xdelta3 printdelta

То после всех заголовков увидим команды VCDIFF


  Offset Code Type1 Size1  @Addr1 + Type2 Size2 @Addr2
  000000 025  CPY_0      9 S@0
  000009 010  ADD        9
  000018 025  CPY_0      9 S@14

Формат VCDIFF по своей сути очень простой. Он состоит из 3х команд.


COPY (копировать) — копирует данные из источника или цели
ADD (добавить) — пишет в целевой файл данные сохранённые в дельте (уникальные данные которых нет в источнике)
RUN (повторить) — повторяет один байт из дельты заданное количество раз


Дельта хранит только уникальные данные а остальное копирует из источника. Если выполнть команду:


xdelta3 -e -A -n -s source.txt target.txt > target.vcdiff

Мы увидим в дельте только слово "изменения" которое есть только в целевом файле


D0A6D093D094200102011720131B2009
0302изменения190D0A19200E

(JSON не любит спец символы поэтому я перевёл их в HEX)


Если дельту применить на источнике (source.txt) то мы получим целевой файл (target.txt)


xdelta3 -d -s source.txt target.vcdiff
копия    изменения    копия

Подменив источник (source.txt) на файл заполненный пробелами (spaces.txt) мы заменили данные которые повторяются в источнике и в целевом файле на пробелы.


xdelta3 -d -s spaces.txt target.vcdiff
         изменения         

В файле spaces.txt можно использовать любой другой символ. Главное условие чтобы файл spaces.txt был больше либо равен по размеру файлу источнику.


Собственно JPEG файлы я сравнивал так:


xdelta3 -e -A -n -s bad_image.jpg good_image.jpg | xdelta3 -d -s spaces.txt

Результат сравнения этих файлов:


Посмотреть результат
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           F488A2                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            F2AB                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            

Много пробелов и байты которые были "побиты". Битые байты перевёл в HEX.


Тестовые jpeg файлы на которых вы можете протестировать способы сравнения:


magnettortoise.jpg (18 821 b) magnettortoise_bad.jpg (18 829 b)
tortoise.jpg tortoise_bad.jpg

xdelta3 -e -A -n -s tortoise_bad.jpg tortoise.jpg | xdelta3 -d -s spaces.txt

Результат сравнения этих файлов:


Посмотреть результат
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             F1BF                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     F0B786                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          F39BAF                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     F3BD94                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         

Битые байты перевёл в HEX.

Комментарии (24)


  1. GH0st3rs
    11.08.2018 12:07

    У меня одного вопрос: "А где описание сравнения JPEG?"
    Обычный текст можно и обычным diff сравнить


    1. ivan386 Автор
      11.08.2018 12:12

      Я текст выбрал для демонстрации чтоб наглядно было и не занимало много места. Но могу приложить и портянку с результатом сравнения JPEG файлов. Там собственно много пробелов и кусочки которые были побиты.


      1. GH0st3rs
        11.08.2018 12:14

        Можно просто заменить заголовок ставить)


        1. ivan386 Автор
          11.08.2018 12:44

          Добавил в конце пример результата сравнения JPEG файлов.


  1. Alukardd
    11.08.2018 15:53

    Чот как-то сложно и не удобно…

    Вариант 1: использовать утилиту cmp

    $ cmp -l bad.png good.png | gawk '{printf "%08X %02X %02X\n", $1-1, strtonum(0$2), strtonum(0$3)}'
    00003680 00 AF
    00003681 00 EB
    00003682 00 0B
    00003683 00 9F

    Вариант 2: vim
    vimdiff bad.png good.png
    # и в каждой панели выполнить :%!xxd
    


    1. ivan386 Автор
      11.08.2018 16:41

      Похоже что cmp сравнивает линейно. У меня в файле пару байт добавилось в тех точках и cmp выведет весь хвост в с этого места.


      Со вторым пытаюсь разобраться. Это для любителей vim наверное легче.


      1. Alukardd
        11.08.2018 18:07

        Да, именно с добавленными байтами, есть проблема…


    1. ivan386 Автор
      11.08.2018 17:11

      На старте он конечно подсвечивает строки и места в них где произошли изменения. Это похоже на классический текстовый diff.


      Я пытался. У меня пару раз завис терминал. После команды :%!xxd vim не даёт переключиться на другую панель командой :n. Я бросил это дело.


      1. Alukardd
        11.08.2018 17:57

        vimdiff это для небольших файлов (несколько десятков мегабайт, ну максимум сотня-другая), потом оно начинает ощутимо тормозить.


      1. Alukardd
        11.08.2018 18:03

        :n это не про переключение между split'ами


        1. ivan386 Автор
          11.08.2018 18:28

          А как это делать?


          1. Alukardd
            11.08.2018 19:14

            CTRL-W +
            CTRL-W + hjkl


            1. ivan386 Автор
              11.08.2018 20:02

              У меня получилось. Но это не вариант опять же. После команды :%!xxd файлы разбиваются на строки и после первого лишнего байта весь хвост файла становится красным.


  1. iig
    12.08.2018 09:51

    hexdiff? Увидеть разницу между бинарниками достаточно.


    1. ivan386 Автор
      12.08.2018 16:05

      Добавил в конце тестовые jpeg файлы и результат сравнения. Вы можете на них протестировать hexdiff. У меня его нет.


      1. iig
        12.08.2018 16:44

        apt-get install hexdiff ;)
        Два 16ричных dump'а, разница подсвечивается.


        1. ivan386 Автор
          12.08.2018 18:11

          У меня Windows. Вопрос в том как разница подсвечивается. Если он подсветил большие участки файла то это не правильно. А если только те маленькие участки в несколько байт в которых разница то нормально.


          1. iig
            13.08.2018 14:50

            После обработки картинок скриптами хостинга не вижу смысла их сравнивать.
            ilkdrlzomd3jwpe3s_osj-vvpfw.jpeg — 17737 байт и zkhknvuzulrcqc92aocitt6sfeg.jpeg — 18829. Отличаются внутри чуть более чем полностью. Где взять tortoise.jpg и tortoise_bad.jpg — не понял, сорри.


            1. ivan386 Автор
              13.08.2018 15:48

              Интересно что habr пережал только хороший файл а плохой не тронул. Перезалил на github и поменял ссылки в посте.


              1. iig
                13.08.2018 16:32

                Спс, теперь похоже на правду.
                18829 tortoise_bad.jpg
                18821 tortoise.jpg
                Первое отличие в позиции 0x147D

                Только я все равно не понял, какая задача решалась ;)
                Контроль целостности файлов?
                Восстановление битого файла?
                Исследование программы для обработки картинок (или протокола передачи), странно искажающей данные?


                1. ivan386 Автор
                  13.08.2018 16:50

                  Я исследовал способ передачи бинарных данных в json кодируя в их utf8. Оказалось что файл бился в процессе декодирования из за того что я не учитывал суррогатные символы.


                  Вот с помощью этого способа я и увидел проблемные байты.


                  1. iig
                    13.08.2018 17:06

                    Понятно. google://json binary data говорит, что json это не умеет. И завернуть binary data в utf-8 строку это тоже надо сильно постараться.


                    1. ivan386 Автор
                      13.08.2018 20:49

                      Это не столь эфективно как Base64 но вполне возможно.


                      1. iig
                        13.08.2018 22:29

                        В произвольных двоичных данных могут оказаться символы, не существующие в utf-8. Превозмочь, конечно, возможно, но ведь есть и других готовых способов сериализации, кроме base64.