Not all file sizes will be evenly divisible by 3.
How do I defeat this if passing a TFileStream to the Encode
function like this: (AStream is a TFileStream)
ss := TStringStream.Create(MIMEEncoder.Encode(AStream, AStream.Size));
> Why is the Encode function checking this:
> ((ABytes mod 3) > 0)
Because it is a bug that keeps creeping back into the code. Someone takes
it out, then someone else puts it back in.
> How do I defeat this
Change the code and recompile Indy. Try the following modified version:
function TIdEncoder3to4.Encode(ASrcStream: TStream; const ABytes:
Integer = MaxInt): string;
//TODO: Make this more efficient. Profile it to test, but maybe make
single
// calls to ReadBuffer then pull from memory
var
LBuffer : String;
LSize : Integer;
LLen : integer;
LBufSize : Integer;
LPos : Integer;
LIn1, LIn2, LIn3: Byte;
LUnit: TIdCardinalBytes;
begin
Result := ''; {Do not Localize}
// No no - this will read the whole thing into memory and what if
its MBs?
// need to load it in smaller buffered chunks MaxInt is WAY too
big....
LBufSize := Min(ASrcStream.Size - ASrcStream.Position, ABytes);
if LBufSize <= 0 then begin
Exit;
end;
SetLength(Result, ((LBufSize+2) div 3) * 4); // we know that the
string will grow by 4/3 adjusted to 3 boundary
LLen := 0;
SetLength(LBuffer, LBufSize);
ASrcStream.ReadBuffer(LBuffer[1], LBufSize);
LPos := 1;
while (LPos <= LBufSize) do
begin
LIn1 := Byte(LBuffer[LPos]);
Inc(LPos);
if LPos <= LBufSize then
begin
LIn2 := Byte(LBuffer[LPos]);
Inc(LPos);
if LPos <= LBufSize then
begin
LIn3 := Byte(LBuffer[LPos]);
Inc(LPos);
LSize := 3;
end
else
begin
LIn3 := 0;
LSize := 2;
end;
end
else
begin
LIn2 := 0;
LIn3 := 0;
LSize := 1;
end;
EncodeUnit(LIn1, LIn2, LIn3, LUnit.Whole);
assert(LLen + 4 <= length(result), 'TIdEncoder3to4.Encode:
Calculated length exceeded (expected '+IntToStr(4 * trunc((LBufSize +
2)/3))+', about to go '+IntToStr(LLen + 4)+' at offset '+IntToStr(LPos)+' of
'+IntToStr(LBufSize));
move(LUnit, Result[LLen + 1], 4);
Inc(LLen, 4);
if LSize < 3 then begin
Result[LLen] := FillChar;
if LSize = 1 then begin
Result[LLen-1] := FillChar;
end;
end;
end;
assert(LLen = 4 * trunc((LBufSize + 2)/3), 'TIdEncoder3to4.Encode:
Calculated length not met (expected '+IntToStr(4 * trunc((LBufSize +
2)/3))+', finished at '+IntToStr(LLen + 4)+', Bufsize =
'+IntToStr(LBufSize));
end;
Otherwise, the only way to defeat it at runtime is to pad your data to make
it an even multiple.
> if passing a TFileStream to the Encode function like this
>
> ss := TStringStream.Create(MIMEEncoder.Encode(AStream, AStream.Size));
You won't be able to defeat it when used that way.
Gambit
Nice source control, then. I thought you guys had it on the ball!!! ;-)