본문 바로가기
Delphi Tip/+Tip

TStreamMemory

by MonoSoft 2022. 2. 9.
728x90
반응형

TStreamMemory

 

델파이 CD의 Extras 폴더를 뒤져보면

ZLIb를 멋지게 포장한

TCompressionStream, TDecompressionStream 객체를 찾을 수 있다.

 

TStream을 간단히 압축하고 해제할 수 있게 해 주기 때문에 자주 애용하게 된다.

그런데, TStream이 아닌 그저 압축된 메모리 덩어리를 다뤄야 할 때는 어떻게 할까.

 

임시 스트림을 만들고 여기에 메모리를 옮겨담고 압축을 푼다??

뭔가 조금 어색하다.

 

메모리 덩어리를 굳이 복사하지 않고 스트림처럼 사용할 수는 없을까?

비슷한 경우는 또 있다.

버퍼에 옮긴 비트맵 파일.

여기 담겨있는 내용을 TBitmap의 LoadFromStream로 불러들일 수는 없을까?

 

TStreamMemory는 이런 고민이 생겼을 때 쓸만한 도구가 될 것이다.

 

동작 방법은 대충 다음과 같고...

 

StrmMem := TStreamMemory.Create(Buffer, BufferSize);

try

Bitmap.LoadFromStream(StrmMem);

finally

StrmMem.Free;

end;

 

이하는 소스코드. 짧은 내용이니 자세한 설명은 생략한다.

 

type

// 메모리를 스트림처럼 접근할 수 있는 녀석. 메모리스트림의 반대개념.

// 사이즈를 조절할 수 없다. 쓰기는 가능하지만 사이즈를 넘길 수 없다.

TStreamMemory = class(TStream)

private

  fMemory: Pointer;

  fSize, fPosition : Longint;

protected

 

public

  constructor Create(const aMemory: Pointer; const aSize: Integer);

  destructor Destroy; override;

 

  function Read(var Buffer; Count: Longint): Longint; override;

  function Write(const Buffer; Count: Longint): Longint; override;

 

  function Seek(Offset: Longint; Origin: Word): Longint; override;

  procedure SetMemory(const aMemory: Pointer; const aSize: Integer);

 

  procedure SaveToStream(Stream: TStream);

  procedure SaveToFile(const FileName: string);

 

  property Memory: Pointer read FMemory;

end;

 

....

 

{ TStreamMemory }

 

constructor TStreamMemory.Create(const aMemory: Pointer; const aSize: Integer);

begin

  fMemory := aMemory;

  fSize := aSize;

  fPosition := 0;

end;

 

destructor TStreamMemory.Destroy;

begin

 

  inherited;

end;

 

function TStreamMemory.Read(var Buffer; Count: Integer): Longint;

begin

if (fPosition >= 0) and (Count >= 0) then

begin

  Result := fSize - fPosition;

  if Result > 0 then

  begin

    if Result > Count then Result := Count;

    Move(Pointer(Longint(fMemory) + fPosition)^, Buffer, Result);

    Inc(fPosition, Result);

    Exit;

  end;

end;

Result := 0;

end;

 

function TStreamMemory.Write(const Buffer; Count: Integer): Longint;

var

  Pos: Longint;

begin

  Result := 0;

 

  if (fPosition >= 0) and (Count >= 0) then

  begin

    Pos := fPosition + Count;

    if Pos > Size then

    begin

      Pos := Size;

      Count := Size - fPosition;

    end;

    System.Move(Buffer, Pointer(Longint(fMemory) + fPosition)^, Count);

    fPosition := Pos;

    Result := Count;

  end;

end;

 

function TStreamMemory.Seek(Offset: Integer; Origin: Word): Longint;

begin

  case Origin of

    soFromBeginning : FPosition := Offset;

    soFromCurrent : Inc(FPosition, Offset);

    soFromEnd : FPosition := FSize + Offset;

  end;

  Result := FPosition;

end;

 

procedure TStreamMemory.SetMemory(const aMemory: Pointer; const aSize: Integer);

begin

  fMemory := aMemory;

  fSize := aSize;

  fPosition := 0;

end;

 

procedure TStreamMemory.SaveToStream(Stream: TStream);

begin

  if fSize <> 0 then Stream.WriteBuffer(fMemory^, fSize);

end;

 

procedure TStreamMemory.SaveToFile(const FileName: string);

var

  Stream: TStream;

begin

  Stream := TFileStream.Create(FileName, fmCreate);

  try

    SaveToStream(Stream);

  finally

    Stream.Free;

  end;

end

728x90
반응형

댓글