Teledisk: различия между версиями
| Panther (обсуждение | вклад) | Panther (обсуждение | вклад)  мНет описания правки | ||
| Строка 99: | Строка 99: | ||
|   Данные блока |   Данные блока | ||
| Если <tt>Тип блока=0</tt>, то «данные блока» представляют собой содержание сектора в неупакованном формате, при этом «длина блока» должна совпадать с размером сектора. | Если <tt>Тип блока=0</tt>, то «данные блока» представляют собой содержание сектора в неупакованном формате, при этом «длина блока» должна совпадать с размером сектора плюс один байт для поля "Тип блока". | ||
| Если <tt>Тип блока=1</tt>, то «данные блока» представляют собой следующую запись: | Если <tt>Тип блока=1</tt>, то «данные блока» представляют собой следующую запись: | ||
Версия от 01:14, 30 января 2010
|   | Этот документ создан для Emuverse и распространяется на условиях лицензии CC-BY-SA-3.0. | 
Teledisk — формат файлов, содержащий посекторную копию дискеты. Создавался с помощью одноименной утилиты. Внутри файла находятся данные, упакованные по принципу RLE (RLE+LZSS в режиме «Advanced compression»).
Описание формата
Формат файла следующий:
Заголовок Данные
Формат заголовка:
type 	
    TTDHeader = packed record
      sig:   array [0..1] of Char;   //Сигнатура "TD" или "td"
      vol:   Byte;                   //Номер тома. 0 для TD0
      chk:   Byte;                   //Сигнатура, одинаковая для всех томов
      ver:   Byte;                   //Для версий 2.11-2.16 равно 15H
      dens:  Byte;                   //Плотность записи. Обычно 0.
      typ:   Byte;                   //Тип устройства. 1=360K, 2=1.2M,
                                     //3=720K, 4=1.44M.
      flag:  Byte;                   //Старший бит - наличие комментария
      dos:   Byte;                   //DOS mode? Обычно 00H
      sides: Byte;                   //Кол-во сторон
      crc:   Word;                   //CRC первых 10 байт записи
    end;
Если сигнатура равна «TD», за заголовком следуют данные без упаковки LZSS, иначе они упакованы, и требуется распаковка. Далее распакованные данные обрабатываются аналогично формату без компрессии.
Формат данных (отступы сделаны для удобства):
Комментарий (если TTDHeader.flag > 80H)
 Заголовок дорожки 0
   Заголовок сектора 1
     Данные сектора 1
   Заголовок сектора 2
     Данные сектора 2
   ..........
   Заголовок сектора N
     Данные сектора N
 Заголовок дорожки 1
 ..........
 Заголовок дорожки M
 ..........
Общее количество секторов и дорожек может быть получено только после обработки всего файла, в общем заголовке этих данных нет.
Формат комментария:
Заголовок комментария Данные комментария (текст)
Формат заголовка комментария:
TTDComment = packed record crc: Word; //Контрольная сумма комментария len: Word; //Длина комментария в байтах yr, mon, day, //Дата. Год отсчитывается от 1990. hr, min, sec: Byte; end;
Данные комментария представляют собой строки, оканчивающиеся #0. Строк может быть несколько.
Формат заголовка дорожки:
TTDTrack = packed record
  nsec: Byte;                //Кол-во последующих записей секторов.
                             //Часть записей должна игнорироваться
  trk:  Byte;                //Номер дорожки
  head: Byte;                //Номер стороны
  crc:  Byte;                //Контрольная сумма заголовка
