⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 idbuffer.pas

📁 photo.163.com 相册下载器 多线程下载
💻 PAS
📖 第 1 页 / 共 2 页
字号:
  public
    procedure Clear;
    constructor Create; overload;
    constructor Create(
      AOnBytesRemoved: TIdBufferBytesRemoved
      ); overload;
    constructor Create(
      AGrowthFactor: Integer
      ); overload;
    procedure CompactHead(
      ACanShrink: Boolean = True
      );
    destructor Destroy; override;
    // will extract number of bytes and treat as AnsiString though WideString will be returned in DotNet
    function Extract(AByteCount: Integer = -1): string;
    // all 3 extract routines append to existing data, if any
    procedure ExtractToStream(AStream: TIdStreamVCL; AByteCount: Integer = -1);
    procedure ExtractToIdBuffer(ABuffer: TIdBuffer; AByteCount: Integer = -1);
    procedure ExtractToBytes(
      var VBytes: TIdBytes;
      AByteCount: Integer = -1;
      AAppend: Boolean = True
      );
    function IndexOf(
      const ABytes: TIdBytes;
      AStartPos: Integer = 0
      ): Integer;
      overload;
    function IndexOf(
      const AString: string;
      AStartPos: Integer = 0
      ): Integer;
      overload;
    function PeekByte(
      AIndex: Integer
      ): Byte;
    procedure Remove(AByteCount: Integer);
    procedure SaveToStream(AStream: TIdStream);
    // Write
    procedure Write(
      const AString: string;
      AEncoding: TIdEncoding = enDefault
      ); overload;
    procedure Write(
      ABytes: TIdBytes
      ); overload;
    procedure Write(
      AStream: TIdStreamVCL;
      AByteCount: Integer = 0
      ); overload;
    //
    //Kudzu: I have removed the Bytes property. Do not add it back - it allowed "internal" access
    // which caused comapacting or internal knoledge. Access via Extract or other such methods
    // instead. Bytes could also be easily confused with FBytes intnernally and cause issues.
    //
    // Bytes also allowed direct acces without removing which could cause concurrency issues if
    // the reference was kept.
    //
    property Capacity: Integer read GetCapacity write SetCapacity;
    property Encoding: TIdEncoding read FEncoding write FEncoding;
    property GrowthFactor: Integer read FGrowthFactor write FGrowthFactor;
    property Size: Integer read FSize;
  end;

implementation

uses
  IdResourceStringsCore,
  SysUtils;

{ TIdBuffer }

procedure TIdBuffer.CheckAdd(AByteCount : Integer);
begin
  EIdTooMuchDataInBuffer.IfTrue(MaxInt - AByteCount < Size, RSTooMuchDataInBuffer);
end;

procedure TIdBuffer.CheckByteCount(var VByteCount : Integer);
begin
  if VByteCount = -1 then begin
    VByteCount := Size;
  end else begin
    EIdNotEnoughDataInBuffer.IfTrue(VByteCount > Size, RSNotEnoughDataInBuffer + ' ('
     + IntToStr(VByteCount) + '/' + IntToStr(Size) + ')');
  end;
end;

procedure TIdBuffer.Clear;
begin
  SetLength(FBytes, 0);
  FHeadIndex := 0;
  FSize := Length(FBytes);
end;

constructor TIdBuffer.Create(
  AGrowthFactor: Integer
  );
begin
  Create;
  FGrowthFactor := AGrowthFactor;
end;

constructor TIdBuffer.Create(
  AOnBytesRemoved: TIdBufferBytesRemoved
  );
begin
  Create;
  FOnBytesRemoved := AOnBytesRemoved;
end;

destructor TIdBuffer.Destroy;
begin
  Clear;
  inherited;
end;

function TIdBuffer.Extract(
  AByteCount: Integer = -1
  ): string;
var
  LBytes: TIdBytes;
begin
  if AByteCount = -1 then begin
    AByteCount := Size;
  end;
  if AByteCount > 0 then begin
    ExtractToBytes(LBytes, AByteCount);
    Result := BytesToString(LBytes);
  end else begin
    Result := '';
  end;
end;

procedure TIdBuffer.ExtractToBytes(
  var VBytes: TIdBytes;
  AByteCount: Integer = -1;
  AAppend: Boolean = True
  );
var
  LOldSize: Integer;
begin
  if AByteCount = -1 then begin
    AByteCount := Size;
  end;
  if AByteCount > 0 then begin
    CheckByteCount(AByteCount);
    if AAppend then begin
      LOldSize := Length(VBytes);
      SetLength(VBytes, LOldSize + AByteCount);
    end else begin
      LOldSize := 0;
      if Length(VBytes) < AByteCount then begin
        SetLength(VBytes, AByteCount);
      end;
    end;
    CopyTIdBytes(FBytes, FHeadIndex, VBytes, LOldSize, AByteCount);
    Remove(AByteCount);
  end;
end;

procedure TIdBuffer.ExtractToIdBuffer(ABuffer: TIdBuffer; AByteCount: Integer);
var
  LBytes: TIdBytes;
begin
  if AByteCount = -1 then begin
    AByteCount := Size;
  end;
  //TODO: Optimize this routine to directly copy from one to the other
  ExtractToBytes(LBytes, AByteCount);
  ABuffer.Write(LBytes);
end;

