Delphi-int.ru: портал программистов

Вход Регистрация | Забыли пароль?

Просмотр кода

Идентификатор: 03e1a79b Описание: Код загружен: 14 апреля 2014, 21:27 (min@y™)

unit uHexFile;
 
interface
 
uses
  Classes, Contnrs, SysUtils, Types;
 
type
  //------------------------- Классы исключений --------------------------------
  EHexFileError = class(Exception);              // Общий предок (для идентификации on E: EHexFileError do)
  EHexInvalidSymbol = class(EHexFileError);      // Исключение - недопустимый символ в НЕХ-строке
  EHexIncorrectDataLen = class(EHexFileError);   // Исключение - Длина строки не соответствует обозначенной длине данных
  EHexIncorrectStringLen = class(EHexFileError); // Исключение - некорректная длина строки (< 11 символов)
  EHexIncorrectChecksum = class(EHexFileError);  // Исключение - Неверная КС
 
   THexFile = class; // Заглушка для ссылки на объект-контейнер
 
  //---------- Класс для перевода НЕХ-строки в адрес/данные и обратно ----------
  THexString = class
  private
    FData: TByteDynArray;        // Данные - только они и нач адрес хранятся, остальное вычисляется
    FAddress: Word;               // Начальный адрес данных
    FHexFile: THexFile;           // Ссылка на объект-контейнер
 
    // Функции доступа к полям
    procedure SetData(const ANew: TByteDynArray);        // Запись данных
    function GetText: string;                             // Чтение НЕХ-текста
    procedure SetText(const ANew: string);                // Установка НЕХ-текста
    function GetChecksum: Byte;                           // Расчёт КС
    function GetDataSize: Byte;                           // Расчёт длины данных в байтах
    procedure SetDataSize(const ANew: Byte);              // Установка новой длины данных (нужно перед записью)
    function GetEOF: Boolean;                             // Флаг конца файла
  public
    constructor Create(AHexFile: THexFile);
    destructor Destroy; override;
 
    // Свойства
    property Data: TByteDynArray read FData write SetData;                   // Данные
    property Text: string read GetText write SetText;                         // НЕХ-строка
    property DataSize: Byte read GetDataSize write SetDataSize;               // Длина данных в байтах
    property Checksum: Byte read GetChecksum;                                 // Контрольная сумма
    property Address: Word read FAddress write FAddress;                      // Начальный адрес данных
    property EOF: Boolean read GetEOF;                                        // Флаг конца файла
    property HexFile: THexFile read FHexFile write FHexFile;                  // Ссылка на объект-контейнер
  end;
 
  //------------ Класс для загрузки из- и сохранения в НЕХ-файл ----------------
  THexFile = class
  private
    FItems: TObjectList; // Список НЕХ-строк
 
    // Функции для доступа к полям
    function GetCount: Integer;                                                 // Количество строк
    function GetDataSize: Cardinal;                                             // Количество данных в байтах
    function GetItem(const Index: Integer): THexString;                         // Доступ к строкам по индексу
  public
    constructor Create;
    destructor Destroy; override;
 
    // Методы
    //procedure SaveToFile
    function Add(const AData: TByteDynArray; const AAddress: Word): THexString;// Добавление НЕХ-строки
    procedure Clear;                                                            // Очистка
    procedure LoadFromFile(const FileName: string);                             // Загрузка
    procedure SaveToFile(const FileName: string);                               // Сохранение
 
    // Свойства
    property Count: Integer read GetCount;                                      // Количество строк
    property DataSize: Cardinal read GetDataSize;                               // Количество данных в байтах
    property Items[const Index: Integer]: THexString read GetItem; default;     // Доступ к строкам по индексу
  end;
 
implementation
 
const
  HexDigits: TSysCharSet = ['0'..'9', 'A'..'F', 'a'..'f']; // 16-чные цифры
 
{ THexString }
 
