[Back to OOP SWAG index]  [Back to Main SWAG index]  [Original]

{
>try using resource files with TurboVision. When opening a resource file with
>extension EXE, TV will append it to the file during write operations.
>I did it already for registration stuff and it works fine.

The trouble with this approach is that each write operation appends a
record, it doesn change the existing one.  For something you do only once
like registration, that's okay, but for config changes, you need to do
something to pack the records.  With Resource files that's complicated, but
possible.  Here's the unit I use to do it.
}

unit resources;

{ Unit to provide extra functions to TVision TResourceFiles }

interface

uses
  objects;

type
  PPackableResource = ^TPackableResource;
  TPackableResource = object(TResourceFile)
    function pack : boolean;
    { Packs the resource file by reading all resources and rewriting them to
      the stream.  Returns false if it fails. }
  end;

implementation

type
  { Type here to get at the secret fields of the TResourceFile }
  TResourceSecrets = object(TObject)
    Stream   : PStream;
    Modified : Boolean;
    BasePos  : Longint;
    IndexPos : Longint;
    Index    : TResourceCollection;
  end;

  PNamedItem = ^TNamedItem;
  TNamedItem = object(TObject)
    Item : PObject;
    Name : PString;
    destructor done; virtual;
  end;

destructor TNamedItem.done;
begin
  DisposeStr(Name);
  inherited done;
end;

procedure Deletechars(var S : TStream; count : Longint);
{ Deletes the given number of characters from the stream }
var
  copy    : longint;
  buffer  : array [1..1024] of byte;
  bufsize : word;
  pos     : longint;
begin
  pos     := S.GetPos;
  copy    := S.GetSize - pos - count;
  bufsize := sizeof(buffer);

  while copy > 0 do
  begin
    if copy < sizeof(buffer) then
      bufsize := copy;
    S.Seek(pos + count);
    S.Read(Buffer, bufsize);
    S.Seek(pos);
    S.write(Buffer, bufsize);
    inc(pos, bufsize);
    dec(copy, bufsize);
  end;
  S.Truncate;
end;

function TPackableResource.Pack : boolean;
var
  contents  : TCollection;
  i         : integer;
  item      : PObject;
  nameditem : PNamedItem;
  OldSize   : longint;
begin
  Flush;
  pack := false;   { Assume failure }
  if Stream^.status <> stOk then
    exit;

  { First, make a copy of all the contents in memory }

  contents.init(Count, 10);
  for i := 0 to pred(Count) do
  begin
    item := Get(KeyAt(i));
    New(NamedItem, init);
    if (NamedItem = nil) or (item = nil) then
    begin
      contents.done;
      exit;
    end;
    NamedItem^.item := item;
    NamedItem^.name := Newstr(Keyat(i));
    contents.atinsert(i, nameditem);
  end;

  { Now, remove all traces of the original. }

  with TResourceSecrets(Self) do
  begin
    Stream^.Seek(BasePos + 4);
    Stream^.Read(OldSize, Sizeof(OldSize));
    Stream^.Seek(BasePos);
    DeleteChars(Stream^, OldSize + 8);
  end;

  { Now, close down and restart }
  TResourceSecrets(Self).Index.Done;
  Stream^.Seek(0);
  inherited init(Stream);

  { Now rewrite all those saved objects. }
  for i := 0 to pred(contents.count) do
  begin
    nameditem := PNamedItem(contents.At(i));
    Put(nameditem^.item, nameditem^.name^);
  end;

  { Get rid of the copies from memory }
  contents.done;

  if Stream^.Status = stOk then
    pack := true;
end;

end.


[Back to OOP SWAG index]  [Back to Main SWAG index]  [Original]