© Иван Рощин, Москва
| ZXNet | : 500:95/462.53 |
| : bestview@mtu-net.ru | |
| WWW | : http://www.ivr.da.ru |
В [1] рассказывалось о проблеме, связанной с использованием текстового редактора Microsoft Word. Напомню: речь шла о том, что в определённых случаях в сохранённом текстовом файле остаются фрагменты текста, удалённые при редактировании, причём автор текста может об этом и не подозревать. А получатель, прочитавший этот файл, может узнать информацию, которая для него вовсе не предназначалась.
Подобная проблема актуальна и для многих текстовых редакторов на ZX
Spectrum, хотя причина её возникновения и не такая, как в MS Word. Дело вот в
чём: для хранения на диске файла, независимо от его длины, выделяется целое
число секторов. Таким образом, остаток последнего сектора
(«хвост») файла может содержать информацию, к этому файлу не
относящуюся. Когда мы сохраняем текст в редакторе, на диск просто записывается
целое число секторов с начала текстового буфера. И если длина текста не кратна
256 байтам, в остатке последнего сектора будет то, что находилось в текстовом
буфере после фактического конца текста. Загрузив файл в текстовый редактор, мы
эту информацию не увидим (потому что в каталоге указывается точная длина
файла), но при просмотре содержимого последнего сектора с помощью
А что находится в буфере после конца текста? Это может быть и остаток предыдущего загруженного в редактор файла (ведь перед загрузкой нового файла буфер не обнуляется зачем выполнять лишнюю работу?), и фрагменты текста, удалённые при редактировании. А если буфер не очищается при запуске редактора, там может остаться то, что было помещено туда при работе предыдущей программы. Даже если этой программой был обычный «boot», в памяти может остаться каталог диска, с которого был запущен редактор. Понятно, что делать эту информацию общедоступной не хотелось бы.
Однако при операциях копирования файла, пересылки его в форматах hobeta, scl, (и, разумеется, в файлах образах диска: trd, fdi, td0), а также при упаковке файлов с помощью архиватора HRIP остаток последнего сектора также участвует в операции. Таким образом, нежелательная информация может быть распространена вместе с самим файлом, и доступ к ней может получить множество людей.
Если бы область памяти после конца текста обнулялась перед записью файла, проблема была бы полностью решена. Именно это я и посоветую создателям редакторов. А что делать простым пользователям?
Выход есть воспользоваться специальной программой, обнуляющей «хвост» указанного файла. Вот её текст:
SECTOR EQU #C000 ;#100 байтов
CATALOG EQU #C100 ;#800 байтов
FILE_LIST EQU #C900 ;#800 байтов
ORG #8000
;Инициализация:
LD A,(23611) ;системные
OR %00001100 ;переменные
LD (23611),A ;обработчика
XOR A ;клавиатуры
LD (23658),A
LD A,(23562)
PUSH AF
LD A,1
LD (23562),A
BEGIN XOR A ;CLS
OUT (254),A
LD HL,#4000
LD (HL),L
LD DE,#4001
LD BC,#17FF
LDIR
LD HL,#5800
LD (HL),7
LD DE,#5801
LD BC,#2FF
LDIR
;Читаем каталог и определяем его
;контрольную сумму:
CALL READ_CAT
;Формируем список файлов:
CALL MAKE_LIST
;Выбор файла:
SELECT LD A,(ALL_FILES)
AND A ;если нет
JR Z,SELECT_NF ;файлов...
XOR A
LD (FIRST),A
LD (NUM_F),A
CALL PRINT_LIST
SELECT_1 CALL CURSOR_ON
WAIT_K CALL GETSYM
CP "q"
JR Z,SEL_UP
CP 11
JR Z,SEL_UP
CP "a"
JR Z,SEL_DN
CP 10
JR Z,SEL_DN
CP 13
JR Z,WORK_FILE
CP 7
JP Z,EXIT
CP "r"
JR Z,BEGIN
JR WAIT_K
;"Вверх":
SEL_UP LD A,(NUM_F)
AND A
JR Z,WAIT_K
CALL CURSOR_OFF
LD HL,NUM_F
DEC (HL)
LD A,(FIRST)
SUB (HL)
JR C,SELECT_1
JR Z,SELECT_1
LD HL,FIRST
DEC (HL)
CALL PRINT_LIST
JR SELECT_1
;"Вниз":
SEL_DN LD A,(NUM_F)
INC A
LD HL,ALL_FILES
CP (HL)
JR Z,WAIT_K
CALL CURSOR_OFF
LD HL,NUM_F
INC (HL)
LD A,(FIRST)
ADD A,17
SUB (HL)
JR NC,SELECT_1
LD HL,FIRST
INC (HL)
CALL PRINT_LIST
JR SELECT_1
;Если на диске нет файлов, ждем нажатия
;"R" или "EDIT":
SELECT_NF CALL GETSYM
CP 7
JP Z,EXIT
CP "r"
JP Z,BEGIN
JR SELECT_NF
;Обработка файла.
WORK_FILE LD A,(NUM_F)
LD H,0
LD L,A
ADD HL,HL
ADD HL,HL
ADD HL,HL
ADD HL,HL ;*16
LD DE,FILE_LIST
ADD HL,DE
PUSH HL
POP IX
;Проверка, можно ли обрабатывать файл:
LD A,(IX+8) ;это Бейсик?
CP "B"
JP Z,WAIT_K
LD A,(IX+11) ;младший байт
AND A ;длины = 0?
LD (USED),A
JP Z,WAIT_K
LD A,(IX+12) ;длина в сект.
INC A ;соответствует
CP (IX+13) ;длине
JP NZ,WAIT_K ;в байтах?
;Определяем трек-секторный адрес
;последнего сектора файла:
LD D,0
DEC A
LD B,A
AND 15
ADD A,(IX+14)
BIT 4,A
RES 4,A
LD E,A ;сектор
JR Z,WORK_1
INC D
WORK_1 LD A,B
RRCA
RRCA
RRCA
RRCA
AND 15
ADD A,(IX+15)
ADD A,D
LD D,A ;трек
LD (DISK_ADR),DE
;Проверяем по контрольной сумме
;каталога: вдруг в дисководе уже другой
;диск? Если так, перечитываем каталог.
LD HL,(SUM)
PUSH HL
CALL READ_CAT
LD HL,(SUM)
POP DE
AND A
SBC HL,DE
JP NZ,BEGIN
;Обнуляем неиспользуемое пространство
;в последнем секторе файла:
LD DE,0
DISK_ADR EQU $-2
LD HL,SECTOR
LD B,1
LD C,5
PUSH DE
PUSH HL
CALL #3D13
LD H,SECTOR/256
LD L,0
USED EQU $-1
WORK_2 LD (HL),0
INC L
JR NZ,WORK_2
POP HL
POP DE
LD B,1
LD C,6
CALL #3D13
;После обработки - снова на выбор файла:
JP WAIT_K
;Выход из программы:
EXIT LD HL,#2758
EXX
POP AF ;восст. период
LD (23562),A ;автоповтора
RET
;---------------------------------------
;Переменные:
SUM DS 2 ;контрольная сумма
ALL_FILES DS 1 ;кол-во файлов
FIRST DS 1 ;N верхнего файла
NUM_F DS 1 ;N выбранного файла
;---------------------------------------
;Процедура READ_CAT читает каталог диска
;и вычисляет его контрольную сумму.
READ_CAT LD C,0 ;сброс
CALL #3D13 ;контроллера
LD C,#18 ;настройка
CALL #3D13 ;на диск
LD B,8 ;чтение
LD DE,0 ;восьми
LD HL,CATALOG ;секторов
LD C,5 ;каталога
CALL #3D13
;Вычисление контрольной суммы:
LD IX,CATALOG ;адр. начала
LD BC,#800 ;счетчик
LD HL,0 ;нач. сумма
LD D,0
CALC_SUM LD E,(IX) ;прибавляем
ADD HL,DE ;очередной байт
INC IX
DEC BC
LD A,B
OR C
JR NZ,CALC_SUM
LD (SUM),HL
RET
;---------------------------------------
;Процедура MAKE_LIST формирует список
;файлов и подсчитывает их количество.
MAKE_LIST LD HL,CATALOG
LD DE,FILE_LIST
LD IX,#8000
;XH - счетчик элементов каталога (128),
;XL - счетчик файлов.
MAKE_M1 LD A,(HL) ;файлы
AND A ;закончились?
JR Z,MAKE_M4
DEC A ;удаленный
JR Z,MAKE_M2 ;файл?
LD BC,16 ;переносим
LDIR ;описатель
INC XL ;увел. кол-во
JR MAKE_M3
MAKE_M2 LD BC,16
ADD HL,BC
MAKE_M3 DEC XH ;счетчик
JR NZ,MAKE_M1
MAKE_M4 LD A,XL
LD (ALL_FILES),A
RET
;---------------------------------------
;Процедуры для изображения курсора:
;CURSOR_ON - нарисовать,
;CURSOR_OFF - стереть.
CURSOR_ON LD B,%00111000
JR CURSOR_1
CURSOR_OFF LD B,%00000111
CURSOR_1 LD A,(NUM_F)
LD HL,FIRST
SUB (HL)
ADD A,4
LD E,A
LD D,1
CALL GET_A_A
LD (HL),B
LD D,H
LD E,L
INC DE
LD BC,11
LDIR
RET
;---------------------------------------
;Процедура PRINT_LIST выводит на экран
;имена файлов, начиная с FIRST, пока не
;будет выведено 18 имен или пока не
;кончатся файлы.
PRINT_LIST LD XH,0 ;счетчик
LD DE,FILE_LIST
LD H,0
LD A,(FIRST)
LD L,A
ADD HL,HL
ADD HL,HL
ADD HL,HL
ADD HL,HL ;*16
ADD HL,DE
;HL указывает на имя файла.
NEXT_OT LD B,8
LD D,2
LD A,XH
ADD A,4
LD E,A
PUSH HL
LOOP_P2 LD A,(HL)
INC HL
CALL PRINT_SYM
INC D
DJNZ LOOP_P2
LD A,(HL)
INC D
CALL PRINT_SYM
POP HL
LD A,(FIRST)
ADD A,XH
LD B,A
LD A,(ALL_FILES)
DEC A
CP B
RET Z
INC XH
LD A,XH
CP 18
RET Z
LD DE,16
ADD HL,DE
JR NEXT_OT
;---------------------------------------
;Процедура PRINT_SYM печатает на экране
;один символ (без атрибутов).
;
;Вход: A - код символа,
; D - координата X,
; E - координата Y.
;
;Выход: регистры не изменены.
PRINT_SYM PUSH BC
PUSH DE
PUSH HL
PUSH AF
LD L,A
LD H,0
ADD HL,HL
ADD HL,HL
ADD HL,HL ;*8
LD BC,#3C00
ADD HL,BC
PUSH HL
CALL GET_A_S
POP DE
LD B,8
LOOP_PR_S LD A,(DE)
LD (HL),A
INC DE
INC H
DJNZ LOOP_PR_S
POP AF
POP HL
POP DE
POP BC
RET
;---------------------------------------
;Процедура GET_A_S рассчитывает адрес
;на экране.
;
;Вход: D - X, E - Y.
;Выход: HL - адрес.
GET_A_S LD A,E
AND #18
OR #40
LD H,A
LD A,E
AND 7
RRA
RRA
RRA
RRA
ADD A,D
LD L,A
RET
;---------------------------------------
;Процедура GET_A_A рассчитывает адрес
;в области атрибутов.
;
;Вход: D - X, E - Y.
;Выход: HL - адрес.
GET_A_A LD A,E
RRA
RRA
RRA
AND 3
OR #58
LD H,A
LD A,E
AND 7
RRA
RRA
RRA
RRA
ADD A,D
LD L,A
RET
;---------------------------------------
;Процедура GETSYM ждет нажатия клавиши.
GETSYM XOR A
LD (23560),A
GET_1 LD A,(23560)
AND A
JR Z,GET_1
RET
После компиляции сохраните объектный код, например, под именем
«del_tail <C>» и напишите простейший
10 CLEAR 32767: RANDOMIZE USR 15619: REM: LOAD "del_tail"
CODE
20 RANDOMIZE USR 32768
30 RANDOMIZE USR 15616
Скачать программу в формате hobeta (1 КБ ZIP)
Пользоваться программой очень просто. После запуска выводится каталог
диска, выбрать нужный файл можно с помощью клавиш «Q»,
«A» и курсорных; «Enter» начать обработку
файла, «R» перечитать каталог,
«Edit» выйти в
Перед тем, как начать обработку выбранного файла, программа проверяет: не был ли заменён диск с момента чтения каталога? Если да, то просто перечитывается каталог.
Есть и ещё одна проверка: в случае, если выбран
Программу можно использовать не только для обработки текстовых файлов. Но
хочу предупредить, чтобы вы были уверены в формате обрабатываемых файлов:
бывает, что «хвост» файла содержит
Программу можно усовершенствовать: добавить выбор дисковода, возможность обработки сразу нескольких помеченных файлов, обнуление неиспользуемых секторов диска и информации о стёртых файлах в каталоге диска
|
Другие мои статьи о
|