// Name        : Lesson 07 - files / Работа с файлами
// Version     : 19 dec 2012
// Author      : LODka3D
// Discription : Урок 07 Читаем список файлов из папки по маске, грузим файлы
//               в виде текста и в виде шестнадцатеричных чисел.
//

{$INCLUDE 'func-demo1.dws'}
{$INCLUDE 'vectorgeometry.dws'}

procedure LODPCreateControls;
var
  FileNames1 : TLODStr;
begin
    // TLODStr - класс для работы с массивами строк аналогичный классу 
    //  TStrings в Дельфи, но дополненный различными функциями.
    // Поддерживаются функции FileNames1.Add('строка'), .Delete(StrNumber),
    //  .Insert(StrNumber, 'строка'), .Count, .Sort, .Text, .IndexOf('строка'), 
    //  IndexOfName('имя'); .Values['имя'], .Names[StrNumber]
    //  .ValueFromIndex[StrNumber] и другие. Где StrNumber - номер строки.
    // Names и Values работает для строк со знаком '=', то, что до него 
    //  - это Names, а после него - Values. Если в такую строку записывать
    //  или читать значение функциями типа .AsByte[StrNumber], то оно 
    //  пишется и считывается после знака '='.
  FileNames1 := TLODStr.Create; // Создаём класс.
    // Грузим в него список файлов по маске '*.pas', цифра '1', означает поиск 
    //  по подкаталогам. Стартовая папка - папка в которой находится скрипт.
  FileNames1.FindFiles('*.pas', '1');
  if LOD('GetLanguage') = '25' then begin
      // Выводим в окошко список файлов.
    LOD('AddPControl', 'FileInd', 'Combo', '0', 'Файлы', 'Выберите файл.', 
      FileNames1.Text);
      // Эта галочка определяет загружать ли выбранный файл как бинарный или
      //  как текстовый. Если файл загружается как бинарный, то каждый байт 
      //  файла загружается в отдельную строку класса TLODStr в виде 
      //  шестнадцатеричной текстовой строки от '00' до 'FF'.
    LOD('AddPControl', 'Bin', 'Bool',    '3', 'Двоичный', 'Читать двоичный '
      +'файл как последовательность 16-ричных чисел.');
      // С какой строки или с какого байта показывать файл.
    LOD('AddPControl', 'BegPos1', 'Int', '0', 'Начало:', 
      'Первая отображаемая строка в текстовом файле или первый отображаемый'
      +'байт в бинарном.', '0', '32767');
      // Сколько строк или сколько байт файла показывать.
    LOD('AddPControl', 'Cnt1', 'Int', '32', 'Размер', 
      'Число показываемых строк текстового файла или число показываемых '
      +'строк бинарного', '0', '32767');
  end else begin
    LOD('AddPControl', 'FileInd', 'Combo', '0', 'Files', 'Select file', 
      FileNames1.Text);
    LOD('AddPControl', 'Bin', 'Bool',    '3', 'Bin file', 'Read file as Bin.');
    LOD('AddPControl', 'BegPos1', 'Int', '0', 'StartPos', 
      'Start line in text file or start byte in text file.', '0', '32767');
    LOD('AddPControl', 'Cnt1', 'Int', '32', 'Count', 
      'Number of lines to show in text, or number of bytes in bin-file', 
       '0', '32767');
  end;
  FileNames1.Free; // Уничтожаем класс (от утечек памяти).
end;


procedure LODPCreatePrimitive;
var
  FileNames1, F1: TLODStr; // Strings;
  SelFileInd1, i1, i2, j1, BegPos1, Cnt1, End1 : Integer;
  s1, s2, s3,
  sFileName1         : string;