procedure TIdBuffer.ExtractToStream(AStream: TIdStreamVCL; AByteCount: Integer);
begin
  if AByteCount = -1 then begin
    AByteCount := Size;
  end;
  CompactHead;
  CheckByteCount(AByteCount);
  AStream.Write(FBytes, AByteCount);
  Remove(AByteCount);
end;

procedure TIdBuffer.Remove(AByteCount: Integer);
begin
  if AByteCount >= Size then begin
    Clear;
  end else begin
    Inc(FHeadIndex, AByteCount);
    Dec(FSize, AByteCount);
    if FHeadIndex > GrowthFactor then begin
      CompactHead;
    end;
  end;
  if Assigned(FOnBytesRemoved) then begin
    FOnBytesRemoved(Self, AByteCount);
  end;
end;

procedure TIdBuffer.CompactHead(
  ACanShrink: Boolean = True
  );
begin
  // Only try to compact if needed.
  if FHeadIndex > 0 then begin
    CopyTIdBytes(FBytes, FHeadIndex, FBytes, 0, Size);
    FHeadIndex := 0;
    if ACanShrink and (Capacity - Size - FHeadIndex > GrowthFactor) then begin
      SetLength(FBytes, FHeadIndex + Size + GrowthFactor);
    end;
  end;
end;

procedure TIdBuffer.Write(ABytes: TIdBytes);
var
  LByteLength: Integer;
begin
  LByteLength := Length(ABytes);
  CheckAdd(LByteLength);
  if Size = 0 then begin
    FBytes := ABytes;
    FHeadIndex := 0;
    FSize := Length(FBytes);
  end else begin
    CompactHead(False);
    if (Capacity - Size - FHeadIndex) < LByteLength then begin
      SetLength(FBytes, Size + LByteLength + GrowthFactor);
    end;
    CopyTIdBytes(ABytes, 0, FBytes, FHeadIndex + Size, LByteLength);
    Inc(FSize, LByteLength);
  end;
end;

procedure TIdBuffer.Write(
  AStream: TIdStreamVCL;
  AByteCount: Integer
  );
var
  LAdded: Integer;
  LLength: Integer;
begin
  if AByteCount = -1 then begin
    // Copy remaining
    LAdded := AStream.VCLStream.Size - AStream.VCLStream.Position;
  end else if AByteCount = 0 then begin
    // Copy all
    AStream.VCLStream.Position := 0;
    LAdded := AStream.VCLStream.Size;
  end else begin
    LAdded := Min(AByteCount, AStream.VCLStream.Size - AStream.VCLStream.Position);
  end;
  if LAdded > 0 then begin
    LLength := Size;
    CheckAdd(LAdded);
    CompactHead;
    SetLength(FBytes, LLength + LAdded);
    AStream.ReadBytes(FBytes, LAdded, LLength);
    Inc(FSize, LAdded);
  end;
end;

function TIdBuffer.IndexOf(const AString: string; AStartPos: Integer): Integer;
begin
  Result := IndexOf(ToBytes(AString), AStartPos);
end;

function TIdBuffer.IndexOf(const ABytes: TIdBytes; AStartPos: Integer): Integer;
var
  i, j, LEnd, BytesLen: Integer;
  LFound: Boolean;
begin
  Result := -1;
  // Dont search if it empty
  if Size > 0 then begin
    EIdException.IfTrue(Length(ABytes) = 0, RSBufferMissingTerminator);
    EIdException.IfNotInRange(AStartPos, 0, Size - 1, RSBufferInvalidStartPos);
    BytesLen := Length(ABytes);
    LEnd := FHeadIndex + Size;
    for i := FHeadIndex + AStartPos to LEnd - BytesLen do begin
      LFound := True;
      for j := 0 to BytesLen - 1 do begin
        if i + j < LEnd then begin
          if FBytes[i + j] <> ABytes[j] then begin
            LFound := False;
            Break;
          end;
        end
        else
          Break;
      end;
      if LFound then begin
        Result := i - FHeadIndex;
        if Result <> -1 then
          Break;
      end;
    end;
  end;
end;

procedure TIdBuffer.Write(
  const AString: string;
  AEncoding: TIdEncoding = enDefault
  );
begin
  if AEncoding = enDefault then begin
    AEncoding := Encoding;
  end;
  Write(ToBytes(AString, AEncoding));
end;

function TIdBuffer.GetCapacity: Integer;
begin
  Result := Length(FBytes);
end;

procedure TIdBuffer.SetCapacity(AValue: Integer);
begin
  EIdException.IfTrue(AValue < Size, 'Capacity cannot be smaller than Size'); {do not localize}
  CompactHead;
  SetLength(FBytes, AValue);
end;

constructor TIdBuffer.Create;
begin
  inherited;
  FEncoding := enANSI;
  FGrowthFactor := 2048;
  Clear;
end;

function TIdBuffer.PeekByte(
  AIndex: Integer
  ): Byte;
begin
  EIdException.IfTrue(Size = 0, 'No bytes in buffer.'); {do not localize}
  EIdException.IfNotInRange(AIndex, 0, Size - 1, 'Index out of bounds.'); {do not localize}
  Result := FBytes[FHeadIndex + AIndex];
end;

procedure TIdBuffer.SaveToStream(AStream: TIdStream);
begin
  CompactHead(False);
  AStream.Write(FBytes, Size);
end;

end.


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -