Преобразование образов NRG в ISO

Vladimir
Опубликовано в: C/C++

Позавчера возникла проблема: нужно было срочно переставить Windows XP (ибо VMWare так больно упала, что Windows пал смертью храбрых). Всё хорошо, но вот родного инсталляционного диска под рукой не было, а инсталлятор жил на NTFS-разделе (кстати, DOS-драйвер для чтения NTFS почему-то оказался бессильным). По счастью, на FAT32-диске нашелся образ загрузочного диска. Одна проблема: образ был сохранен Nero и записан в формате NRG. И, как на зло, не было ничего, что понимает NRG-образы. А так как Internet тоже не было (какой там Internet при загрузке с Реаниматора!), пришлось думать, как можно с ограниченными средствами преобразовать NRG-образ в ISO.

По счастью, я когда-то задавался этим вопросом — нужно было достать файлы из NRG, но записывать диск не хотелось. Тогда вот и поверхностно познакомился с форматом NRG. Но, к сожалению, тогда я это забросил. Но тестовые ISO и NRG-файлы остались.

Сразу отмечу (хотя выяснил это я позже), что все сказанное ниже относится только к образам CD-дисков, записанных методом Disk-at-Once (DAO). Если диск был записан в режиме Track-at-Once (TAO), то приведённое ниже преобразование к нему применять нельзя. Разница между режимами DAO и TAO прекрасно описана в Wikipedia в статье "Optical disc recording modes". Обычно загрузочные диски пишутся в режиме DAO.

Продолжим.
Первое, на что я сразу же обратил внимание — NRG-образ был примерно на 300 КиБ больше, чем ISO-образ. Что вполне логично, если рассматривать NRG-файл как ISO-образ плюс метаданные. Простое сравнение показало, что у NRG-файла есть какой-то непонятный заголовок размером 300 КиБ, состоящий из одних нулей.

В моём случае NRG-файл был длиннее на 144 байта. Хвост выглядел следующим образом:

002B916800: 43 55 45 58 00 00 00 20 │ 41 00 00 00 FF FF FF 6A
002B916810: 41 01 00 00 FF FF FF 6A │ 41 01 01 00 00 00 00 00
002B916820: 41 AA 01 00 00 05 71 97 │ 44 41 4F 58 00 00 00 40
002B916830: 00 00 00 40 00 00 00 00 │ 00 00 00 00 00 00 00 00
002B916840: 00 00 00 01 01 01 00 00 │ 00 00 00 00 00 00 00 00
002B916850: 00 00 08 00 00 00 00 01 │ 00 00 00 00 00 00 00 00
002B916860: 00 00 00 00 00 04 B0 00 │ 00 00 00 00 2B 91 68 00
002B916870: 53 49 4E 46 00 00 00 04 │ 00 00 00 01 4D 54 59 50
002B916880: 00 00 00 04 00 00 00 01 │ 45 4E 44 21 00 00 00 00
002B916890: 4E 45 52 35 00 00 00 00 │ 2B 91 68 00

Блоки, выделенные красным цветом, имеют следующие текстовые значения: CUEX, DAOX, SINF, MTYP, END!, NER5. По структуре очень напоминает IFF — Interchange File Format (например, подобный подход используется в PNG-файлах). Считая, что CUEX, DAOX и пр. — это имена блоков (chunk), то логично предположить, что следом за именем идет длина блока, а за длиной — сам блок. Еще одно совпадение выделено зелёным цветом: адрес самого первого блока. Однако порядок байт в адресе не Intel'овский (little endian), а Mototrolla'овский (big endian). Логично предположить, что смещение будет 8-байтным (иначе не будет работать для образов больше 4 ГиБ). Таким образом, чтобы узнать смещение первого блока, нужно прочитать последние 8 байт образа (на забывая, что они в формате big endian). Для подстраховки: перед смещением идет сигнатура NER5, перед которой находится блок END! (END! и четыре нуля).

В результате получили простой алгоритм: читаем последние 8 байт, узнаём смещение первого блока. Это смещение будет длиной ISO-образа с "заголовком" Nero в 300 КиБ. Вычитаем из смещения 307200 (те самые 300 КиБ), получаем размер ISO-образа. Далее читаем это количество байт с позиции 307200 исходного файла и записываем в ISO-файл. Всё просто! :-)

Упрощённая версия кода на языке C будет выглядеть следующим образом (в целях упрощения кода я убрал все проверки на ошибки):

[-]
View Code C
    fseek(in, -sizeof(id), SEEK_END);

    read = fread(&id, 1, sizeof(id), in);
    if (0x3552454Eul == id[0]) {    /* Nero v2 footer */
        id[1] = ((id[1] & 0x000000FF) << 24) |
                ((id[1] & 0x0000FF00) << 8) |
                ((id[1] & 0x00FF0000) >> 8) |
                ((id[1] & 0xFF000000) >> 24);

        id[2] = ((id[2] & 0x000000FF) << 24) |
                ((id[2] & 0x0000FF00) << 8) |
                ((id[2] & 0x00FF0000) >> 8) |
                ((id[2] & 0xFF000000) >> 24);

        bytes_to_copy = id[2] | ((uint64_t)(id[1]) << 32);
    }
    else if (0x4F52454E == id[1]) { /* Nero v1 footer */
        bytes_to_copy = id[2];
        bytes_to_copy = ((bytes_to_copy & 0x000000FF) << 24) |
                        ((bytes_to_copy & 0x0000FF00) << 8) |
                        ((bytes_to_copy & 0x00FF0000) >> 8) |
                        ((bytes_to_copy & 0xFF000000) >> 24);
    }

    bytes_to_copy -= 512*600;
    fseek(in, 512*600, SEEK_SET);

    while (bytes_to_copy > 0) {
        to_read = (bytes_to_copy < READ_BUFFER_SIZE) ? bytes_to_copy : READ_BUFFER_SIZE;
        read    = fread(buf, 1, to_read, in);
        if (0 == read) {
            break;
        }

        written = fwrite(buf, 1, read, out);
        if (written != read) {
            break;
        }

        bytes_to_copy -= read;
    }

Примечание: в код добавлена поддержка старых образов Nero.

Полный исходный код nrg2iso можно скачать отсюда, скомпилированный EXE-файл для Windows (7680 байт) лежит здесь. Файл зависит только от KERNEL32.DLL и msvcrt.dll (они есть в каждой версии Windows).

MD5 от nrg2iso.exe — 6cba4b141839031d91af14cac261650a.

PS — исходник написан на ANSI C и, как следствие, должен компилироваться всеми компиляторами, поддерживающими стандарт ANSI C.

Чтобы скомпилировать файл в gcc, достаточно команды

[-]
View Code Bash
gcc nrg2iso.c -ansi -O3 -o nrg2iso
Добавить в закладки
  • del.ici.ous
  • Digg
  • Furl
  • Google
  • Simpy
  • Spurl
  • Y! MyWeb
  • БобрДобр
  • Мистер Вонг
  • Yandex.Закладки
  • Текст 2.0
  • News2
  • AddScoop
  • RuSpace
  • RUmarkz
  • Memori
  • Google Bookmarks
  • Писали
  • СМИ 2
  • Моё Место
  • 100 Закладок
  • Ваау!
  • Technorati
  • RuCity
  • LinkStore
  • NewsLand
  • Lopas
  • Закладки - IN.UA
  • Connotea
  • Bibsonomy
  • Trucking Bookmarks
  • Communizm
  • UCA
  • Slashdot
  • Magnolia
  • Blogmarks
  • Current
  • Meneame
  • Oknotizie
  • Diigo
  • Funp
  • Hugg
  • Dealspl.us
  • N4G
  • Mister Wong
  • Faves
  • Yigg
  • Fresqui
  • Care2
  • Kirtsy
  • Sphinn

Связанные записи

28
Март
2008

Комментарии к статье «Преобразование образов NRG в ISO»  »

К статье «Преобразование образов NRG в ISO» комментариев пока нет. Не хотите ли стать первым?

Подписаться на RSS-ленту комментариев к статье «Преобразование образов NRG в ISO» Trackback URL: http://blog.sjinks.org.ua/c-cpp/57-how-to-convert-nrg-to-iso/trackback/

Оставить комментарий к записи «Преобразование образов NRG в ISO»

Вы можете использовать данные тэги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Оставляя комментарий, Вы выражаете своё согласие с Правилами комментирования.

Подписаться, не комментируя