Reputation: 274
I'm looking for a simple way of taking lines of hexadecimal data from a TStringList (always "Windows-1252" text files) and chopping them into record blocks (every line can be different length).
In Delphi 7 I used:
procedure DecodeLineAddr(const aLine: AnsiString; var ByteCount: integer; var Address:Cardinal; var RecType: Integer);
begin
//123 4567 89 0
//:10 4640 00 0000 0600 0200 fa00 004f 7800 1e00 fb00 88
ByteCount:= StrToInt('$' + copy(aLine, 2, 2));
Address := StrToInt('$' + copy(aLine, 4, 4));
RecType := StrToInt('$' + copy(aLine, 8, 2));
end;
That is, just copy the chars from the correct positions in the initial "block info" in the line, then prepend a '$' so StrToInt would interpret the string as hex.
I process line-by-line - so it's easy enough to do something like:
aLineAsTBytes:= TEncoding.ASCII.GetBytes(aStringLst[ndx]);
Then pass aLineAsTBytes into DecodeLineAddr as TBytes instead of AnsiString.
It isn't clear to me of how I should decode the various bytes (or how to carve them up appropriately) in order to return the correct results with code that will work on desktop and mobile.
That is, if using aLine:TBytes (instead of AnsiString), what's the equivalent of:
ByteCount:= StrToInt('$' + copy(aLine, 2, 2));
(and is there a better/faster way of handling this?)
TIA.
EdB
Upvotes: 0
Views: 2106
Reputation: 454
What you're already doing will work but you'll need to make a few tweaks. Most Importantly, make your function into a "string" type instead of an "AnsiString" type, which means that you'll have to convert it.
Mobile strings are 0-based, so on mobile you'll need to subtract 1 from your indexes. Or you can use my ocopy() or zcopy() functions which both perform the same on all platforms. Use ocopy() if you're dealing with old windows code, it will treat your 0-based strings as 1-based strings essentially, making it easier to port.
const
{$IFNDEF MSWINDOWS}
STRZ = 1;
{$ELSE}
STRZ = 0;
function zcopy(sString: string; iStartZeroBased: nativeint; iLength: nativeint): string;
begin
result := '';
setlength(result, lesserof(iLength, length(sString)-iStartZerobased));
movemem32(@result[strz], @sString[(strz+iStartZeroBased)], length(result)*sizeof(char));
end;
function ocopy(sString: string; iStartOneBased: nativeint; iLength: nativeint): string;
begin
result := zcopy(sString, iStartOneBased-1, iLength);
end;
Next, take this code which isn't a totally complete solution, but will give you most of your ansi-string support on mobile (with some slight caveats around pointers). But basically you can essentially convert strings by simply assigning an ansistring to a string type or vice verse. I had to hack this away from a couple of dependencies so I don't guarantee that it will compile out of the box, but it should be pretty close.
unit iosbytestring;
interface
uses
sysutils, classes;
{$IFNDEF MSWINDOWS}
const STRZERO = 0;
{$ELSE}
const STRZERO = 1;
{$ENDIF}
type
Tiosansichar = packed record
private
b: byte;
class function AnsiFromChar(c: char): byte;static;
class function CharFromAnsi(b: byte): char;static;
public
function ToChar: char;
function ToOrd: byte;
class operator Implicit(const s: Tiosansichar): string;
class operator Implicit(const s: Tiosansichar): char;
class operator Implicit(const s: Tiosansichar): byte;
class operator Implicit(const s: Tiosansichar): pointer;
end;
Tiosbytestring = record
private
Fbytes: TBytes;
function GetChar(idx: nativeint): char;
procedure SetChar(idx: nativeint; const Value: char);
function GetAddrOf(idx: nativeint): pbyte;
function getbyte(idx: nativeint): byte;
procedure setbyte(idx: nativeint; const Value: byte);
public
property chars[idx: nativeint]: char read GetChar write SetChar;
property bytes[idx: nativeint]: byte read getbyte write setbyte;
property addrof[idx: nativeint]: pbyte read GetAddrOf;
class operator Implicit(const s: TIOSByteString): string;
class operator Implicit(const s: string): TIOSByteString;
class operator Add(const s1,s2: TIOSByteString): TIOSByteSTring;
class operator Add(const s1: string; const s2: TIOSByteString): TIOSByteSTring;
class operator Add(const s1: TIOSByteString; const s2: string): TIOSByteSTring;
procedure FromString(s: string);
function ToString: string;
procedure SetLength(i: nativeint);
end;
TIOSAnsiString = TIOSByteString;
{$IFNDEF MSWINDOWS}
ansistring = TIOSByteString;
utf8string = TIOSByteString;
widestring = string;
{$ENDIF}
implementation
{ iosbytestring }
class operator Tiosbytestring.Add(const s1: string;
const s2: TIOSByteString): TIOSByteSTring;
var
ss2,ss3: string;
begin
ss2 := s2.ToString;
ss3 := s1+ss2;
result.FromString(ss3);
end;
class operator Tiosbytestring.Add(const s1: TIOSByteString;
const s2: string): TIOSByteSTring;
var
ss1,ss3: string;
begin
ss1 := s1.ToString;
ss3 := ss1+s2;
result.FromString(ss3);
end;
procedure Tiosbytestring.FromString(s: string);
begin
Fbytes := TEncoding.ANSI.GetBytes(s);
end;
function Tiosbytestring.GetAddrOf(idx: nativeint): pbyte;
begin
result := @Fbytes[idx];
end;
function Tiosbytestring.getbyte(idx: nativeint): byte;
begin
result := Fbytes[idx-strzero];
end;
function Tiosbytestring.GetChar(idx: nativeint): char;
begin
result := Tiosansichar.CharFromAnsi(Fbytes[idx-strzero]);
end;
class operator Tiosbytestring.Implicit(const s: TIOSByteString): string;
begin
result := s.ToString;
end;
class operator Tiosbytestring.Implicit(const s: string): TIOSByteString;
begin
result.FromString(s);
end;
procedure Tiosbytestring.setbyte(idx: nativeint; const Value: byte);
begin
Fbytes[idx-strzero] := value;
end;
class operator Tiosbytestring.Add(const s1,
s2: TIOSByteString): TIOSByteSTring;
var
ss1,ss2,ss3: string;
begin
ss1 := s1.ToString;
ss2 := s2.ToString;
ss3 := ss1+ss2;
result.FromString(ss3);
end;
procedure Tiosbytestring.SetChar(idx: nativeint; const Value: char);
begin
Fbytes[idx-strzero] := Tiosansichar.AnsiFromChar(value);
end;
procedure Tiosbytestring.SetLength(i: nativeint);
begin
system.setlength(Fbytes,i);
end;
function Tiosbytestring.ToString: string;
begin
result := TEncoding.ANSI.GetString(Fbytes);
end;
{ Tiosansichar }
class function Tiosansichar.AnsiFromChar(c: char): byte;
var
s: string;
te: TEncoding;
b: TBytes;
begin
s := c;
b := TEncoding.ANSI.GetBytes(c);
result := b[0];
end;
class function Tiosansichar.CharFromAnsi(b: byte): char;
var
s: string;
bytes: TBytes;
begin
system.setlength(bytes, 1);
bytes[0] := b;
s := TEncoding.ANSI.GetString(bytes, 0, 1);
result := s[low(s)];
end;
class operator Tiosansichar.Implicit(const s: Tiosansichar): char;
begin
result := s.ToChar;
end;
class operator Tiosansichar.Implicit(const s: Tiosansichar): string;
begin
result := s.ToChar;
end;
class operator Tiosansichar.Implicit(const s: Tiosansichar): pointer;
begin
result := @s.b;
end;
class operator Tiosansichar.Implicit(const s: Tiosansichar): byte;
begin
result := s.b;
end;
function Tiosansichar.ToChar: char;
begin
result := CharFromAnsi(b);
end;
function Tiosansichar.ToOrd: byte;
begin
result := b;
end;
end.
So just add the above unit, add it to your uses clause, and magically, you'll have an ansistring type on your mobile platforms. Continue using the standard ansistring type on windows.
If all is well... this is how your code snippet might end up looking.
procedure DecodeLineAddr(const aLine: AnsiString; var ByteCount: integer; var Address:Cardinal; var RecType: Integer);
var
aLineWide: string;
begin
aLineWide = aLine;
//123 4567 89 0
//:10 4640 00 0000 0600 0200 fa00 004f 7800 1e00 fb00 88
ByteCount:= StrToInt('$' + ocopy(aLineWide, 2, 2));
Address := StrToInt('$' + ocopy(aLineWide, 4, 4));
RecType := StrToInt('$' + ocopy(aLineWide, 8, 2));
end;
Upvotes: 1