
Hi,
  Below I attach a TPW 1.5 unit  which provides a dynamically sized
memory stream with no 64K limit. Enjoy.

Eyal Doron

--------------------------Cut here--------------------------
{===============================================================================}
{ Unit wHugeMem, written by Eyal Doron,
1997.                                   }
{                                                                              
}
{ This unit implements a memory stream which is allocated from the
global       }
{ Windows memory pool. The size of the memory stream grows dynamically,
and     }
{ is limited only by the available real and virtual memory. Uses
include:       }
{ * A temporary
stream.                                                         }
{ * A convenient method to randomly access or write to a memory
handle.         }
{                                                                              
}
{
Variables:                                                                   
}
{   Handle - The actual memory
handle.                                          }
{   Size   - The current size of the
stream.                                    }
{   AllocSize - The amount of currently allocated
memory.                       }
{   Base   - A pointer to the beginning of the allocated
memory.                }
{   Owner  - A boolean which determines if the stream owns the handle.
If so,   }
{            the memory will be de-allocated in the destructor,
otherwise no.   }
{   ReallyTruncate - A boolean which determines if Truncate calls
will          }
{                    also de-allocate memory. The default is no, to
speed up    }
{                   
access.                                                    }
{                                                                              
}
{
Constructors:                                                                
}
{                                                                              
}
{
Init(InitialSize)                                                            
}
{   Initialize a new memory stream, and allocate "InitialSize" bytes.
Note      }
{   that the size of the stream, in contrast to the allocated memory, is
zero.  }
{ InitExt(ExtHandle: THandle; InitialSize: longint; AOwner:
boolean)            }
{   Initialize a new memory stream, using an externally provided memory
handle. }
{   Specifying InitialSize=-1 will take it to be given by the allocated
size    }
{   of the memory
block.                                                        }
{===============================================================================}

{$W-,R+,G+}
Unit WHugeMem;

{ Implements a memory stream }

interface

Uses
  WObjects,WinTypes,WinProcs;

type
  TLongType = record
    case Word of
      0: (Ptr: Pchar);
      1: (Long: Longint);
      2: (Lo: Word; Hi: Word);
  end;

  PHugeMemStream = ^THugeMemStream;
  THugeMemStream = object(TStream)
    Size,Current,AllocSize: longint;
    Handle: THandle;
    Base  : TLongType;
    Owner,ReallyTruncate: boolean;
    constructor Init(InitialSize: longint);
    constructor InitExt(ExtHandle: THandle; InitialSize: longint;
AOwner: boolean);
    function    GetPos : longint;   virtual;
    function    GetSize: longint;   virtual;
    procedure   Seek(Pos: Longint); virtual;
    procedure   Truncate;           virtual;
    procedure   Read(var Buf;  Count: Word); virtual;
    procedure   Write(var Buf; Count: Word); virtual;
    destructor  Done; virtual;
  end;

implementation

const
  K64 = $10000;

procedure AHIncr; far; external 'KERNEL' index 114;



{ THugeMemStream methods }

constructor THugeMemStream.init(InitialSize: longint);
begin
  TStream.init;
  Size:=0; Current:=0; AllocSize:=0; Base.Ptr:=Nil; Handle:=0;
  ReallyTruncate:=false;
  if InitialSize>0 then
  begin
    Handle:=GlobalAlloc(GMEM_Moveable,InitialSize);
    AllocSize:=GlobalSize(Handle);
    Base.Ptr:=GlobalLock(Handle);
  end;
  Owner:=true;
end;              { THugeMemStream.init }

constructor THugeMemStream.initExt(ExtHandle: THandle; InitialSize:
longint;
                                   AOwner: boolean);
begin
  TStream.init;
  AllocSize:=GlobalSize(ExtHandle);
  if InitialSize=-1 then InitialSize:=AllocSize;
  Size:=InitialSize; Current:=0; Base.Ptr:=Nil; Handle:=0;
  ReallyTruncate:=false;
  if InitialSize>0 then
  begin
    Handle:=ExtHandle; Base.Ptr:=GlobalLock(Handle);
  end;
  Owner:=AOwner;
end;              { THugeMemStream.init }

function THugeMemStream.GetPos: longint;
begin GetPos:=Current; end;

function THugeMemStream.GetSize: longint;
begin GetSize:=Size; end;

procedure THugeMemStream.Seek(Pos: Longint);
begin
  if Status<>stOK then Exit;
  if (Pos<0) or (Pos>Size) then Error(stReadError,0)
  else Current:=Pos;
end;

procedure THugeMemStream.Truncate;
begin
  if Status<>stOK then Exit;
  Size:=Current;
  if ReallyTruncate then
    GlobalRealloc(Handle,Size,GMEM_ZeroInit);
  { Does not currently de-allocate memory }
end;                    { THugeMemStream.Truncate }

procedure THugeMemStream.Read(var Buf; Count: Word);
var
  Start,ToAddr: TLongType;
  l: word;
  P: PChar;
begin
  if Status<>stOK then Exit;
  if Current+Count>Size then
  begin
    Error(stReadError,0); FillChar(Buf,Count,0);
  end else
  begin
    P:=@Buf;
    Start.Long:=Base.Lo+Current;
    ToAddr.Hi := Base.Hi + (Start.Hi * Ofs(AHIncr));
    ToAddr.Lo := Start.Lo;
    if ToAddr.Lo>$FFFF-Count then  { Crossing a segment boundary }
    begin
      l:=$FFFF-ToAddr.Lo+1;
      Move(ToAddr.Ptr^,Buf,l);
      ToAddr.Hi:=ToAddr.Hi+Ofs(AHIncr); ToAddr.Lo:=0;
      Move(ToAddr.Ptr^,P[l],Count-l);
    end else Move(ToAddr.Ptr^,Buf,Count);
    Current:=Current+Count;
  end;
end;          { THugeMemStream.Read }

procedure THugeMemStream.write(var Buf; Count: Word);
var
  Start,ToAddr: TLongType;
  l: word;
  P: PChar;
  ll: longint;
  NewHandle: THandle;
begin
  if Status<>stOK then Exit;
  if Current+Count>AllocSize then
  begin
    ll:=Current+Count;
    ll:=K64*((ll-1) div K64)+K64;
{    message('Re-alloc to '+num2str(ll));}
    if Handle=0 then Handle:=GlobalAlloc(GMem_Moveable,ll)
    else begin
      GlobalUnlock(Handle);
      NewHandle:=GlobalReAlloc(Handle,ll,GMEM_Moveable);
      if NewHandle=0 then Error(stWriteError,0)
      else Handle:=NewHandle;
{      message('New size is '+num2str(GlobalSize(Handle)));}
    end;
    Base.Ptr:=GlobalLock(Handle);
    AllocSize:=GlobalSize(Handle);
  end;

  P:=@Buf;
  Start.Long:=Base.Lo+Current;
  ToAddr.Hi := Base.Hi + (Start.Hi * Ofs(AHIncr));
  ToAddr.Lo := Start.Lo;
  if ToAddr.Lo>$FFFF-Count+1 then  { Crossing a segment boundary }
  begin
{    message('write '+num2str(count)+' bytes');}
    l:=$FFFF-ToAddr.Lo+1;
{    message(num2str(l)+' bytes first');}
    Move(Buf,ToAddr.Ptr^,l);
    if Count>l then
    begin
      ToAddr.Hi:=ToAddr.Hi+Ofs(AHIncr); ToAddr.Lo:=0;
{      message(num2str(Count-l)+' bytes second');}
      Move(P[l],ToAddr.Ptr^,Count-l);
    end;
  end else Move(Buf,ToAddr.Ptr^,Count);
  Current:=Current+Count; if Current>Size then Size:=Current;
end;               { THugeMemStream.write }

destructor THugeMemStream.Done;
begin
  if Handle<>0 then
  begin
    GlobalUnlock(Handle);
    if Owner then GlobalFree(Handle);
  end;
  TStream.Done;
end;              { THugeMemStream.Done }


end.
