Иллюстрированный самоучитель по SVGA

Воспроизведение сжатых рисунков

Подпрограмма распаковки строки

Предположим, что в оперативной памяти задача зарезервировала пространство для размещения буфера общего назначения достаточно большого размера. Сегмент, в котором расположен буфер, хранится в переменной GenSeg, а начало свободного пространства в этом сегменте – в переменной GenOffs. Эти переменные должны располагаться в разделе данных программы в следующем порядке.

GenOffs dw 0; адрес (смещение) в буфере общего назначения

GenSeg dw 0; сегмент, содержащий буфер общего назначения

Способы резервирования пространства в оперативной памяти описаны в приложении Б данной книги.

Текст подпрограммы распаковки строки приведен в примере 3.24.

Пример 3.24. Распаковка строки рисунка (способ RLE для PCX).

Unpack: PushReg <ax,cx,dx,di,es>; сохранение содержимого регистров
les di, Dword ptr GenOffs; смещение и сегмент буфера
mov dx, fwidth; логический размер строки
Unploop: call nxt sym; читаем в al следующий символ
mov ex, 01; количество повторяемых символов
cmp al, OCOh; символ содержит счетчик повторов?
jbe Unl; › нет, это одиночный символ
mov cl, al; копируем содержимое al в cl
and cl, 3Fh; и выделяем количество повторов
call nxt sym; читаем в al – повторяемый символ
Unl: sub dx, ex; уменьшаем остаток строки
rep stosb; записываем символы в буфер строки
or dx, dx; строка распакована полностью?
jnz Unploop; нет, продолжение распаковки
PopReg <es, di, dx, ex, ax>; восстанавливаем регистры
ret; › возврат из подпрограммы

В примере 3.24 перед началом распаковки в стеке сохраняется содержимое используемых регистров. Затем команда les загружает в регистры es:di адрес для записи распакованной строки. Размер строки в байтах помещается в регистр dx, используемый в качестве счетчика распакованных символов. После этого выполняется цикл Unploop.

Действия при распаковке соответствуют описанному выше алгоритму. Очередной байт считывается в регистр al, а в счетчик повторов сх записывается 1. Если код символа меньше чем сон, то происходит переход на метку ип_1. В противном случае в cl помещается содержимое 6-ти младших разрядов регистра al и читается повторяемый символ.

Команда, имеющая метку un_i, вычитает из счетчика распакованных символов содержимое регистра сх. Следующая команда записывает в буфер строки содержимое регистра al столько раз, сколько указано в регистре сх. После этого проверяется содержимое регистра dx и если оно отлично от нуля, то цикл распаковки продолжается. В противном случае восстанавливается содержимое сохраненных в стеке регистров и выполняется команда возврата.

Подпрограмма Nxtjsym

Для получения кода очередного байта в примере 3.24 вызывается подпрограмма Nxtjsym, текст которой приведен в примере 3.25.

Пример 3.25. Чтение очередного символа из буфера обмена.

Nxt sym: cmp si, incount в буфере есть символы?
jb @F › да, можно читать очередной символ
push ex сохраняем содержимое сх
mov ex, – I указываем размер порции данных
call Readf читаем данные из файла
mov incount, ax сохраняем размер порции данных
xor si, si очищаем указатель адреса
pop ex восстанавливаем содержимое сх
@@: lods byte ptr fs: [si] чтение очередного байта
ret; возврат из подпрограммы

Подпрограмма примера 3.25 сравнивает текущее значение указателя адреса буфера обмена (содержимое регистра si) с переменной incount, значение которой соответствует размеру считанной из файла порции данных, т. е. количеству байтов, находящихся в буфере обмена.

Если в буфере достаточно данных, то происходит переход на локальную метку @@. Для чтения кода символа в регистр al, увеличения указателя адреса на 1 и выхода из подпрограммы.

Если достигнута граница данных, хранящихся в буфере обмена, то надо прочитать новую порцию данных. Для этого сохраняется содержимое регистра сх, в него записывается предельное количество байтов для чтения (-1 имеет код OFFFFh) и происходит обращение к подпрограмме Readf, описанной в примере 3.23.

После чтения в переменную incount записывается количество прочитанных байтов, очищается регистр si и восстанавливается из стека содержимое регистра сх. Теперь можно прочитать очередной символ, увеличить значение сх на единицу и выйти из подпрограммы.

В примере 3.25 отсутствует проверка состояния С-разряда регистра признаков после чтения. Вы можете включить ее в текст примера 3.25., но целесообразнее контролировать правильность чтения непосредственно в подпрограмме Readf. Это упростит структуру всех подпрограмм, которые обращаются к Readf.

Замечание
В литературе встречаются сведения о существовании файлов, частично не соответствующих стандарту фирмы ZSoft – при их сжатии цикл упаковки не прекращается в конце строки. Для распаковки подобных файлов подпрограмму примера 3.24 надо изменить так, чтобы она выдавала заданное количество распакованных кодов независимо от размера строки
.

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.