458 lines
13 KiB
ObjectPascal
458 lines
13 KiB
ObjectPascal
unit mr.trinity.hex;
|
|
|
|
interface
|
|
uses
|
|
Generics.Collections,
|
|
Classes;
|
|
|
|
const
|
|
rtData = $00;
|
|
rtEOF = $01;
|
|
rtExtendedSegment = $02;
|
|
rtStartSegment = $03;
|
|
rtExtendedLinear = $04;
|
|
rtStartLinear = $05;
|
|
|
|
type
|
|
THexLine = class
|
|
public
|
|
RecLength : byte;
|
|
RecType : byte;
|
|
Address : word;
|
|
Data : PByte;
|
|
Chksum : byte;
|
|
|
|
public
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
THexBlock = class
|
|
public
|
|
BlockLength : cardinal;
|
|
BlockType : byte;
|
|
Address : word;
|
|
Data : PByte;
|
|
|
|
public
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
THexLineList = TObjectList<THexLine>;
|
|
THexBlockList = TObjectList<THexBlock>;
|
|
|
|
THexFile = class
|
|
protected
|
|
fHexLines : THexLineList;
|
|
fHexBlocks : THexBlockList;
|
|
|
|
private
|
|
function GetBlockCount : integer;
|
|
function GetBlock(i:integer): THexBlock;
|
|
|
|
protected
|
|
function ReadLine( Stream: TStream): THexLine;
|
|
|
|
public
|
|
procedure LoadFromFile( FileName : string);
|
|
procedure LoadFromStream( Stream : TStream);
|
|
|
|
procedure Dump( Stream : TStream);
|
|
|
|
public
|
|
procedure AfterConstruction; override;
|
|
procedure BeforeDestruction; override;
|
|
|
|
public
|
|
property Lines : THexLineList read fHexLines;
|
|
property Blocks : THexBlockList read fHexBlocks;
|
|
|
|
property BlockCount : integer read GetBlockCount;
|
|
property Block[i:integer] : THexBlock read GetBlock;
|
|
|
|
end;
|
|
|
|
|
|
implementation
|
|
uses
|
|
Windows,
|
|
SysUtils;
|
|
|
|
{ THexFile }
|
|
|
|
|
|
|
|
// @@@: Construction/destruction ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Construction/destruction
|
|
//
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ================================================================================================
|
|
// After Construction
|
|
// ================================================================================================
|
|
procedure THexFile.AfterConstruction;
|
|
begin
|
|
inherited;
|
|
|
|
fHexLines := THexLineList .Create(false);
|
|
fHexBlocks := THexBlockList .Create
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// Before Destruction
|
|
// ================================================================================================
|
|
procedure THexFile.BeforeDestruction;
|
|
begin
|
|
FreeAndNil(fHexBlocks);
|
|
FreeAndNil(fHexLines );
|
|
|
|
inherited
|
|
end;
|
|
|
|
|
|
|
|
// @@@: Interface +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Interface
|
|
//
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ================================================================================================
|
|
// Load From File
|
|
// ================================================================================================
|
|
procedure THexFile.LoadFromFile(FileName: string);
|
|
var
|
|
stm: TMemoryStream;
|
|
|
|
begin
|
|
if FileExists(FileName) then
|
|
begin
|
|
stm := TMemoryStream.Create;
|
|
stm.LoadFromFile(FileName);
|
|
LoadFromStream(stm);
|
|
stm.Free;
|
|
end
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// Load From Stream
|
|
// ================================================================================================
|
|
procedure THexFile.LoadFromStream(Stream: TStream);
|
|
var
|
|
block : THexBlock;
|
|
line : THexLine;
|
|
cnt : integer;
|
|
|
|
procedure Compress;
|
|
var
|
|
blk1 : THexBlock;
|
|
blk2 : THexBlock;
|
|
i,j : integer;
|
|
size : integer;
|
|
ptr : PByte;
|
|
|
|
label
|
|
loop;
|
|
|
|
begin
|
|
loop:
|
|
|
|
for i:=0 to fHexBlocks.Count -2 do
|
|
begin
|
|
blk1 := fHexBlocks[i];
|
|
|
|
for j:=1 to fHexBlocks.Count -1 do
|
|
begin
|
|
blk2 := fHexBlocks[j];
|
|
|
|
if (blk1.Address +blk1.BlockLength) = blk2.Address then
|
|
begin
|
|
size := blk1.BlockLength +blk2.BlockLength;
|
|
blk1.Data := ReallocMemory( blk1.Data,size);
|
|
ptr := blk1.Data;
|
|
|
|
INC(ptr, blk1.BlockLength);
|
|
CopyMemory(ptr, blk2.Data, blk2.BlockLength);
|
|
|
|
blk1.BlockLength := size;
|
|
|
|
fHexBlocks.Delete(j);
|
|
|
|
goto loop;
|
|
end
|
|
|
|
else if (blk2.Address +blk2.BlockLength) = blk1.Address then
|
|
begin
|
|
size := blk1.BlockLength +blk2.BlockLength;
|
|
blk2.Data := ReallocMemory( blk2.Data,size);
|
|
ptr := blk2.Data;
|
|
|
|
INC(ptr, blk2.BlockLength);
|
|
CopyMemory(ptr, blk1.Data, blk1.BlockLength);
|
|
|
|
blk2.BlockLength := size;
|
|
|
|
fHexBlocks.Delete(i);
|
|
|
|
goto loop;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if Assigned(Stream) then
|
|
begin
|
|
Stream.Seek(0, soBeginning);
|
|
|
|
// ------------------------------------------------------------
|
|
// Read hex records
|
|
// ------------------------------------------------------------
|
|
while true do
|
|
begin
|
|
line := ReadLine(Stream);
|
|
|
|
if line = nil
|
|
then break
|
|
else fHexLines.Add(line)
|
|
end;
|
|
|
|
// ------------------------------------------------------------
|
|
// If the last record is EOF then the data is correct,
|
|
// so build the blocks.
|
|
// ------------------------------------------------------------
|
|
cnt := fHexLines.Count;
|
|
|
|
if (cnt > 0) and (fHexLines[cnt-1].RecType = rtEOF) then
|
|
begin
|
|
for line in fHexLines do
|
|
if line.RecType = rtData then
|
|
begin
|
|
block := THexBlock.Create;
|
|
|
|
block.BlockLength := line.RecLength;
|
|
block.BlockType := line.RecType;
|
|
block.Address := line.Address;
|
|
block.Data := AllocMem(line.RecLength);
|
|
|
|
CopyMemory( block.Data, line.Data, line.RecLength);
|
|
|
|
fHexBlocks.Add(block);
|
|
end;
|
|
|
|
Compress;
|
|
end;
|
|
end
|
|
end;
|
|
|
|
|
|
|
|
// @@@: Internals +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Internals
|
|
//
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ================================================================================================
|
|
// Read Line
|
|
// ================================================================================================
|
|
function THexFile.ReadLine(Stream: TStream): THexLine;
|
|
|
|
function HexToBin( hex: byte): byte;
|
|
begin
|
|
result := 0;
|
|
|
|
if ansichar(hex) in ['0'..'9'] then result := ord(hex) -ord('0');
|
|
if ansichar(hex) in ['a'..'f'] then result := ord(hex) -ord('a') +10;
|
|
if ansichar(hex) in ['A'..'F'] then result := ord(hex) -ord('A') +10;
|
|
end;
|
|
|
|
function GetByte( Data: array of byte): byte;
|
|
begin
|
|
result := (HexToBin(Data[0]) shl 4) +
|
|
(HexToBin(Data[1]));
|
|
end;
|
|
|
|
function GetWord( Data0: array of byte; Data1: array of byte): word;
|
|
begin
|
|
result := (HexToBin(Data0[0]) shl 12) +
|
|
(HexToBin(Data0[1]) shl 8) +
|
|
(HexToBin(Data1[0]) shl 4) +
|
|
(HexToBin(Data1[1]));
|
|
end;
|
|
|
|
var
|
|
mark : ansichar;
|
|
chksum : byte;
|
|
i : byte;
|
|
l : cardinal;
|
|
ptr : PByte;
|
|
|
|
x1 : array [0..1] of byte;
|
|
x2 : array [0..1] of byte;
|
|
|
|
|
|
begin
|
|
result := nil;
|
|
|
|
l := Stream.Read( mark, 1);
|
|
|
|
// -----------------------------------------------------
|
|
// skip CR,LF
|
|
// -----------------------------------------------------
|
|
while (l > 0) and (mark in [#10,#13]) do
|
|
l := Stream.Read(mark,1);
|
|
|
|
if l = 0 then
|
|
exit;
|
|
|
|
// -----------------------------------------------------
|
|
// process record
|
|
// -----------------------------------------------------
|
|
if mark = ':' then
|
|
begin
|
|
chksum := 0;
|
|
|
|
// --------------------------------------------------
|
|
// Allocate HexLine
|
|
// --------------------------------------------------
|
|
result := THexLine.Create;
|
|
|
|
// --------------------------------------------------
|
|
// Length
|
|
// --------------------------------------------------
|
|
Stream.Read(x1, 2);
|
|
inc(chksum, GetByte(x1));
|
|
|
|
result.RecLength := GetByte(x1);
|
|
result.Data := GetMemory(result.RecLength);
|
|
|
|
// --------------------------------------------------
|
|
// Offset
|
|
// --------------------------------------------------
|
|
Stream.Read(x1, 2);
|
|
Stream.Read(x2, 2);
|
|
inc(chksum, GetByte(x1));
|
|
inc(chksum, GetByte(x2));
|
|
|
|
result.Address := GetWord(x1,x2);
|
|
|
|
// --------------------------------------------------
|
|
// Record type
|
|
// --------------------------------------------------
|
|
Stream.Read(x1, 2);
|
|
inc(chksum, GetByte(x1));
|
|
|
|
result.RecType := GetByte(x1);
|
|
|
|
// --------------------------------------------------
|
|
// Data
|
|
// --------------------------------------------------
|
|
ptr := result.Data;
|
|
|
|
for i:=0 to result.RecLength -1 do
|
|
begin
|
|
Stream.Read(x1,2);
|
|
inc(chksum, GetByte(x1));
|
|
|
|
ptr^ := GetByte(x1);
|
|
inc(ptr);
|
|
end;
|
|
|
|
// --------------------------------------------------
|
|
// Checksum
|
|
// --------------------------------------------------
|
|
Stream.Read(x1,2);
|
|
inc(chksum, GetByte(x1));
|
|
|
|
// --------------------------------------------------
|
|
// At that point the checksum must be 0!!!
|
|
// --------------------------------------------------
|
|
if chksum <> 0 then
|
|
FreeAndNil(result);
|
|
end
|
|
end;
|
|
|
|
|
|
|
|
// @@@: Property Handlers +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Property Handlers
|
|
//
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ================================================================================================
|
|
// Get Block Count
|
|
// ================================================================================================
|
|
function THexFile.GetBlockCount: integer;
|
|
begin
|
|
result := fHexBlocks.Count
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// Get Block
|
|
// ================================================================================================
|
|
function THexFile.GetBlock(i: integer): THexBlock;
|
|
begin
|
|
if (i>=0) and (i<fHexBlocks.Count)
|
|
then result := fHexBlocks.Items[i]
|
|
else result := nil
|
|
end;
|
|
|
|
|
|
// ================================================================================================
|
|
// Dump
|
|
// ================================================================================================
|
|
procedure THexFile.Dump(Stream: TStream);
|
|
var
|
|
blk: THexBlock;
|
|
i : integer;
|
|
s : string;
|
|
|
|
begin
|
|
i := 1;
|
|
|
|
for blk in fHexBlocks do
|
|
begin
|
|
// blk.Address;
|
|
// blk.BlockLength;
|
|
s := Format('%3d %4.4x-%4.4x (%4.4x)'#13, [i,blk.Address,blk.Address+blk.BlockLength, blk.BlockLength]);
|
|
writeln(s);
|
|
INC(i);
|
|
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
|
|
{ THexLine }
|
|
|
|
destructor THexLine.Destroy;
|
|
begin
|
|
if Assigned(Data) then FreeMem(Data);
|
|
inherited;
|
|
end;
|
|
|
|
{ THexBlock }
|
|
|
|
destructor THexBlock.Destroy;
|
|
begin
|
|
if Assigned(Data) then FreeMem(Data);
|
|
inherited;
|
|
end;
|
|
|
|
end.
|