Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Работа с длинными именами файлов под ГОЛЫМ ДОСОМ

(c) Mikhail Krivyy
13 марта 1998 года

В этом модуле реализованы функции FindFirst и FindNext, но не простые, а работающие с длинными именами файлов под ГОЛЫМ ДОСОМ. Формат длинных имен, насколько я помню, узнавался методом высоконаучного тыка, так что никаких гарантий.

Писал очень давно, и сейчас даже откомпилировать не смог, так как не нашел модуля uni2dos. Зато вспомнил, что он делает :) Он перекодирует строку из Unicode в DOS кодировку. Таблица Unicodе для русских символов приведена тут.

Код:
uses uni2dos;

type TStr3=Array[1..3] of Char;
     TStr8=Array[1..8] of Char;
     TStr10=Array[1..10] of Char;

type TSector0 = Record
       Jump             : Array[1..3] of Char;  
                          { NEAR-переход на код загрузки }
       OEMName          : Array[1..8] of Char;
                          { OEM-имя компании и версия системы }
       SectSize         : Word;
                          { байт на сектор }
       ClustSize        : Byte;
                          { секторов на единицу распределения (кластер) }
       ResSecs          : Word;
                          { резервных секторов (секторов перед первой FAT) }
       FatCnt           : Byte;
                          { число таблиц FAT }
       RootSiz          : Word;
                          { макс.число 32-байтовых элементов корневого оглавления }
       TotSecs          : Word;
                          { общее число секторов на носителе (раздел DOS) }
       Media            : Byte;
                          { дескриптор носителя (то же, что 1-й байт FAT) }
       FatSize          : Word;
                          { число секторов в одной FAT }
       TrkSecs          : Word;
                          { секторов на дорожку (цилиндр) }
       HeadCnt          : Word;
                          { число головок чтения/записи (поверхностей) }
       HidnSec          : Word;
                          { спрятанных секторов (исп. в схемах разделения) }
       Ostatok          : Array[1..486] of Char;
                          { Остаток, что-бы сюда можно было читать сектор }
     End;

type TFile = Record
       Name             : TStr8;   { Имя файла }
       Ext              : TStr3;   { Расширение }
       Attr             : Byte;    { Атрибут файла }
       Reserv           : TStr10;  { Резерв }
       Time             : Word;    
                          { время создания/модификации в формате filetime }
       Date             : Word;    
                          { дата создания/модификации в формате filetime }
       ClstrNo          : Word;    
                          { номер начального кластера данных (связь с FAT ) }
       Size             : LongInt; { размер файла в байтах }
     End;

type TLongSearchRec = Record
       Name             : TStr8;   { Имя файла }
       LongName         : String;  { Длиное имя файла }
       Ext              : TStr3;   { Расширение }
       Attr             : Byte;    { Атрибут файла }
       Reserv           : TStr10;  { Резерв }
       Time             : Word;    
                          { время создания/модификации в формате filetime }
       Date             : Word;    
                          { дата создания/модификации в формате filetime }
       ClstrNo          : Word;    
                          { номер начального кластера данных (связь с FAT ) }
       Size             : LongInt; { размер файла в байтах }
       FPosInSec        : Integer; { Позиция - в секторе }
       FSecPos          : Integer; { Позиция - сектор }
       FMask            : String;  { Маска для поиска }
       FAttr            : Byte;    { Путь заданный в FindFirst }
     End;

type TDTA = Record
       Reserved         : Array[1..$15] of Byte;
                          { Зарезервированно для FindNext }
       Attr             : Byte;                  
                          { Атрибут файла }
       Time             : Word;                  
                          { время создания/модификации в формате filetime }
       Date             : Word;                  
                          { дата создания/модификации в формате filetime }
       Size             : LongInt;              
                          { размер файла в байтах }
       Name             : Array[1..13] of Char;  
                          { Имя файла + . +расширение }
     End;

type TDir=Array[0..15] of TFile;

var s0           : TSector0;
    dir          : TDir;
    Root         : Word;
    I            : Word;
    Search       : TLongSearchRec;
    LongDosError : Integer;
    SecPerCat    : Integer;
    DTA          : TDTA;        { Текущая DTA }

Function ReadSector(A:Pointer;Disk:Byte;Count:Word;Sector:Word):Boolean;
var Error     :Word;
    Offs      :Word;
Begin
 Offs:=Word(A);
 Error:=0;
  asm
         mov  al,[Disk]         {Номер диска 0-A}
         mov  cx,[Count]        {Счетчик считываемых символов}
         mov  dx,[Sector]       {Начальный сектор}

         mov  bx,[Offs]
         int  25h
         pop  dx
         je   @nError
         mov  ax,1
         mov  [Error],ax
@nError:
  end;
 if Error=0 then ReadSector:=True
            else ReadSector:=False;
End;

