summaryrefslogtreecommitdiff
path: root/utils/ihx2tzx/ihxreader.pas
diff options
context:
space:
mode:
Diffstat (limited to 'utils/ihx2tzx/ihxreader.pas')
-rw-r--r--utils/ihx2tzx/ihxreader.pas130
1 files changed, 130 insertions, 0 deletions
diff --git a/utils/ihx2tzx/ihxreader.pas b/utils/ihx2tzx/ihxreader.pas
new file mode 100644
index 0000000000..5ff4d54252
--- /dev/null
+++ b/utils/ihx2tzx/ihxreader.pas
@@ -0,0 +1,130 @@
+{ IHX (Intel Hex format) to TZX (ZX Spectrum tape file format) convertor tool.
+
+ This file contains the IHX writer code.
+
+ Copyright (C) 2020 Nikolay Nikolov <nickysn@users.sourceforg.net>
+
+ This source is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your option)
+ any later version.
+
+ This code is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ A copy of the GNU General Public License is available on the World Wide Web
+ at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing
+ to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+ Boston, MA 02110-1335, USA.
+}
+
+unit ihxreader;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils;
+
+type
+
+ { TIHXReader }
+
+ TIHXReader = class
+ private
+ FOrigin: Word;
+ FInternalData: array [0..$FFFF] of Byte;
+ public
+ Data: array of Byte;
+
+ procedure ReadIHXFile(const FileName: string);
+
+ property Origin: Word read FOrigin;
+ end;
+
+implementation
+
+{ TIHXReader }
+
+procedure TIHXReader.ReadIHXFile(const FileName: string);
+var
+ InF: TextFile;
+ S: string;
+ I: Integer;
+ LineByteCount: Byte;
+ LineAddress: Word;
+ MinAddress, MaxAddress: LongInt;
+ RecordType: Byte;
+ Checksum, ExpectedChecksum: Byte;
+ B: Byte;
+begin
+ MinAddress := -1;
+ MaxAddress := -1;
+ FOrigin := 0;
+ SetLength(Data, 0);
+ AssignFile(InF, FileName);
+ Reset(InF);
+ try
+ while not EoF(InF) do
+ begin
+ ReadLn(InF, S);
+ S:=UpperCase(Trim(S));
+ if S='' then
+ continue;
+ if Length(S)<11 then
+ raise Exception.Create('Line too short');
+ if S[1]<>':' then
+ raise Exception.Create('Line must start with '':''');
+ for I:=2 to Length(S) do
+ if not (S[I] in ['0'..'9','A'..'F']) then
+ raise Exception.Create('Line contains an invalid character');
+ LineByteCount:=StrToInt('$'+Copy(S,2,2));
+ if (LineByteCount*2+11)<>Length(S) then
+ raise Exception.Create('Invalid line length');
+ LineAddress:=StrToInt('$'+Copy(S,4,4));
+ RecordType:=StrToInt('$'+Copy(S,8,2));
+ Checksum:=StrToInt('$'+Copy(S,Length(S)-1,2));
+ ExpectedChecksum := Byte(LineByteCount + RecordType + Byte(LineAddress) + Byte(LineAddress shr 8));
+ for I:=0 to LineByteCount-1 do
+ begin
+ B := StrToInt('$' + Copy(S, 10 + 2*I, 2));
+ ExpectedChecksum := Byte(ExpectedChecksum + B);
+ end;
+ ExpectedChecksum := Byte(-ExpectedChecksum);
+ if ExpectedChecksum <> Checksum then
+ raise Exception.Create('Invalid checksum');
+ case RecordType of
+ 0:
+ begin
+ if (MinAddress = -1) or (LineAddress < MinAddress) then
+ MinAddress := LineAddress;
+ if (MaxAddress = -1) or (MaxAddress < (LineAddress + LineByteCount - 1)) then
+ MaxAddress := LineAddress + LineByteCount - 1;
+ if MaxAddress > High(FInternalData) then
+ raise Exception.CreateFmt('Data exceeds %d bytes', [High(FInternalData) + 1]);
+ for I:=0 to LineByteCount-1 do
+ begin
+ B := StrToInt('$' + Copy(S, 10 + 2*I, 2));
+ FInternalData[LineAddress + I] := B;
+ end;
+ end;
+ 1:
+ begin
+ { end of file }
+ break;
+ end;
+ end;
+ end;
+ FOrigin := MinAddress;
+ SetLength(Data, MaxAddress - MinAddress + 1);
+ Move(FInternalData[MinAddress], Data[0], MaxAddress - MinAddress + 1);
+ finally
+ CloseFile(InF);
+ end;
+end;
+
+end.
+