constructor THexString.Create(AHexFile: THexFile);
begin
  FHexFile:= AHexFile; // Ссылка на объект-контейнер
  SetLength(FData, 0);
  FAddress:= $0000;
end;
 
destructor THexString.Destroy;
begin
  SetLength(FData, 0); // возможная
  FData:= nil;         // очистка памяти
  inherited;
end;
 
function THexString.GetChecksum: Byte;
var
  Index: Integer;
begin
  // Расчёт КС
  if Self.DataSize <> 0
    then Result:= (Self.DataSize and $FF) + // Длина данных
                  ((Address shr 8) and $FF) + // Ст. байт адреса
                  (Address and $FF)           // Мл. байт адреса
    else begin // EOF (:00000001FF)
           Result:= $FF;
           Exit;
         end;
 
  // Плюс сумма данных
  for Index:= 0 to Self.DataSize - 1 do
    Inc(Result, FData[Index]);
 
  Result:= Byte($100 - Result); // Перевод в доп. код.
end;
 
function THexString.GetDataSize: Byte;
begin
  // Расчёт длины данных в байтах
  Result:= Length(FData) and $FF;
end;
 
function THexString.GetEOF: Boolean;
begin
  // Флаг конца файла
  Result:= Self.DataSize = 0;
end;
 
function THexString.GetText: string;
var
  Index: Integer;
begin
  if Self.DataSize = 0
    then Result:= ':00000001FF' // EOF
    else begin
           Result:= ':' +                                  // Префикс
                    IntToHex(Self.DataSize and $FF, 2) +   // Длина данных
                    IntToHex(Self.FAddress, 4) +           // Адрес
                    '00';                                  // Тип строки
 
           for Index:= 0 to Self.DataSize - 1 do           // Данные
             Result:= Result + IntToHex(FData[Index], 2);
 
           Result:= Result + IntToHex(Self.Checksum, 2);   // КС
         end;
end;
 
procedure THexString.SetText(const ANew: string);
var
  Index, Len, dLen: Integer;
  dChecksum: Byte;         // Для подсчёта суммы
  rChecksum: Byte;         // Сумма, взятая из НЕХ-строки для сравнение с расчётной
  Digits: string;
begin
  // Установка текста
 
  { Формат НЕХ-строки:
 
    :0100230032AA
    :00000001FF
 
    01 - длина данных
    0023 - начальный адрес
    00 - тип строки
    32 - данные
    AA - контрольная сумма.
 
    :|01|0023|00|32|AA
    :|08|0013|00|C2AF020AF1D2AF32|C4 }
 
  // Длина строки должна быть = длина данных (закодирована во 2-м и 3-м символах) * 2 + 11,
  // начинаться на ":", состоять из 16-чных символов, начиная со 2-го символа,
  // и КС (закодирована 2-мя последними символами) должна совпадать с расчётной
  // по байтам, закодированным со 2-го по N-2-й символами.
 
  Len:= Length(ANew);
 
  if Len < 11
    then raise EHexIncorrectStringLen.Create('Некорректная длина строки (< 11 символов).');
 
  if ANew[1] <> ':'
    then raise EHexInvalidSymbol.Create('Недопустимый символ "' + ANew[1] + '" в позиции 1.');
 
  // Проверка на 16-чные цифры
  for Index:= 2 to Len do
    if not (ANew[Index] in HexDigits)
      then raise EHexInvalidSymbol.Create('Недопустимый символ "' + ANew[Index] + '" в позиции ' + IntToStr(Index) +
'.');
 
  // Проверка длины строки на соответствие указанной длине данных (закодирована во 2-м и 3-м символах)
  dLen:= StrToInt('$' + Copy(ANew, 2, 2));
  if dLen * 2 + 11 <> Len
    then raise EHexIncorrectDataLen.Create('Длина строки не соответствует обозначенной длине данных.');
 
  // Вычисление и проверка КС
  Digits:= Copy(ANew, 2, Len - 3); // Копирую всё, кроме ":" и КС (последнего байта)
  dChecksum:= $00;
  for Index:= 1 to Length(Digits) div 2 do
    Inc(dChecksum, StrToInt('$' + Copy(Digits, (Index * 2) - 1, 2))); // 1, 3, 5,...
  dChecksum:= Byte($100 - dChecksum);
 
  rChecksum:= Byte(StrToInt('$' + Copy(ANew, Len - 1, 2)));
  if dChecksum <> rChecksum
    then raise EHexIncorrectChecksum.Create('Неверная контрольная сумма (0x' + IntToHex(rChecksum, 2) +
                                     ').'#13#10'Ожидалось 0x' + IntToHex(dChecksum, 2));
 
  // Ну, и наконец, если все проверки не выявили ошибок,
  // выделяю начальный адрес и данные
  FAddress:= Word(StrToInt('$' + Copy(ANew, 4, 4))); // адрес
  Digits:= Copy(ANew, 10, dLen * 2); // Кусок строки с данными
  SetLength(FData, dLen);
  for Index:= 1 to Length(Digits) div 2 do
    FData[Index - 1]:= StrToInt('$' + Copy(Digits, (Index * 2) - 1, 2));
end;
 
procedure THexString.SetDataSize(const ANew: Byte);
begin
  // Установка новой длины данных (нужно перед записью)
  SetLength(FData, ANew);
end;
 
 
procedure THexString.SetData(const ANew: TByteDynArray);
begin
  // Запись данных
  // Self.DataSize:= Cardinal(Length(AData)); // Проверить, нужно ли выделение памяти или оно автоматическое!!!
  Self.FData:= Copy(ANew); // Копирование, именно копирование!
end;
 
{ THexFile }
 
function THexFile.Add(const AData: TByteDynArray;
  const AAddress: Word): THexString;
begin
  // Добавление НЕХ-строки
  Result:= THexString.Create(Self);
  Result.Address:= AAddress;
  Result.Data:= AData;
  Self.FItems.Add(Result);
end;
 
procedure THexFile.Clear;
begin
  // Очистка
  Self.FItems.Clear();
end;
 
constructor THexFile.Create;
begin
  FItems:= TObjectList.Create(True);
end;
 
destructor THexFile.Destroy;
begin
  FItems.Free();
  inherited;
end;
 
function THexFile.GetCount: Integer;
begin
  // Вычисление кол-ва строк
  Result:= FItems.Count;
end;
 
function THexFile.GetDataSize: Cardinal;
var
  Index: Integer;
begin
  // Количество данных в байтах
  Result:= 0;
  for Index:= 0 to Self.Count - 1 do
    Inc(Result, Self[Index].DataSize);
end;
 
function THexFile.GetItem(const Index: Integer): THexString;
begin
  // Доступ к строкам по индексу
  if (Index > -1) and (Index < Self.Count)
    then Result:= THexString(FItems[Index])
    else Result:= nil;
end;
 
procedure THexFile.LoadFromFile(const FileName: string);
var
  Index: Integer;
  List: TStringList;
  Item: THexString;
begin
  // Загрузка
  Self.Clear();
  List:= TStringList.Create();
  try
    List.LoadFromFile(FileName);
 
    for Index:= 0 to List.Count - 1 do
      begin
        Item:= THexString.Create(Self);
        Item.Text:= List[Index];
        FItems.Add(Item);
      end;
  finally
    List.Free();
  end;
end;
 
procedure THexFile.SaveToFile(const FileName: string);
var
  Index: Integer;
  List: TStringList;
begin
  // Сохранение
  List:= TStringList.Create();
  try
    for Index:= 0 to Self.Count - 1 do
      List.Add(Self[Index].Text);
 
    List.SaveToFile(FileName);
  finally
    List.Free();
  end;
end;
 
end.

Ссылка на данный код:

На главную страницу сервиса обмена кодом »