Skip to content

Instantly share code, notes, and snippets.

@FRex
Created November 2, 2013 03:53
Show Gist options
  • Save FRex/7275301 to your computer and use it in GitHub Desktop.
Save FRex/7275301 to your computer and use it in GitHub Desktop.
unit SFUtils;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
type
TRawBytes = array of byte;
TPacketSizeCheckFailed = class
constructor Create; overload;
end;
TPacket = class
private
FData: array of byte;
FValid: boolean;
FReadPos: longword;
procedure CheckSize(i: integer);
public
constructor Create; overload;
procedure Clear;
function GetDataSize: longword;
property DataSize: longword read GetDataSize;
function GetData: TRawBytes;
property Data: TRawBytes read GetData;
function GetEndOfPacket: boolean;
property EndOfPacket: boolean read GetEndOfPacket;
function GetCanRead: boolean;
property CanRead: boolean read GetCanRead;
function ReadBool: boolean;
function ReadInt8: shortint;
function ReadUint8: byte;
function ReadInt16: smallint;
function ReadUint16: word;
function ReadInt32: longint;
function ReadUint32: longword;
function ReadString: string;
function ReadSingle: single;
function ReadDouble: double;
procedure WriteBool(v: boolean);
procedure WriteInt8(v: shortint);
procedure WriteUint8(v: byte);
procedure WriteInt16(v: smallint);
procedure WriteUint16(v: word);
procedure WriteInt32(v: longint);
procedure WriteUint32(v: longword);
procedure WriteString(const v: string);
procedure WriteSingle(v: single);
procedure WriteDouble(v: double);
procedure Append(const bytes; size: longword);
end;
implementation
uses Sockets;
constructor TPacketSizeCheckFailed.Create;
begin
inherited;
end;
procedure TPacket.CheckSize(i: integer);
begin
FValid := FValid and (FReadPos + i <= Length(FData));
if not FValid then
raise TPacketSizeCheckFailed.Create;
end;
constructor TPacket.Create;
begin
inherited;
FReadPos := 0;
FValid := True;
end;
procedure TPacket.Clear;
begin
SetLength(FData, 0);
FReadPos := 0;
FValid := True;
end;
function TPacket.GetDataSize: longword;
begin
Result := Length(FData);
end;
function TPacket.GetData: TRawBytes;
begin
Result := FData;
end;
function TPacket.GetEndOfPacket: boolean;
begin
Result := High(FData) < FReadPos;
end;
function TPacket.GetCanRead: boolean;
begin
Result := FValid;
end;
function TPacket.ReadBool: boolean;
begin
Result := ReadUint8 <> 0;
end;
function TPacket.ReadInt8: shortint;
begin
CheckSize(SizeOf(shortint));
Move(FData[FReadPos], Result, SizeOf(shortint));
Inc(FReadPos, SizeOf(shortint));
end;
function TPacket.ReadUint8: byte;
begin
CheckSize(SizeOf(byte));
Move(FData[FReadPos], Result, SizeOf(byte));
Inc(FReadPos, SizeOf(byte));
end;
function TPacket.ReadInt16: smallint;
begin
CheckSize(SizeOf(smallint));
Move(FData[FReadPos], Result, SizeOf(smallint));
Inc(FReadPos, SizeOf(smallint));
Result := ntohs(Result);
end;
function TPacket.ReadUint16: word;
begin
CheckSize(SizeOf(word));
Move(FData[FReadPos], Result, SizeOf(word));
Inc(FReadPos, SizeOf(word));
Result := ntohs(Result);
end;
function TPacket.ReadInt32: longint;
begin
CheckSize(SizeOf(longint));
Move(FData[FReadPos], Result, SizeOf(longint));
Inc(FReadPos, SizeOf(longint));
Result := ntohl(Result);
end;
function TPacket.ReadUint32: longword;
begin
CheckSize(SizeOf(longword));
Move(FData[FReadPos], Result, SizeOf(longword));
Inc(FReadPos, SizeOf(longword));
Result := ntohl(Result);
end;
function TPacket.ReadString: string;
var
l: longword;
begin
l := ReadUint32;
CheckSize(l);
SetLength(Result, l);
Move(FData[FReadPos], Result[1], l);
Inc(FReadPos, l);
end;
function TPacket.ReadSingle: single;
begin
Move(FData[FReadPos], Result, SizeOf(single));
Inc(FReadPos, SizeOf(single));
end;
function TPacket.ReadDouble: double;
begin
Move(FData[FReadPos], Result, SizeOf(double));
Inc(FReadPos, SizeOf(double));
end;
procedure TPacket.WriteBool(v: boolean);
begin
if v then
WriteUint8(1)
else
WriteUint8(0);
end;
procedure TPacket.WriteInt8(v: shortint);
begin
SetLength(FData, Length(FData) + SizeOf(shortint));
move(v, FData[Length(FData) - SizeOf(shortint)], SizeOf(shortint));
end;
procedure TPacket.WriteUint8(v: byte);
begin
SetLength(FData, Length(FData) + SizeOf(byte));
move(v, FData[Length(FData) - SizeOf(byte)], SizeOf(byte));
end;
procedure TPacket.WriteInt16(v: smallint);
begin
SetLength(FData, Length(FData) + SizeOf(smallint));
move(htons(v), FData[Length(FData) - SizeOf(smallint)], SizeOf(smallint));
end;
procedure TPacket.WriteUint16(v: word);
begin
SetLength(FData, Length(FData) + SizeOf(word));
move(htons(v), FData[Length(FData) - SizeOf(word)], SizeOf(word));
end;
procedure TPacket.WriteInt32(v: longint);
begin
SetLength(FData, Length(FData) + SizeOf(longint));
move(htonl(v), FData[Length(FData) - SizeOf(longint)], SizeOf(longint));
end;
procedure TPacket.WriteUint32(v: longword);
begin
SetLength(FData, Length(FData) + SizeOf(longword));
move(htonl(v), FData[Length(FData) - SizeOf(longword)], SizeOf(longword));
end;
procedure TPacket.WriteString(const v: string);
begin
WriteUint32(Length(v));
SetLength(FData, Length(FData) + Length(v));
move(v[1], FData[Length(FData) - Length(v)], Length(v));
end;
procedure TPacket.WriteSingle(v: single);
begin
SetLength(FData, Length(FData) + SizeOf(single));
move(v, FData[Length(FData) - SizeOf(single)], SizeOf(single));
end;
procedure TPacket.WriteDouble(v: double);
begin
SetLength(FData, Length(FData) + SizeOf(double));
move(v, FData[Length(FData) - SizeOf(double)], SizeOf(double));
end;
procedure TPacket.Append(const bytes; size: longword);
var
i: integer;
begin
SetLength(FData, Length(FData) + size);
Move(bytes, FData[Length(FData) - size], size);
end;
end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment