unit SetupEnt;

{
  Inno Setup
  Copyright (C) 1997-2004 Jordan Russell
  Portions by Martijn Laan
  For conditions of distribution and use, see LICENSE.TXT.

  Functions for handling records with embedded long strings

  $jrsoftware: issrc/Projects/SetupEnt.pas,v 1.6 2009/05/27 10:03:49 mlaan Exp $
}

interface

uses
  Compress;

procedure SEFreeRec(const P: Pointer; const NumStrings, NumAnsiStrings: Integer);
procedure SEDuplicateRec(OldP, NewP: Pointer; Bytes: Cardinal;
  const NumStrings, NumAnsiStrings: Integer);
procedure SECompressedBlockWrite(const W: TCompressedBlockWriter; var Buf;
  const Count: Cardinal; const NumStrings, NumAnsiStrings: Integer);
procedure SECompressedBlockRead(const R: TCompressedBlockReader; var Buf;
  const Count: Cardinal; const NumStrings, NumAnsiStrings: Integer);

implementation

procedure SEFreeRec(const P: Pointer; const NumStrings, NumAnsiStrings: Integer);
var
  AnsiP: Pointer;
begin
  if P = nil then Exit;
  if NumStrings > 0 then  { Finalize in Delphi versions < 5 can't be called with zero count }
    Finalize(String(P^), NumStrings);
  if NumAnsiStrings > 0 then begin
    AnsiP := P;
    Inc(Cardinal(AnsiP), NumStrings*SizeOf(Pointer));
    Finalize(AnsiString(AnsiP^), NumAnsiStrings);
  end;
  FreeMem(P);
end;

procedure SEDuplicateRec(OldP, NewP: Pointer; Bytes: Cardinal;
  const NumStrings, NumAnsiStrings: Integer);
var
  I: Integer;
begin
  for I := 1 to NumStrings do begin
    String(NewP^) := String(OldP^);
    Inc(Cardinal(OldP), SizeOf(Pointer));
    Inc(Cardinal(NewP), SizeOf(Pointer));
    Dec(Bytes, SizeOf(Pointer));
  end;
  for I := 1 to NumAnsiStrings do begin
    AnsiString(NewP^) := AnsiString(OldP^);
    Inc(Cardinal(OldP), SizeOf(Pointer));
    Inc(Cardinal(NewP), SizeOf(Pointer));
    Dec(Bytes, SizeOf(Pointer));
  end;
  Move(OldP^, NewP^, Bytes);
end;

procedure SECompressedBlockWrite(const W: TCompressedBlockWriter; var Buf;
  const Count: Cardinal; const NumStrings, NumAnsiStrings: Integer);
var
  P: Pointer;
  I: Integer;
  Len: Integer;
begin
  P := @Buf;
  for I := 1 to NumStrings do begin
    Len := Length(String(P^))*SizeOf(Char);
    W.Write(Len, SizeOf(Len));
    if Len <> 0 then
      W.Write(Pointer(P^)^, Len);
    Inc(Cardinal(P), SizeOf(Pointer));
  end;
  for I := 1 to NumAnsiStrings do begin
    Len := Length(AnsiString(P^));
    W.Write(Len, SizeOf(Len));
    if Len <> 0 then
      W.Write(Pointer(P^)^, Len);
    Inc(Cardinal(P), SizeOf(Pointer));
  end;
  W.Write(P^, Count - (Cardinal(NumStrings + NumAnsiStrings) * SizeOf(Pointer)));
end;

procedure SECompressedBlockRead(const R: TCompressedBlockReader; var Buf;
  const Count: Cardinal; const NumStrings, NumAnsiStrings: Integer);
var
  P: Pointer;
  I: Integer;
  Len: Integer;
  S: String;
  AnsiS: AnsiString;
begin
  P := @Buf;
  for I := 1 to NumStrings do begin
    R.Read(Len, SizeOf(Len));
    SetLength(S, Len div SizeOf(Char));
    if Len <> 0 then
      R.Read(S[1], Len);
    String(P^) := S;
    Inc(Cardinal(P), SizeOf(Pointer));
  end;
  for I := 1 to NumAnsiStrings do begin
    R.Read(Len, SizeOf(Len));
    SetLength(AnsiS, Len);
    if Len <> 0 then
      R.Read(AnsiS[1], Len);
    AnsiString(P^) := AnsiS;
    Inc(Cardinal(P), SizeOf(Pointer));
  end;
  R.Read(P^, Count - (Cardinal(NumStrings + NumAnsiStrings) * SizeOf(Pointer)));
end;

end.
