一个汇编写的BASE64

一个汇编写的BASE64

一个汇编写的BASE64

unit Base64;
{
procedure TForm1.Button1Click(Sender: TObject);
var
  Source, Dest: TStream;
begin
  if OpenDialog1.Execute then
  begin
    Source := TFileStream.Create(OpenDialog1.FileName, fmOpenRead); // 打开源文件
    Dest := TFileStream.Create('Base64EncodeTest.txt', fmCreate); // Base64编码文件
    try
      Base64Encode(Source, Dest);
    finally
      Source.Free;
      Dest.Free;
    end;

    Source := TFileStream.Create('Base64EncodeTest.txt', fmOpenRead); // 打开编码文件
    Dest := TFileStream.Create('2.exe', fmCreate); // 还原源文件内容
    try
      Base64Decode(Source, Dest);
      Dest.Position := 0;
    finally
      Source.Free;
      Dest.Free;
    end;
  end;
end;
}

interface

uses
  SysUtils, Classes;

type
{$IFDEF UNICODE}
  Base64String = AnsiString;
{$ELSE}

  Base64String = string;
{$ENDIF}

// 按源长度SourceSize返回Base64编码所需缓冲区字节数

function Base64EncodeBufSize(SourceSize: Integer): Integer;
// 获取Sourec的Base64编码,Base64Buf必须有足够长度。返回实际编码字节数

function Base64Encode(const Source; SourceSize: Integer; var Base64Buf): Integer; overload;
// 将Source编码为Base64字符串返回

function Base64Encode(const Source; SourceSize: Integer): Base64String; overload;
// 将Source从StartPos开始的Size长度的内容源编码为Base64,写入流Dest。
// Size=0 表示一直编码到文件尾

procedure Base64Encode(Source, Dest: TStream; StartPos: Int64 = 0; Size: Int64 = 0); overload;
// 把字符串Str编码为Base64字符串返回
{$IFDEF UNICODE}

function StrToBase64(const Str: AnsiString): Base64String; overload;

function StrToBase64(const Str: string): Base64String; overload;
{$ELSE}

function StrToBase64(const Str: string): Base64String;
{$ENDIF}

// 按给定的编码源Source和长度SourceSize计算并返回解码缓冲区所需字节数

function Base64DecodeBufSize(const Base64Source; SourceSize: Integer): Integer;
// 将Base64编码源Base64Source解码,Buf必须有足够长度。返回实际解码字节数

function Base64Decode(const Base64Source; SourceSize: Integer; var Buf): Integer; overload;
// 将Source从StartPos开始的Size长度的Base64编码内容解码,写入流Dest。
// Size=0 表示一直解码到文件尾

procedure Base64Decode(Source, Dest: TStream; StartPos: Int64 = 0; Size: Int64 = 0); overload;
// 将Base64编码源Base64Source解码为字符串返回

function Base64Decode(const Base64Source; SourceSize: Integer): string; overload;
// 把Base64字符串Base64Str解码为字符串返回

function Base64ToStr(const Base64Str: Base64String): string;

implementation

const
  Base64_Chars: array[0..63] of AnsiChar = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  Base64_Bytes: array[0..79] of Byte = (62, 0, 0, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51);

type
  Base64Proc = function(const Source; SourceSize: Integer; var Buf): Integer;

procedure Base64Stream(Source, Dest: TStream; Proc: Base64Proc; StartPos, Size: Int64; RBufSize, WBufSize: Integer);
var
  RBuf: array of Byte;
  WBuf: array of Byte;
  RSize, WSize: Integer;
begin
  if (StartPos < 0) or (StartPos >= Source.Size) then
    Exit;
  Source.Position := StartPos;
  if (Size <= 0) or (Size > Source.Size - Source.Position) then
    Size := Source.Size
  else
    Size := Size + Source.Position;
  SetLength(RBuf, RBufSize);
  SetLength(WBuf, WBufSize);
  while Size <> Source.Position do
  begin
    if RBufSize > Size - Source.Position then
      RBufSize := Size - Source.Position;
    RSize := Source.Read(RBuf[0], RBufSize);
    WSize := Proc(RBuf[0], RSize, WBuf[0]);
    Dest.Write(WBuf[0], WSize);
  end;
end;

function Base64EncodeBufSize(SourceSize: Integer): Integer;
begin
  Result := ((SourceSize + 2) div 3) shl 2;
end;

(****************************************************************************
* *
* BASE64 Encode hint: *
* *
* addr: (high) 4 byte 3 byte 2 byte 1 byte (low) *
* sourec ASCII(3 bytes): 33333333 22222222 11111111 *
* bswap: 11111111 22222222 33333333 00000000 *
* b4 = Base64_Chars[(source >> 8) & 63]: [00333333]->44444444 *
* b3 = Base64_Chars[(source >> 14) & 63]: [00222233]->33333333 *
* b2 = Base64_Chars[(source >> 20) & 63]: [00112222]->22222222 *
* b1 = Base64_Chars[source >> 26]: [00111111]->11111111 *
* b4 << 24 b3 << 16 b2 << 8 b1 *
* dest BASE64(4 bytes) 44444444 33333333 22222222 11111111 *
* *
****************************************************************************)

function Base64Encode(const Source; SourceSize: Integer; var Base64Buf): Integer;
asm
        push    ebp
        push    esi
        push    edi
        push    ebx
        mov     esi, eax // esi = Source
        mov     edi, ecx // edi = Buf
        mov     eax, edx
        cdq
        mov     ecx, 3
        DIV     ecx // edx = SourceSize % 3
        mov     ecx, eax // ecx = SourceSize / 3
        test    edx, edx
        jz      @@1
        inc     eax // eax = (SourceSize + 2) / 3

@@1:
        push    eax
        push    edx
        lea     ebp, Base64_Chars
        jecxz   @Last
        cld

@EncodeLoop: // while (ecx > 0){
        mov     edx, [esi] // edx = 00000000 33333333 22222222 11111111
        bswap   edx // edx = 11111111 22222222 33333333 00000000
        push    edx
        push    edx
        push    edx
        pop     ebx // ebx = edx
        SHR     edx, 20
        SHR     ebx, 26 // ebx = 00111111
        AND     edx, 63 // edx = 00112222
        mov     ah, [ebp + edx] // *(word*)edi = (Base64_Chars[edx] << 8) |
        mov     al, [ebp + ebx] // Base64_Chars[ebx]
        stosw // edi += 2
        pop     edx // edx = 11111111 22222222 33333333 00000000
        pop     ebx // ebx = edx
        SHR     edx, 8
        SHR     ebx, 14
        AND     edx, 63 // edx = 00333333
        AND     ebx, 63 // ebx = 00222233
        mov     ah, [ebp + edx] // *(word*)edi = (Base64_Chars[edx] << 8) |
        mov     al, [ebp + ebx] // Base64_Chars[ebx]
        stosw // edi += 2
        add     esi, 3 // esi += 3
        loop    @EncodeLoop // }

@Last:
        pop     ecx // ecx = SourceSize % 3
        jecxz   @END // if (ecx == 0) return
        mov     eax, 3d3d0000h // preset 2 bytes '='
        mov     [edi], eax
        test    ecx, 2
        jnz     @@3
        mov     al, [esi] // if (ecx == 1)
        SHL     eax, 4 // eax = *esi << 4
        jmp     @@4

@@3:
        mov     ax, [esi] // else
        xchg    al, ah // eax = ((*esi << 8) or *(esi + 1)) << 2
        SHL     eax, 2

@@4:
        add     edi, ecx // edi += ecx
        inc     ecx // ecx = last encode bytes

@LastLoop:
        mov     edx, eax // for (; cex > 0; ecx --, edi --)
        AND     edx, 63 // {
        mov     dl, [ebp + edx] // edx = eax & 63
        mov     [edi], dl // *edi = Base64_Chars[edx]
        SHR     eax, 6 // eax >>= 6
        dec     edi // }
        loop    @LastLoop

@end:
        pop     eax
        SHL     eax, 2 // return encode bytes
        pop     ebx
        pop     edi
        pop     esi
        pop     ebp
end;

function Base64Encode(const Source; SourceSize: Integer): Base64String;
begin
  SetLength(Result, Base64EncodeBufSize(SourceSize));
  Base64Encode(Source, SourceSize, Result[1]);