{ Получаем длиное имя файла #################################################}
function GetUniLFN(I:Word):String;
var Str,Str0,Str1:String;
    Flag:Boolean;
    Len:Integer;
Begin
 Flag:=true;Str0:=#255+#255;Str:='';Str1:='';
 While flag do
  Begin
      Str1:=copy(Dir[I-1].Name,2,7)+Dir[I-1].Ext+
                 copy(Dir[I-1].Reserv,3,8)+char(Dir[I-1].Time)+
            char(Dir[I-1].Time shr 8)+char(Dir[I-1].Date)+
                 char(Dir[I-1].Date shr 8)+char(Dir[I-1].Size)+
            char(Dir[I-1].Size shr 8)+char(Dir[I-1].Size shr 16)+
                 char(Dir[I-1].Size shr 24);
   Len:=pos(Str0,Str1);
   If Len<>0 then Begin Flag:=False; Str:=Str+copy(Str1,1,Len); End
             else Begin
                    dec(i);
                    Str:=Str+Str1;
                    if Dir[I].Attr<>15 then Flag:=False;
                  End;
  End;
 GetUniLFN:=Str;
End;

{ Long Find First ###########################################################}
Procedure LongFindFirst(Path:String;Attr:Word;var SR:TLongSearchRec);
var I,Sec                  :Integer;
    Drive                  :Word;        { Номер диска }
    NameSeg,NameOfs        :Word;        { Адрес строки для поиска }
    ParentDir              :String;      { Родительский каталог }
    Sector,InSect,Data     :LongInt;    
                           { Сектор, и позиция каталоговой записи }
    DTASeg,DTASize,DTAOfs  :Word;        { Адрес локальгого DTA }
Begin
 LongDOSError:=0;
 {Drive:=Path[1];} Drive:=0;         { Получаем имя диска }
 ParentDir:=copy(Path,4,Length(Path)-1);   { Выделим родительский каталог }
 If not ReadSector(@s0,Drive,1,0) then Exit;
 If Pos('\',ParentDir)=0 then
  Begin { Если ищем в корне #################################################}
   Path:=Path+#0;
   NameSeg:=Seg(Path);NameOfs:=Ofs(Path)+1;
   DTAOfs:=Ofs(DTA);DTASeg:=Seg(DTA);DTASize:=Sizeof(DTA);
   asm                                 { FindFirst - заполняем }
         push ds

         mov ax,[NameSeg]
         mov ds,ax
         mov dx,[NameOfs]
         mov ah,$4E                   { Функция DOS - найти первый файл }
         mov cx,Attr                  { Аттрибуты файла }
         int 21h
         jnc @FilesF
         mov ax,$FF
         mov [LongDOSError],ax
         jmp @AsmEnd
@FilesF: mov ah,$2f                   { Получим адрес текущей DTA }
         int 21h
         mov ax,es                    { И скопируем ее в нашу локальную DTA }
         mov ds,ax
         mov si,bx
         mov di,[DTAOfs]
         mov es,[DTASeg]
         mov cx,[DTASize]
         cld
         rep movsb

@AsmEnd: pop ds
   end; { В DTA.Reserved[14] можно узнать номер найденой записи в каталоге}
   If LongDOSError<>0 then Exit;
   Sector:=trunc((DTA.Reserved[14]+256*DTA.Reserved[15])/(s0.SectSize shr 5));
   { Номер сектора,где находится каталог с именем }
   InSect:=(DTA.Reserved[14]+256*DTA.Reserved[15])-Sector*(s0.SectSize shr 5);
   { Номер записи в секторе }
   Root:=s0.ResSecs+s0.FatSize*s0.FatCnt; { Вычисляем номер сектора с корнем }
   If not ReadSector(@dir,0,1,Root+Sector) then Exit; { Читаем сектор }
   SR.Name:=dir[InSect].Name; { Заполнаяем TLongSearchRec }
   SR.Ext:=dir[InSect].Ext;
   SR.Attr:=dir[InSect].Attr;
   SR.Reserv:=dir[InSect].Reserv;
   SR.Time:=dir[InSect].Time;
   SR.Date:=dir[InSect].Date;
   SR.ClstrNo:=dir[InSect].ClstrNo;
   SR.Size:=dir[InSect].Size;
   { Теперь смотрим длиное имя }
   If (InSect>0) and (dir[InSect-1].attr=15) then
           SR.LongName:=UniToDos(GetUniLFN(InSect))
      else SR.LongName:=dir[InSect].Name+'.'+dir[InSect].Ext;
  End
 else
  Begin { Если ищем не в корне ##############################################}
   Path:=Path+#0;
   NameSeg:=Seg(Path);NameOfs:=Ofs(Path)+1;
   DTAOfs:=Ofs(DTA);DTASeg:=Seg(DTA);DTASize:=Sizeof(DTA);
   asm                                 { FindFirst - заполняем }
         push ds

         mov ax,[NameSeg]
         mov ds,ax
         mov dx,[NameOfs]
         mov ah,$4E                   { Функция DOS - найти первый файл }
         mov cx,Attr                  { Аттрибуты файла }
         int 21h
         jnc @FilesF
         mov ax,$FF
         mov [LongDOSError],ax
         jmp @AsmEnd
@FilesF: mov ah,$2f                   { Получим адрес текущей DTA }
         int 21h
         mov ax,es                    { И скопируем ее в нашу локальную DTA }
         mov ds,ax
         mov si,bx
         mov di,[DTAOfs]
         mov es,[DTASeg]
         mov cx,[DTASize]
         cld
         rep movsb

@AsmEnd: pop ds
   end; { В DTA.Reserved[14] можно узнать номер найденой записи в каталоге}
   If LongDOSError<>0 then Exit;
   Sector:=trunc((DTA.Reserved[14]+256*DTA.Reserved[15])/(s0.SectSize shr 5));
   InSect:=(DTA.Reserved[14]+256*DTA.Reserved[15])-Sector*(s0.SectSize shr 5);
   { Номер записи в секторе }
   Sector:=Sector+DTA.Reserved[16]+256*DTA.Reserved[17]-3;
   { Номер сектора,где находится каталог с именем }
   Root:=s0.ResSecs+s0.FatSize*s0.FatCnt; { Вычисляем номер сектора с корнем }
   Data:=Root+(s0.RootSiz*32) div s0.SectSize;
   If not ReadSector(@dir,0,1,Data+Sector) then Exit; { Читаем сектор }
   SR.Name:=dir[InSect].Name; { Заполнаяем TLongSearchRec }
   SR.Ext:=dir[InSect].Ext;
   SR.Attr:=dir[InSect].Attr;
   SR.Reserv:=dir[InSect].Reserv;
   SR.Time:=dir[InSect].Time;
   SR.Date:=dir[InSect].Date;
   SR.ClstrNo:=dir[InSect].ClstrNo;
   SR.Size:=dir[InSect].Size;
   { Теперь смотрим длиное имя }
   If (InSect>0) and (dir[InSect-1].attr=15) then
          SR.LongName:=UniToDos(GetUniLFN(InSect))
     else SR.LongName:=dir[InSect].Name+'.'+dir[InSect].Ext;
  End;
End;

{ Long Find Next ############################################################}
Procedure LongFindNext(var SR:TLongSearchRec);
var
    Drive                  :Word;        { Номер диска }
    Sector,InSect,Data     :LongInt;     { Сектор, и позиция каталоговой записи }
    DTASeg,DTASize,DTAOfs  :Word;        { Адрес локальгого DTA }
Begin
 Drive:=0;
 LongDOSError:=0;
 DTAOfs:=Ofs(DTA);DTASeg:=Seg(DTA);DTASize:=Sizeof(DTA);
 asm                                  { FindFirst - заполняем }
         push ds

         mov ah,$2f                   { Получим адрес текущей DTA }
         int 21h
         mov dx,bx
         mov ah,$4F                   { Функция DOS - найти первый файл }
         int 21h
         jnc @FilesF
         mov ax,$FF
         mov [LongDOSError],ax
         jmp @AsmEnd
@FilesF: mov ah,$2f                   { Получим адрес текущей DTA }
         int 21h
         mov ax,es                    { И скопируем ее в нашу локальную DTA }
         mov ds,ax
         mov si,bx
         mov di,[DTAOfs]
         mov es,[DTASeg]
         mov cx,[DTASize]
         cld
         rep movsb

@AsmEnd: pop ds
 end; { В DTA.Reserved[14] можно узнать номер найденой записи в каталоге}
 If LongDOSError<>0 then Exit;
 Sector:=trunc((DTA.Reserved[14]+256*DTA.Reserved[15])/(s0.SectSize shr 5));
 InSect:=(DTA.Reserved[14]+256*DTA.Reserved[15])-Sector*(s0.SectSize shr 5);
 { Номер записи в секторе }
 Sector:=Sector+DTA.Reserved[16]+256*DTA.Reserved[17]-3;
 { Номер сектора,где находится каталог с именем }
 Root:=s0.ResSecs+s0.FatSize*s0.FatCnt; { Вычисляем номер сектора с корнем }
 Data:=Root+(s0.RootSiz*32) div s0.SectSize;
 If not ReadSector(@dir,0,1,Data) then Exit; { Читаем сектор }
 SR.Name:=dir[InSect].Name; { Заполнаяем TLongSearchRec }
 SR.Ext:=dir[InSect].Ext;
 SR.Attr:=dir[InSect].Attr;
 SR.Reserv:=dir[InSect].Reserv;
 SR.Time:=dir[InSect].Time;
 SR.Date:=dir[InSect].Date;
 SR.ClstrNo:=dir[InSect].ClstrNo;
 SR.Size:=dir[InSect].Size;
 { Теперь смотрим длиное имя }
 If (InSect>0) and (dir[InSect-1].attr=15) then
          SR.LongName:=UniToDos(GetUniLFN(InSect))
     else SR.LongName:=dir[InSect].Name+'.'+dir[InSect].Ext;
End;

Begin
 WriteLn;
 InitUni;
 LongFindFirst('A:\1\*.*',$FFFF,Search);
 While LongDosError=0 do
  Begin
   WriteLn(Search.Name+' '+Search.Ext+' ',Search.Size:8,' ',
           Search.FPosInSec:8,' ',Search.FSecPos:8,' ',Search.LongName);
   LongFindNext(Search);
   Search.LongName:=copy(Search.LongName,1,30);
  End;
End.

Оставить комментарий

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог