Просмотр кода
Идентификатор: 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.