end;

procedure Base64Encode(Source, Dest: TStream; StartPos: Int64; Size: Int64);
begin
  Base64Stream(Source, Dest, Base64Encode, StartPos, Size, 6144, 8192);
end;

{$IFDEF UNICODE}
function StrToBase64(const Str: AnsiString): Base64String;
begin
  Result := Base64Encode(Str[1], Length(Str));
end;

function StrToBase64(const Str: string): Base64String;
begin
  Result := StrToBase64(AnsiString(Str));
end;
{$ELSE}

function StrToBase64(const Str: string): Base64String;
begin
  Result := Base64Encode(Str[1], Length(Str));
end;
{$ENDIF}

function Base64DecodeBufSize(const Base64Source; SourceSize: Integer): Integer;
asm
        mov     ecx, eax // ecx = Source + Size
        add     ecx, edx
        mov     eax, edx // eax = Size / 4 * 3
        SHR     edx, 2
        SHR     eax, 1
        add     eax, edx
        mov     edx, eax
        jz      @@2

@@1:
        dec     ecx
        cmp     byte ptr[ecx], 61
        jne     @@2 // if (*--ecx == '=')
        dec     eax // eax --
        jmp     @@1

@@2: // return eax: BufSize; edx: Size / 4 * 3
end;

function Base64Decode(const Base64Source; SourceSize: Integer; var Buf): Integer;
asm
        push    ebp
        push    esi
        push    edi
        push    ebx
        mov     esi, eax // esi = Source
        mov     edi, ecx // edi = Buf
        mov     ebx, edx
        call    Base64DecodeBufSize
        push    eax // eax = Base64DecodeBufSize(Source, SourceSize)
        sub     edx, eax // edx -= eax // edx: '=' count
        lea     ebp, Base64_Bytes
        SHR     ebx, 2 // ebx = SourceSize / 4
        test    ebx, ebx
        jz      @END
        push    edx
        cld

@DecodeLoop: // for (; ebx > 0; ebx --; edi += 3)
        mov     ecx, 4 // {
        XOR     eax, eax

@xchgLoop: // for (ecx = 4, eax = 0; ecx > 0; ecx --)
        movzx   edx, [esi] // {
        sub     edx, 43 // edx = *(int*)esi - 43
        SHL     eax, 6 // eax <<= 6
        OR      al, [ebp + edx]// al |= Base64_Bytes[edx]
        inc     esi // esi ++
        loop    @xchgLoop // }
        bswap   eax // bswap(eax)
        dec     ebx // if (ebx == 1) break
        jz      @Last
        SHR     eax, 8 // eax >>= 8
        stosw // *edi = ax; edi += 2
        SHR     eax, 16 // eax >>= 16
        stosb // *edi++ = al
        jmp     @DecodeLoop // }

@Last:
        pop     ecx
        XOR     ecx, 3 // ecx = last bytes

@LastLoop: // for (; ecx > 0; ecx --)
        SHR     eax, 8 // {
        stosb // eax >>= 8; *edi ++ = al
        loop    @LastLoop // }

@end:
        pop     eax // return eax
        pop     ebx
        pop     edi
        pop     esi
        pop     ebp
end;

procedure Base64Decode(Source, Dest: TStream; StartPos: Int64; Size: Int64);
begin
  Base64Stream(Source, Dest, Base64Decode, StartPos, Size, 8192, 6144);
end;

{$IFDEF UNICODE}
function Base64Decode(const Base64Source; SourceSize: Integer): string;
var
  s: AnsiString;
begin
  SetLength(s, Base64DecodeBufSize(Base64Source, SourceSize));
  Base64Decode(Base64Source, SourceSize, s[1]);
  Result := string(s);
end;
{$ELSE}

function Base64Decode(const Base64Source; SourceSize: Integer): string;
begin
  SetLength(Result, Base64DecodeBufSize(Base64Source, SourceSize));
  Base64Decode(Base64Source, SourceSize, Result[1]);
end;
{$ENDIF}

function Base64ToStr(const Base64Str: Base64String): string;
begin
  Result := Base64Decode(Base64Str[1], Length(Base64Str));
end;

end.

  

12-31 14:51