end;
Количество секторов может не совпадать с реальным, так как назначение части записей пока не установлено, они должны игнорироваться.
Заголовок сектора:
TTDSector = packed record trk: Byte; //Номер дорожки; head: Byte; //Номер стороны; sec: Byte; //Номер сектора; secz: Byte; //Код размера сектора; cntrl: Byte; //Тип данных; crc: Byte; //Контрольная сумма распакованных данных end;
TDSector.sec=$65 обозначает, что достигнут конец файла, остаток данных нужно пропустить.
Если TDSector.sec > TDTrack.nsec, последующие данные сектора должны быть проигнорированы.
Вычисление размера сектора в байтах: SectSize := 1 shl (TDSector.secz+7);
Данные относятся к реальному сектору, если выполняется следующее условие: ((TDSector.cntrl and $30) = 0) and ((TDSector.secz and $F8) = 0), иначе данные нужно игнорировать.
Если TDSector.cntrl=$10, то сектор содержит пустые данные (возможно, не был прочитан корректно), нужно переходить к чтению заголовка следующего сектора.
Формат блока данных сектора (если сектор непустой):
Длина блока (2 байта) Тип блока (1 байт) Данные блока
Если Тип блока=0, то «данные блока» представляют собой содержание сектора в неупакованном формате, при этом «длина блока» должна совпадать с размером сектора плюс один байт для поля "Тип блока".
Если Тип блока=1, то «данные блока» представляют собой следующую запись:
TTDRepeat = packed record count: Word; //Количество повторений pat: array [0..1] of Byte; //Данные для повторения (2 байта) end;
«Количество повторений» должно быть в два раза меньше размера сектора.
Если Тип блока=2, то «данные блока» представляют собой последовательность записей:
Заголовок записи Данные записи
Формат заголовка записи:
TTDPattern = packed record flag: Byte; count: Byte; end;
Если TDPattern.flag=0, то за заголовком следуют данные длиной TDPattern.count. Иначе, TDPattern.flag обозначает размер блока для повторения, следующий за заголовком, TDPattern.count — количество повторений. Размер блока в байтах вычисляется как PatSize := 1 shl TDPattern.flag;.
Обобщенный алгоритм
--------- основная процедура ---------
Чтение заголовка файла TDHeader
Если TDHeader.sig == ”td” то распаковка данных
Если TDHeader.sig != ”TD” то выход с ошибкой «неправильный формат»
Если TDHeader.flag & 80H > 0 то
  Чтение заголовка комментария
  Чтение блока данных комментария
Пока не конец данных
  Чтение заголовка дорожки TDTrack
  Если TDTrack.nsec == 0FFH то окончание работы
  
   Для секторов от 1 до TDTrack.nsec
     Чтение заголовка сектора TDSector
     Если TDSector.sec == 65H то окончание работы
     SectSize := 1 shl (TDSector.secz+7);
     Если ((TDSector.cntrl & 30H) == 0) && ((TDSector.secz & 0F8H) == 0) то
       Если TDSector.cntrl == 10H то 
         сектор пустой, переход к следующему
       Иначе
         Чтение 2-х байт «Длина данных»
         Если TDSector.sec <= TDTrack.nsec то
           Распаковка_данных(Длина данных)
         Иначе
           Пропускаем «Длина данных» из входного потока
--------- подпрограмма ---------
Процедура Распаковка_данных(Длина данных)
  Чтение 1 байта «Тип блока»
  Если «Тип блока» == 0 то
     Читаем «Длина данных» в качестве данных сектора
  Иначе
  Если «Тип блока» == 1 то
     Читаем запись TDRepeat
     Помещаем в буфер сектора TDRepeat.count повторений TDRepeat.pat
  Иначе
  Если «Тип блока» == 2 то
     Пока не достигнута «Длина данных»-1
       Читаем запись TDPattern
       Если TDPattern.flag == 0 то
         Читаем TDPattern.count байт и помещаем их в буфер сектора
       Иначе
         PatSize := 1 shl TDPattern.flag;
         Читаем «PatSize» данных из входного потока
         Пишем эти данные TDPattern.count раз в буфер сектора
Источники и ссылки
Программы
 Библиотека для работы с форматом Teledisk (Pascal/Delphi, исходные коды, пример использования) Библиотека для работы с форматом Teledisk (Pascal/Delphi, исходные коды, пример использования)
 Программа Teledisk разных версий (MS-DOS/Win 9x/Me, в NT/XP/Vista не работает) Программа Teledisk разных версий (MS-DOS/Win 9x/Me, в NT/XP/Vista не работает)
 
	