begin
  LOD('SetPMessage', ''); // Очищаем окно.

  FileNames1      := TLODStr.Create;
    // Опять грузим в FileNames1 список файлов.
  FileNames1.FindFiles('*.pas', '1');
    // Читаем какой порядковый номер файла выбрал пользователь в окошке Combo.
  SelFileInd1     := StrToInt(LOD('GetPControl', 'FileInd'));
    // Имя выбранного пользователем файла.
  sFileName1 := FileNames1[SelFileInd1];
    // Читаем из окошек с какой строки или с какого байта показывать файл.
  BegPos1         := StrToInt(LOD('GetPControl', 'BegPos1'));
    // Читаем сколько строк или сколько байт файла показывать.
  Cnt1            := StrToInt(LOD('GetPControl', 'Cnt1'));

    // Читаем какой вид загрузки файла выбрал пользователь как Bin
  if LOD('GetPControl', 'Bin') = '0' then begin
      // Пользователь хочет загрузить файл как текст. Грузим его в F1
      //  как текстовый функцией LoadFromFile .
      // Сохранять файлы можно функциями F1.SaveToFile и F1.SaveToFileBin.
    F1 := TLODStr.Create;
    F1.LoadFromFile(sFileName1);
      // Копируем в s1 первые строки файла начиная с BegPos1 числом Cnt.
    s1 := '';
    for i1 := BegPos1 to Round(Min(F1.Count, BegPos1 +Cnt1)) -1 do
      s1 := s1 +F1[i1] +#13#10;

      // Отображаем имя файла и его содержимое в окне ЛОДки.
    LOD('AddPMessage', 'Filename: ''' +sFileName1 +'''.' +#13#10
      +'  < Start line: ' +IntToStr(BegPos1)
      +' Count: ' +IntToStr(Cnt1) +' >' +#13#10 +s1);
  end else begin
      // Пользователь хочет загрузить файл как бинарный. Грузим его в
      //  F1 как бинарный функцией LoadFromFileBin .
    F1 := TLODStr.Create;
    F1.LoadFromFileBin(sFileName1);
      // Этими функциями можно загружать и сохранять файлы через диалоговые
      //  окна открытия и сохранения файлов.
    // F1.LoadFromFileDlg(   'test01.txt',  'Text files(*.txt)|*.txt|All files(*.*)|*.*');
    // F1.LoadFromFileBinDlg('test01.bin','Binary files(*.bin)|*.bin|All files(*.*)|*.*');
    // F1.SaveToFileBinDlg(  'test01.bin','Binary files(*.bin)|*.bin|All files(*.*)|*.*');
    // F1.SaveToFileDlg(     'test01.txt',  'Text files(*.txt)|*.txt|All files(*.*)|*.*');

      // Отображаем файл в виде HEX-вьюера.
    s1   := '';
    s2   := '';
    End1 :=  Round(Min(F1.Count, BegPos1 +Cnt1)) -1;    
    for i1 := BegPos1 to End1 do begin
      s3 := '';
        // Пишем стартовую позицию в файле в 16-ричном формате.
      j1 := i1 -BegPos1 +1;
      if ((j1 -1) mod 16) = 0 then s3 := s3 +CrdToHEX(i1, 2) ++'|';
        // Обращение к F1[i1] читает из файла строку текста номер i1.
      s3 := s3 +F1[i1];
        // Если в файле есть не символьные байты показываем их как пробелы.
        // Здесь функция F1.AsByte[i1] читает HEX данные из строки I1 как
        //  байт, ей же можно устанавливать значения строк в массиве F1: 
        //    F1.AsByte[i1] := 28;
        // Аналогично работают функции F1.asSmallInt[i1], F1.asInt[i1], 
        //  F1.asSingle[i1], F1.asDouble[i1]. Функция F1.asStr[i1] позволяет
        //  только записывать строки в F1 в HEX формате. А читать их можно 
        //  через функцию F1.GetAsStr(i1, cnt1). Где cnt1 - длина строки.
        //  При чтении или записи читается не только строка i1, но и 
        //  последующие в соответствии с размерностью переменной 
        //  Integer - 4 байта. SmallInt - 2, Single - 4, Double - 8, String - 
        //  в соответствии с длиной строки.
      if F1.AsByte[i1] >= 32 
        then s2 := s2 +F1.GetAsStr(i1, 1)
        else s2 := s2 +' ';
        // Через каждые 8 байт ставим разделитель.
      if (j1 mod  8) = 0 then s3 := s3 +'|'
                         else s3 := s3 +' ';
        // Каждые 16 байт выводим в конце строчку текста.
      if (j1 mod 16) = 0 then begin
        s3 := s3 +s2 +'|' +#13#10;
        s2 := '';
      end;
        // Последняя строка.
      if i1 = End1 then begin
        if (j1 mod 16) <> 0 then begin
          for i2 := 0 to (16 -(j1 mod 16))*3 -2 do
            s3 := s3 +' ';
          s3 := s3 +'|' +s2;
          for i2 := 0 to (16 -(j1 mod 16))*1 -1 do
          // for i2 := 0 to ((j1 mod 8)*1) -1 do
            s3 := s3 +' ';
          s3 := s3 +'|' +#13#10;
        end;
      end;
      s1 := s1 +s3;
    end;
      // Отображаем имя файла и его содержимое в окне ЛОДки.
    LOD('AddPMessage', 'Filename: ''' +sFileName1 +'''.' +#13#10
      +'  < Start byte: ' +IntToStr(BegPos1)
      +' Count: ' +IntToStr(End1 -BegPos1 +1) +' >' +#13#10 +s1);
  end;
    // Уничтожение классов.
  F1.Free;
  FileNames1.Free;
end;