
(*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * http://www.opensource.org/licenses/cddl1.php.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * http://www.opensource.org/licenses/cddl1.php.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying * information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Andreas Schneider
 *)
unit UEnhancedMemoryStream;

{$mode delphi}{$H+}

interface

uses
  Classes, UStreamHelper;

type

  { TEnhancedMemoryStream }

  TEnhancedMemoryStream = class(TFifoStream)
  public
    function ReadBoolean: Boolean;
    function ReadByte: Byte;
    function ReadCardinal: Cardinal;
    function ReadInteger: Integer;
    function ReadInt64: Int64;
    function ReadShortInt: ShortInt;
    function ReadSmallInt: SmallInt;
    function ReadWord: Word;
    function ReadStringNull: string;
    function ReadStringFixed(ALength: Integer): string;
    function ReadStringBigUniNull: WideString;
    procedure WriteBoolean(AValue: Boolean);
    procedure WriteByte(AValue: Byte);
    procedure WriteCardinal(AValue: Cardinal);
    procedure WriteInteger(AValue: Integer);
    procedure WriteInt64(AValue: Int64);
    procedure WriteShortInt(AValue: ShortInt);
    procedure WriteSmallInt(AValue: SmallInt);
    procedure WriteWord(AValue: Word);
    procedure WriteStringNull(AValue: string);
    procedure WriteStringFixed(AValue: string; ALength: Integer);
    procedure WriteStringBigUniNull(AValue: WideString);
    procedure WriteStringLittleUniNull(AValue: WideString);
  end;

implementation

type
  PByteArray = ^TByteArray;
  TByteArray = array[0..MaxInt - 1] of Byte;

function SwapWideChar(Char: WideChar): WideChar;
begin
  Result := WideChar((Word(Char) shl 8) or ((Word(Char) shr 8) and $FF));
end;  

{ TEnhancedMemoryStream }

function TEnhancedMemoryStream.ReadBoolean: Boolean;
begin
  Read(Result, SizeOf(Boolean));
end;

function TEnhancedMemoryStream.ReadByte: Byte;
begin
  Read(Result, SizeOf(Byte));
end;

function TEnhancedMemoryStream.ReadCardinal: Cardinal;
begin
  Read(Result, SizeOf(Cardinal));
end;

function TEnhancedMemoryStream.ReadInt64: Int64;
begin
  Read(Result, SizeOf(Int64));
end;

function TEnhancedMemoryStream.ReadShortInt: ShortInt;
begin
  Read(Result, SizeOf(ShortInt));
end;

function TEnhancedMemoryStream.ReadInteger: Integer;
begin
  Read(Result, SizeOf(Integer));
end;

function TEnhancedMemoryStream.ReadSmallInt: SmallInt;
begin
  Read(Result, SizeOf(SmallInt));
end;

function TEnhancedMemoryStream.ReadStringBigUniNull: WideString;
var
  buffer: PWideChar;
  length: Integer;
begin
  Result := '';
  buffer := Pointer(LongInt(Memory) + Position);
  length := 0;
  while (buffer[length] <> #0) and (length < (Size - Position)) do
  begin
    if (SwapWideChar(buffer[length]) = #10) and (SwapWideChar(buffer[length - 1]) <> #13) then
      Result := Result + #13;
    Result := Result + SwapWideChar(buffer[length]);
    if (SwapWideChar(buffer[length]) = #13) and (SwapWideChar(buffer[length + 1]) <> #10) then
      Result := Result + #10;
    inc(length);
  end;
  Position := Position + (Length + 1) * 2;
end;

function TEnhancedMemoryStream.ReadStringFixed(ALength: Integer): string;
var
  buffer: PChar;
  length: Integer;
begin
  Result := '';
  buffer := Pointer(LongInt(FMemory) + FPosition);
  length := 0;
  while (length < ALength) and (length < (FSize - (FPosition - FLockOffset))) do
  begin
    if (buffer[length] = #10) and (buffer[length - 1] <> #13) then
      Result := Result + #13;
    Result := Result + buffer[length];
    if (buffer[length] = #13) and (buffer[length + 1] <> #10) then
      Result := Result + #10;
    inc(length);
  end;
  FPosition := FPosition + length + 1;
end;

function TEnhancedMemoryStream.ReadStringNull: string;
var
  buffer: PByteArray;
  length: Integer;
begin
  Result := '';
  buffer := Pointer(LongInt(FMemory) + FPosition);
  length := 0;
  while (buffer^[length] <> 0) and (length < (FSize - (FPosition - FLockOffset))) do
  begin
    if (buffer^[length] = 10) and (buffer^[length - 1] <> 13) then
      Result := Result + #13;
    Result := Result + Char(buffer^[length]);
    if (buffer^[length] = 13) and (buffer^[length + 1] <> 10) then
      Result := Result + #10;
    inc(length);
  end;
  FPosition := FPosition + length + 1;
end;

function TEnhancedMemoryStream.ReadWord: Word;
begin
  Read(Result, SizeOf(Word));
end;

procedure TEnhancedMemoryStream.WriteBoolean(AValue: Boolean);
begin
  Write(AValue, SizeOf(Boolean));
end;

procedure TEnhancedMemoryStream.WriteByte(AValue: Byte);
begin
  Write(AValue, SizeOf(Byte));
end;

procedure TEnhancedMemoryStream.WriteCardinal(AValue: Cardinal);
begin
  Write(AValue, SizeOf(Cardinal));
end;

procedure TEnhancedMemoryStream.WriteInt64(AValue: Int64);
begin
  Write(AValue, SizeOf(Int64));
end;

procedure TEnhancedMemoryStream.WriteShortInt(AValue: ShortInt);
begin
  Write(AValue, SizeOf(ShortInt));
end;

procedure TEnhancedMemoryStream.WriteInteger(AValue: Integer);
begin
  Write(AValue, SizeOf(Integer));
end;

procedure TEnhancedMemoryStream.WriteSmallInt(AValue: SmallInt);
begin
  Write(AValue, SizeOf(SmallInt));
end;

procedure TEnhancedMemoryStream.WriteStringBigUniNull(AValue: WideString);
var
  i: Integer;
begin
  for i := 1 to Length(AValue) do
    WriteWord(Word(SwapWideChar(AValue[i])));
  WriteWord(0);
end;

procedure TEnhancedMemoryStream.WriteStringFixed(AValue: string;
  ALength: Integer);
var
  i: Integer;
begin
  for i := Length(AValue) to ALength do
    AValue := AValue + #0;
  Write(PChar(AValue)^, ALength);
end;

procedure TEnhancedMemoryStream.WriteStringLittleUniNull(
  AValue: WideString);
var
  i: Integer;
begin
  for i := 1 to Length(AValue) do
    WriteWord(Word(AValue[i]));
  WriteWord(0);
end;

procedure TEnhancedMemoryStream.WriteStringNull(AValue: string);
begin
  write(PChar(AValue)^, Length(AValue) + 1);
end;

procedure TEnhancedMemoryStream.WriteWord(AValue: Word);
begin
  Write(AValue, SizeOf(Word));
end;

end.
