{$A+,B-,D+,E-,F-,G+,I+,L+,N-,O+,P+,Q+,R+,S+,T-,V-,X+,Y+} {.$DEFINE OPRO} { This unit adds an XMS-memory stream to TStream or IdStream depending on the define above. (c) 1994 Helge Olav Helgesen If you have any comments, please leave them in the Pascal conference on Rime or U'NI, or on InterNet to me at helge.helgesen@midnight.powertech.no } {$IFNDEF MSDOS} !! This unit must be compiled under real mode !! {$ENDIF} Unit Xms; interface uses {$IFDEF OPRO} OpRoot, {$ELSE} Objects, {$ENDIF} OpDos, OpXms; type PXmsStream = ^TXmsStream; { pointer to TXmsStream } TXmsStream = object({$IFDEF OPRO}IdStream{$ELSE}TStream{$ENDIF}) XmsSizeInK, { allocated size in kilobytes } XmsHandle: word; { XMS Handle } TotalSize, { total size in bytes } CurOfs, { current offset into the stream } UsedSize: longint; { size of used stream } constructor Init(MemNeeded: word); { allocate ext. memory and init vars } destructor Done; virtual; { deallocate ext. memory } procedure Seek(WhereTo: longint); virtual; { seek within stream } function GetPos: longint; virtual; { get curret offset } function GetSize: longint; virtual; { get used size of stream } procedure SetPos(Ofs: longint; Mode: byte); virtual; { seek using POS mode } procedure Truncate; virtual; { truncate stream to current size } procedure Write(var Buf; Count: Word); virtual; { writes Buf to the stream } procedure Read(var Buf; Count: Word); virtual; { reads Buf from the stream } end; { TXmsStream } {$IFNDEF OPRO} var InitStatus: byte; { detailed error code from last Init or Done } {$ENDIF} const RealMemHandle = 0; { handle for Real Memory } {$IFNDEF OPRO} PosAbs = 0; {Relative to beginning} PosCur = 1; {Relative to current position} PosEnd = 2; {Relative to end} {$ENDIF} {$IFDEF OPRO} procedure SaveStream(const FileName: string; var S: IdStream); { Saves a stream to disk, old file is erased! } procedure LoadStream(const FileName: string; var S: IdStream); { Loads a stream from disk } {$ELSE} procedure SaveStream(const FileName: string; var S: TStream); { Saves a stream to disk, old file is erased! } procedure LoadStream(const FileName: string; var S: TStream); { Loads a stream from disk } {$ENDIF} implementation constructor TXmsStream.Init; { You should already have tested if XMS is installed! } begin if not inherited Init then Fail; InitStatus:=AllocateExtMem(MemNeeded, XmsHandle); if InitStatus>0 then Fail; XmsSizeInK:=MemNeeded; TotalSize:=LongInt(MemNeeded)*LongInt(1024); UsedSize:=0; CurOfs:=0; end; { TXmsStream } destructor TXmsStream.Done; begin FreeExtMem(XmsHandle); inherited Done; end; { TXmsStream.Done } procedure TXmsStream.Seek; begin {$IFDEF OPRO} if idStatus=0 then {$ELSE} if Status=stOk then {$ENDIF} CurOfs:=WhereTo; end; { TXmsStream } function TXmsStream.GetPos; begin {$IFDEF OPRO} if idStatus=0 then {$ELSE} if Status=stOk then {$ENDIF} GetPos:=CurOfs else GetPos:=-1; end; { TXmsStream.GetPos } function TXmsStream.GetSize; begin {$IFDEF OPRO} if idStatus=0 then {$ELSE} if Status=stOk then {$ENDIF} GetSize:=UsedSize else GetSize:=-1; end; { TXmsStream.GetSize } procedure TXmsStream.Truncate; begin {$IFDEF OPRO} if idStatus=0 then {$ELSE} if Status=stOk then {$ENDIF} UsedSize:=CurOfs; end; { TXmsStream.Truncate } procedure TXmsStream.Write; var NumberisOdd: boolean; x: word; Source, Dest: ExtMemPtr; begin {$IFDEF OPRO} if idStatus<>0 then {$ELSE} if Status<>stOk then {$ENDIF} Exit; if LongInt(Count)+LongInt(CurOfs)>LongInt(TotalSize) then begin {$IFDEF OPRO} Error(101); { disk write error } {$ELSE} Error(stWriteError, 0); {$ENDIF} Exit; end; { if } NumberIsOdd:=Odd(Count); if NumberIsOdd then Dec(Count); Source.RealPtr:=@Buf; Dest.ProtectedPtr:=CurOfs; if Count>0 then x:=MoveExtMemBlock(Count, RealMemHandle, Source, { source data } XmsHandle, Dest) { dest data } else x:=0; if x>0 then { new error } begin {$IFDEF OPRO} Error(101); { disk write error } {$ELSE} Error(stWriteError, x); {$ENDIF} Exit; end; { if } Inc(CurOfs, Count); { adjust current offset } if CurOfs>UsedSize then UsedSize:=CurOfs; if not NumberisOdd then Exit; asm { get last byte to transfer } les di, Buf mov bx, Count mov ax, es:[di+bx] inc Count mov x, ax end; { asm } Source.RealPtr:=@x; Inc(Dest.ProtectedPtr, Count-1); Count:=2; x:=MoveExtMemBlock(Count, RealMemHandle, Source, { source data } XmsHandle, Dest); { dest data } if x>0 then { new error } begin {$IFDEF OPRO} Error(101); { disk write error } {$ELSE} Error(stWriteError, x); {$ENDIF} Exit; end; { if } Inc(CurOfs); if CurOfs>UsedSize then UsedSize:=CurOfs; end; { TXmsStream.Write } procedure TXmsStream.Read; var NumberisOdd: boolean; x: word; Source, Dest: ExtMemPtr; begin {$IFDEF OPRO} if idStatus<>0 then {$ELSE} if Status<>stOk then {$ENDIF} Exit; if LongInt(CurOfs)+LongInt(Count)>LongInt(UsedSize) then begin { read error } {$IFDEF OPRO} Error(100); { read error } {$ELSE} Error(stReadError, 0); {$ENDIF} Exit; end; { if } NumberisOdd:=Odd(Count); if NumberisOdd then Inc(Count); Source.ProtectedPtr:=CurOfs; Dest.RealPtr:=@Buf; x:=MoveExtMemBlock(Count, XmsHandle, Source, { source data } RealMemHandle, Dest); { dest data } if x>0 then begin {$IFDEF OPRO} Error(100); { read error } {$ELSE} Error(stReadError, x); {$ENDIF} Exit; end; { if } if NumberisOdd then Dec(Count); Inc(CurOfs, Count); end; { TXmsStream.Read } procedure TXmsStream.SetPos; begin case Mode of PosAbs: Seek(Ofs); PosCur: Seek(LongInt(Ofs)+LongInt(CurOfs)); PosEnd: Seek(LongInt(UsedSize)-LongInt(Ofs)); end; { case } end; { TXmsStream.SetPos } procedure SaveStream; { Saves the stream to disk. No errorchecking is done } var Buf: pointer; x, BufSize: word; f: file; OldPos, l: longint; begin Assign(f, FileName); Rewrite(f, 1); if S.GetSize=0 then begin Close(f); Exit; end; { if } if MaxAvail>65520 then BufSize:=65520 else BufSize:=MaxAvail; GetMem(Buf, BufSize); OldPos:=S.GetPos; l:=S.GetSize; S.Seek(0); while l<>0 do begin if l>BufSize then x:=BufSize else x:=l; S.Read(Buf^, x); {$IFDEF OPRO} if S.PeekStatus<>0 then {$ELSE} if S.Status<>0 then {$ENDIF} begin Close(f); Exit; end; { if } BlockWrite(f, Buf^, x); Dec(l, x); end; { while } Close(f); FreeMem(Buf, BufSize); S.Seek(OldPos); end; { SaveStream } procedure LoadStream; { Loads the stream from disk. No errorchecking is done, you must allocate enough memory yourself! Any old contents of the stream is erased. } var f: file; BufSize, x: word; l: longint; Buf: pointer; begin if not ExistFile(FileName) then Exit; Assign(f, FileName); Reset(f, 1); S.Seek(0); S.Truncate; l:=FileSize(f); if l>0 then begin if MaxAvail>65520 then BufSize:=65520 else BufSize:=MaxAvail; GetMem(Buf, BufSize); while l<>0 do begin BlockRead(f, Buf^, BufSize, x); S.Write(Buf^, x); {$IFDEF OPRO} if S.PeekStatus<>0 then {$ELSE} if S.Status<>0 then {$ENDIF} begin Close(f); Exit; end; { if } Dec(l, x); end; { while } FreeMem(Buf, BufSize); end; { if } Close(f); S.Seek(0); end; { LoadStream } end.