1
0
mirror of synced 2024-09-16 16:46:09 +00:00

Added: Win64 compatibility

Fixed: XML persist reader creating sections
Fixed: new MIME implementation for XMLDataBindingUtils
This commit is contained in:
Mark van Renswoude 2014-03-16 08:42:46 +00:00
parent 4d9a76cb35
commit a212dbd74c
4 changed files with 329 additions and 222 deletions

View File

@ -9,8 +9,8 @@
<ProjectVersion>13.4</ProjectVersion> <ProjectVersion>13.4</ProjectVersion>
<Base>True</Base> <Base>True</Base>
<Config Condition="'$(Config)'==''">Debug</Config> <Config Condition="'$(Config)'==''">Debug</Config>
<Platform Condition="'$(Platform)'==''">Win32</Platform> <Platform Condition="'$(Platform)'==''">Win64</Platform>
<TargetedPlatforms>1</TargetedPlatforms> <TargetedPlatforms>3</TargetedPlatforms>
<AppType>Package</AppType> <AppType>Package</AppType>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''"> <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
@ -31,11 +31,29 @@
<CfgParent>Base</CfgParent> <CfgParent>Base</CfgParent>
<Base>true</Base> <Base>true</Base>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''">
<Cfg_1_Win64>true</Cfg_1_Win64>
<CfgParent>Cfg_1</CfgParent>
<Cfg_1>true</Cfg_1>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
<Cfg_1_Win32>true</Cfg_1_Win32>
<CfgParent>Cfg_1</CfgParent>
<Cfg_1>true</Cfg_1>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''"> <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''">
<Cfg_2>true</Cfg_2> <Cfg_2>true</Cfg_2>
<CfgParent>Base</CfgParent> <CfgParent>Base</CfgParent>
<Base>true</Base> <Base>true</Base>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win64)'!=''">
<Cfg_2_Win64>true</Cfg_2_Win64>
<CfgParent>Cfg_2</CfgParent>
<Cfg_2>true</Cfg_2>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''"> <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
<Cfg_2_Win32>true</Cfg_2_Win32> <Cfg_2_Win32>true</Cfg_2_Win32>
<CfgParent>Cfg_2</CfgParent> <CfgParent>Cfg_2</CfgParent>
@ -57,14 +75,20 @@
<DCC_GenerateStackFrames>true</DCC_GenerateStackFrames> <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Base_Win64)'!=''"> <PropertyGroup Condition="'$(Base_Win64)'!=''">
<DCC_Namespace>Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
<DCC_BplOutput>$(DELPHIBIN64)</DCC_BplOutput>
<VerInfo_Locale>1033</VerInfo_Locale>
<DCC_DcpOutput>$(DELPHIBIN64)</DCC_DcpOutput>
<DCC_DcuOutput>$(DELPHILIB64)</DCC_DcuOutput>
<Icon_MainIcon>X2Utils_Icon.ico</Icon_MainIcon> <Icon_MainIcon>X2Utils_Icon.ico</Icon_MainIcon>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Base_Win32)'!=''"> <PropertyGroup Condition="'$(Base_Win32)'!=''">
<DCC_BplOutput>$(DELPHIBIN)</DCC_BplOutput>
<DCC_DcuOutput>$(DELPHILIB)</DCC_DcuOutput>
<DCC_DcpOutput>$(DELPHIBIN)</DCC_DcpOutput>
<Icon_MainIcon>X2Utils_Icon.ico</Icon_MainIcon> <Icon_MainIcon>X2Utils_Icon.ico</Icon_MainIcon>
<DCC_Namespace>Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace> <DCC_Namespace>Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Locale>1033</VerInfo_Locale> <VerInfo_Locale>1033</VerInfo_Locale>
<VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''"> <PropertyGroup Condition="'$(Cfg_1)'!=''">
<Version>7.0</Version> <Version>7.0</Version>
@ -75,15 +99,21 @@
<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo> <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
<DCC_Define>RELEASE;$(DCC_Define)</DCC_Define> <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
<VerInfo_Locale>1033</VerInfo_Locale>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
<VerInfo_Locale>1033</VerInfo_Locale>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''"> <PropertyGroup Condition="'$(Cfg_2)'!=''">
<Version>7.0</Version> <Version>7.0</Version>
<DCC_WriteableConstants>True</DCC_WriteableConstants> <DCC_WriteableConstants>True</DCC_WriteableConstants>
<DCC_GenerateStackFrames>True</DCC_GenerateStackFrames> <DCC_GenerateStackFrames>True</DCC_GenerateStackFrames>
<DCC_DcuOutput>$(DELPHILIB)</DCC_DcuOutput>
<DCC_ObjOutput>$(DELPHILIB)</DCC_ObjOutput> <DCC_ObjOutput>$(DELPHILIB)</DCC_ObjOutput>
<DCC_HppOutput>$(DELPHILIB)</DCC_HppOutput> <DCC_HppOutput>$(DELPHILIB)</DCC_HppOutput>
<DCC_BplOutput>$(DELPHIBIN)</DCC_BplOutput> </PropertyGroup>
<DCC_DcpOutput>$(DELPHIBIN)</DCC_DcpOutput> <PropertyGroup Condition="'$(Cfg_2_Win64)'!=''">
<VerInfo_Locale>1033</VerInfo_Locale>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''"> <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
<DllSuffix>XE2</DllSuffix> <DllSuffix>XE2</DllSuffix>
@ -135,7 +165,7 @@
</Excluded_Packages> </Excluded_Packages>
</Delphi.Personality> </Delphi.Personality>
<Platforms> <Platforms>
<Platform value="Win64">False</Platform> <Platform value="Win64">True</Platform>
<Platform value="Win32">True</Platform> <Platform value="Win32">True</Platform>
</Platforms> </Platforms>
</BorlandProject> </BorlandProject>

Binary file not shown.

View File

@ -35,6 +35,7 @@ type
private private
FFileName: String; FFileName: String;
FConfiguration: IXMLConfiguration; FConfiguration: IXMLConfiguration;
FIsReader: Boolean;
FSection: IXMLSection; FSection: IXMLSection;
FSectionStack: TInterfaceList; FSectionStack: TInterfaceList;
protected protected
@ -71,6 +72,7 @@ type
property Configuration: IXMLConfiguration read FConfiguration; property Configuration: IXMLConfiguration read FConfiguration;
property IsReader: Boolean read FIsReader;
property Section: IXMLSection read FSection; property Section: IXMLSection read FSection;
property SectionStack: TInterfaceList read FSectionStack; property SectionStack: TInterfaceList read FSectionStack;
property FileName: String read FFileName; property FileName: String read FFileName;
@ -132,6 +134,7 @@ begin
FSectionStack := TInterfaceList.Create; FSectionStack := TInterfaceList.Create;
FFileName := AFileName; FFileName := AFileName;
FIsReader := AIsReader;
if AIsReader then if AIsReader then
FConfiguration := LoadConfiguration(AFileName) FConfiguration := LoadConfiguration(AFileName)
@ -170,7 +173,7 @@ begin
end; end;
end; end;
if not Result then if (not Result) and (not IsReader) then
begin begin
FSection := Section.section.Add; FSection := Section.section.Add;
FSection.name := AName; FSection.name := AName;

View File

@ -148,12 +148,6 @@ type
function MimeDecodeString(const S: AnsiString): AnsiString; forward; function MimeDecodeString(const S: AnsiString): AnsiString; forward;
procedure MimeEncodeStream(const InputStream: TStream; const OutputStream: TStream); forward; procedure MimeEncodeStream(const InputStream: TStream; const OutputStream: TStream); forward;
procedure MimeDecodeStream(const InputStream: TStream; const OutputStream: TStream); forward; procedure MimeDecodeStream(const InputStream: TStream; const OutputStream: TStream); forward;
function MimeEncodedSize(const I: Cardinal): Cardinal; forward;
function MimeDecodedSize(const I: Cardinal): Cardinal; forward;
procedure MimeEncode(var InputBuffer; const InputByteCount: Cardinal; var OutputBuffer); forward;
function MimeDecode(var InputBuffer; const InputBytesCount: Cardinal; var OutputBuffer): Cardinal; forward;
function MimeDecodePartial(var InputBuffer; const InputBytesCount: Cardinal; var OutputBuffer; var ByteBuffer: Cardinal; var ByteBufferSpace: Cardinal): Cardinal; forward;
function MimeDecodePartialEnd(var OutputBuffer; const ByteBuffer: Cardinal; const ByteBufferSpace: Cardinal): Cardinal; forward;
@ -590,45 +584,65 @@ end;
{ --- JclMime implementation from here. } { --- JclMime implementation from here. }
// Caution: For MimeEncodeStream and all other kinds of multi-buffered type
// Mime encodings (i.e. Files etc.), BufferSize must be set to a multiple of 3. {$IFDEF WIN64}
// Even though the implementation of the Mime decoding routines below SizeInt = NativeInt;
// do not require a particular buffer size, they work fastest with sizes of TJclAddr = UInt64;
// multiples of four. The chosen size is a multiple of 3 and of 4 as well. {$ELSE}
// The following numbers are, in addition, also divisible by 1024: SizeInt = Integer;
// $2400, $3000, $3C00, $4800, $5400, $6000, $6C00. TJclAddr = Cardinal;
{$ENDIF}
PByte4 = ^TByte4;
TByte4 = packed record
B1: Byte;
B2: Byte;
B3: Byte;
B4: Byte;
end;
PByte3 = ^TByte3;
TByte3 = packed record
B1: Byte;
B2: Byte;
B3: Byte;
end;
const const
BUFFER_SIZE = $3000; MIME_ENCODED_LINE_BREAK = 76;
EqualSign = Byte('='); MIME_DECODED_LINE_BREAK = MIME_ENCODED_LINE_BREAK div 4 * 3;
MIME_BUFFER_SIZE = MIME_DECODED_LINE_BREAK * 3 * 4 * 4;
MIME_ENCODE_TABLE: array [0..63] of Byte = ( MIME_ENCODE_TABLE: array [0..63] of Byte = (
65, 66, 67, 68, 69, 70, 71, 72, // 00 - 07 065, 066, 067, 068, 069, 070, 071, 072, // 00 - 07
73, 74, 75, 76, 77, 78, 79, 80, // 08 - 15 073, 074, 075, 076, 077, 078, 079, 080, // 08 - 15
81, 82, 83, 84, 85, 86, 87, 88, // 16 - 23 081, 082, 083, 084, 085, 086, 087, 088, // 16 - 23
89, 90, 97, 98, 99, 100, 101, 102, // 24 - 31 089, 090, 097, 098, 099, 100, 101, 102, // 24 - 31
103, 104, 105, 106, 107, 108, 109, 110, // 32 - 39 103, 104, 105, 106, 107, 108, 109, 110, // 32 - 39
111, 112, 113, 114, 115, 116, 117, 118, // 40 - 47 111, 112, 113, 114, 115, 116, 117, 118, // 40 - 47
119, 120, 121, 122, 48, 49, 50, 51, // 48 - 55 119, 120, 121, 122, 048, 049, 050, 051, // 48 - 55
52, 53, 54, 55, 56, 57, 43, 47); // 56 - 63 052, 053, 054, 055, 056, 057, 043, 047); // 56 - 63
MIME_DECODE_TABLE: array [Byte] of Cardinal = ( MIME_PAD_CHAR = Byte('=');
255, 255, 255, 255, 255, 255, 255, 255, // 00 - 07
255, 255, 255, 255, 255, 255, 255, 255, // 08 - 15 MIME_DECODE_TABLE: array [Byte] of Byte = (
255, 255, 255, 255, 255, 255, 255, 255, // 0 - 7
255, 255, 255, 255, 255, 255, 255, 255, // 8 - 15
255, 255, 255, 255, 255, 255, 255, 255, // 16 - 23 255, 255, 255, 255, 255, 255, 255, 255, // 16 - 23
255, 255, 255, 255, 255, 255, 255, 255, // 24 - 31 255, 255, 255, 255, 255, 255, 255, 255, // 24 - 31
255, 255, 255, 255, 255, 255, 255, 255, // 32 - 39 255, 255, 255, 255, 255, 255, 255, 255, // 32 - 39
255, 255, 255, 62, 255, 255, 255, 63, // 40 - 47 255, 255, 255, 062, 255, 255, 255, 063, // 40 - 47
52, 53, 54, 55, 56, 57, 58, 59, // 48 - 55 052, 053, 054, 055, 056, 057, 058, 059, // 48 - 55
60, 61, 255, 255, 255, 255, 255, 255, // 56 - 63 060, 061, 255, 255, 255, 255, 255, 255, // 56 - 63
255, 0, 1, 2, 3, 4, 5, 6, // 64 - 71 255, 000, 001, 002, 003, 004, 005, 006, // 64 - 71
7, 8, 9, 10, 11, 12, 13, 14, // 72 - 79 007, 008, 009, 010, 011, 012, 013, 014, // 72 - 79
15, 16, 17, 18, 19, 20, 21, 22, // 80 - 87 015, 016, 017, 018, 019, 020, 021, 022, // 80 - 87
23, 24, 25, 255, 255, 255, 255, 255, // 88 - 95 023, 024, 025, 255, 255, 255, 255, 255, // 88 - 95
255, 26, 27, 28, 29, 30, 31, 32, // 96 - 103 255, 026, 027, 028, 029, 030, 031, 032, // 96 - 103
33, 34, 35, 36, 37, 38, 39, 40, // 104 - 111 033, 034, 035, 036, 037, 038, 039, 040, // 104 - 111
41, 42, 43, 44, 45, 46, 47, 48, // 112 - 119 041, 042, 043, 044, 045, 046, 047, 048, // 112 - 119
49, 50, 51, 255, 255, 255, 255, 255, // 120 - 127 049, 050, 051, 255, 255, 255, 255, 255, // 120 - 127
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
@ -646,259 +660,218 @@ const
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255); 255, 255, 255, 255, 255, 255, 255, 255);
type
PByte4 = ^TByte4;
TByte4 = packed record
B1: Byte;
B2: Byte;
B3: Byte;
B4: Byte;
end;
PByte3 = ^TByte3; function MimeEncodedSize(const InputSize: SizeInt): SizeInt;
TByte3 = packed record
B1: Byte;
B2: Byte;
B3: Byte;
end;
//------------------------------------------------------------------------------
// Wrapper functions & procedures
//------------------------------------------------------------------------------
function MimeEncodeString(const S: AnsiString): AnsiString;
var
L: Cardinal;
begin begin
L := Length(S); if InputSize > 0 then
if L > 0 then Result := (InputSize + 2) div 3 * 4 + (InputSize - 1) div MIME_DECODED_LINE_BREAK * 2
begin
SetLength(Result, MimeEncodedSize(L));
MimeEncode(PAnsiChar(S)^, L, PAnsiChar(Result)^);
end
else else
Result := ''; Result := InputSize;
end; end;
//------------------------------------------------------------------------------
function MimeDecodeString(const S: AnsiString): AnsiString; procedure MimeEncodeFullLines(const InputBuffer; const InputByteCount: SizeInt; out OutputBuffer);
var
ByteBuffer, ByteBufferSpace: Cardinal;
L: Cardinal;
begin
L := Length(S);
if L > 0 then
begin
SetLength(Result, MimeDecodedSize(L));
ByteBuffer := 0;
ByteBufferSpace := 4;
L := MimeDecodePartial(PAnsiChar(S)^, L, PAnsiChar(Result)^, ByteBuffer, ByteBufferSpace);
Inc(L, MimeDecodePartialEnd(PAnsiChar(Cardinal(Result) + L)^, ByteBuffer, ByteBufferSpace));
SetLength(Result, L);
end;
end;
//------------------------------------------------------------------------------
procedure MimeEncodeStream(const InputStream: TStream; const OutputStream: TStream);
var
InputBuffer: array [0..BUFFER_SIZE - 1] of Byte;
OutputBuffer: array [0..((BUFFER_SIZE + 2) div 3) * 4 - 1] of Byte;
BytesRead: Integer;
begin
BytesRead := InputStream.Read(InputBuffer, SizeOf(InputBuffer));
while BytesRead > 0 do
begin
MimeEncode(InputBuffer, BytesRead, OutputBuffer);
OutputStream.Write(OutputBuffer, MimeEncodedSize(BytesRead));
BytesRead := InputStream.Read(InputBuffer, SizeOf(InputBuffer));
end;
end;
//------------------------------------------------------------------------------
procedure MimeDecodeStream(const InputStream: TStream; const OutputStream: TStream);
var
ByteBuffer, ByteBufferSpace: Cardinal;
InputBuffer: array [0..(BUFFER_SIZE + 3) div 4 * 3 - 1] of Byte;
OutputBuffer: array [0..BUFFER_SIZE - 1] of Byte;
BytesRead: Integer;
begin
ByteBuffer := 0;
ByteBufferSpace := 4;
BytesRead := InputStream.Read(InputBuffer, SizeOf(InputBuffer));
while BytesRead > 0 do
begin
OutputStream.Write(OutputBuffer, MimeDecodePartial(InputBuffer, BytesRead, OutputBuffer, ByteBuffer, ByteBufferSpace));
BytesRead := InputStream.Read(InputBuffer, SizeOf(InputBuffer));
end;
OutputStream.Write(OutputBuffer, MimeDecodePartialEnd(OutputBuffer, ByteBuffer, ByteBufferSpace));
end;
//------------------------------------------------------------------------------
// Helper functions
//------------------------------------------------------------------------------
function MimeEncodedSize(const I: Cardinal): Cardinal;
begin
Result := (I + 2) div 3 * 4;
end;
//------------------------------------------------------------------------------
function MimeDecodedSize(const I: Cardinal): Cardinal;
begin
Result := (I + 3) div 4 * 3;
end;
//------------------------------------------------------------------------------
// Primary functions & procedures
//------------------------------------------------------------------------------
procedure MimeEncode(var InputBuffer; const InputByteCount: Cardinal; var OutputBuffer);
var var
B: Cardinal; B: Cardinal;
InMax3: Cardinal; InnerLimit, OuterLimit: TJclAddr;
InPtr, InLimitPtr: ^Byte; InPtr: PByte3;
OutPtr: PByte4; OutPtr: PByte4;
begin begin
if InputByteCount <= 0 then { Do we have enough input to encode a full line? }
if InputByteCount < MIME_DECODED_LINE_BREAK then
Exit; Exit;
InPtr := @InputBuffer; InPtr := @InputBuffer;
InMax3 := InputByteCount div 3 * 3; OutPtr := @OutputBuffer;
OutPTr := @OutputBuffer;
Cardinal(InLimitPtr) := Cardinal(InPtr) + InMax3;
while InPtr <> InLimitPtr do InnerLimit := TJclAddr(InPtr);
Inc(InnerLimit, MIME_DECODED_LINE_BREAK);
OuterLimit := TJclAddr(InPtr);
Inc(OuterLimit, InputByteCount);
{ Multiple line loop. }
repeat
{ Single line loop. }
repeat
{ Read 3 bytes from InputBuffer. }
B := InPtr^.B1;
B := B shl 8;
B := B or InPtr^.B2;
B := B shl 8;
B := B or InPtr^.B3;
Inc(InPtr);
{ Write 4 bytes to OutputBuffer (in reverse order). }
OutPtr^.B4 := MIME_ENCODE_TABLE[B and $3F];
B := B shr 6;
OutPtr^.B3 := MIME_ENCODE_TABLE[B and $3F];
B := B shr 6;
OutPtr^.B2 := MIME_ENCODE_TABLE[B and $3F];
B := B shr 6;
OutPtr^.B1 := MIME_ENCODE_TABLE[B];
Inc(OutPtr);
until TJclAddr(InPtr) >= InnerLimit;
{ Write line break (CRLF). }
OutPtr^.B1 := 13;
OutPtr^.B2 := 10;
Inc(TJclAddr(OutPtr), 2);
Inc(InnerLimit, MIME_DECODED_LINE_BREAK);
until InnerLimit > OuterLimit;
end;
procedure MimeEncodeNoCRLF(const InputBuffer; const InputByteCount: SizeInt; out OutputBuffer);
var
B: Cardinal;
InnerLimit, OuterLimit: SizeInt;
InPtr: PByte3;
OutPtr: PByte4;
begin
if InputByteCount = 0 then
Exit;
InPtr := @InputBuffer;
OutPtr := @OutputBuffer;
OuterLimit := InputByteCount div 3 * 3;
InnerLimit := TJclAddr(InPtr);
Inc(InnerLimit, OuterLimit);
{ Last line loop. }
while TJclAddr(InPtr) < TJclAddr(InnerLimit) do
begin begin
B := InPtr^; { Read 3 bytes from InputBuffer. }
B := InPtr^.B1;
B := B shl 8; B := B shl 8;
Inc(InPtr); B := B or InPtr^.B2;
B := B or InPtr^;
B := B shl 8; B := B shl 8;
B := B or InPtr^.B3;
Inc(InPtr); Inc(InPtr);
B := B or InPtr^; { Write 4 bytes to OutputBuffer (in reverse order). }
Inc(InPtr); OutPtr^.B4 := MIME_ENCODE_TABLE[B and $3F];
// Write 4 bytes to OutputBuffer (in reverse order).
OutPtr.B4 := MIME_ENCODE_TABLE[B and $3F];
B := B shr 6; B := B shr 6;
OutPtr.B3 := MIME_ENCODE_TABLE[B and $3F]; OutPtr^.B3 := MIME_ENCODE_TABLE[B and $3F];
B := B shr 6; B := B shr 6;
OutPtr.B2 := MIME_ENCODE_TABLE[B and $3F]; OutPtr^.B2 := MIME_ENCODE_TABLE[B and $3F];
B := B shr 6; B := B shr 6;
OutPtr.B1 := MIME_ENCODE_TABLE[B]; OutPtr^.B1 := MIME_ENCODE_TABLE[B];
Inc(OutPtr); Inc(OutPtr);
end; end;
case InputByteCount - InMax3 of { End of data & padding. }
case InputByteCount - OuterLimit of
1: 1:
begin begin
B := InPtr^; B := InPtr^.B1;
B := B shl 4; B := B shl 4;
OutPtr.B2 := MIME_ENCODE_TABLE[B and $3F]; OutPtr.B2 := MIME_ENCODE_TABLE[B and $3F];
B := B shr 6; B := B shr 6;
OutPtr.B1 := MIME_ENCODE_TABLE[B]; OutPtr.B1 := MIME_ENCODE_TABLE[B];
OutPtr.B3 := EqualSign; // Fill remaining 2 bytes. OutPtr.B3 := MIME_PAD_CHAR; { Pad remaining 2 bytes. }
OutPtr.B4 := EqualSign; OutPtr.B4 := MIME_PAD_CHAR;
end; end;
2: 2:
begin begin
B := InPtr^; B := InPtr^.B1;
Inc(InPtr);
B := B shl 8; B := B shl 8;
B := B or InPtr^; B := B or InPtr^.B2;
B := B shl 2; B := B shl 2;
OutPtr.B3 := MIME_ENCODE_TABLE[B and $3F]; OutPtr.B3 := MIME_ENCODE_TABLE[B and $3F];
B := B shr 6; B := B shr 6;
OutPTr.b2 := MIME_ENCODE_TABLE[B and $3F]; OutPtr.B2 := MIME_ENCODE_TABLE[B and $3F];
B := B shr 6; B := B shr 6;
OutPtr.B1 := MIME_ENCODE_TABLE[B]; OutPtr.B1 := MIME_ENCODE_TABLE[B];
OutPtr.B4 := EqualSign; // Fill remaining byte. OutPtr.B4 := MIME_PAD_CHAR; { Pad remaining byte. }
end; end;
end; end;
end; end;
//------------------------------------------------------------------------------
function MimeDecode(var InputBuffer; const InputBytesCount: Cardinal; var OutputBuffer): Cardinal; procedure MimeEncode(const InputBuffer; const InputByteCount: SizeInt; out OutputBuffer);
var var
ByteBuffer, ByteBufferSpace: Cardinal; IDelta, ODelta: SizeInt;
I, O: PByte;
begin begin
ByteBuffer := 0; MimeEncodeFullLines(InputBuffer, InputByteCount, OutputBuffer);
ByteBufferSpace := 4; IDelta := InputByteCount div MIME_DECODED_LINE_BREAK; // Number of lines processed so far.
Result := MimeDecodePartial(InputBuffer, InputBytesCount, OutputBuffer, ByteBuffer, ByteBufferSpace); ODelta := IDelta * (MIME_ENCODED_LINE_BREAK + 2);
Inc(Result, MimeDecodePartialEnd(PAnsiChar(Cardinal(OutputBuffer) + Result)^, ByteBuffer, ByteBufferSpace)); IDelta := IDelta * MIME_DECODED_LINE_BREAK;
I := @InputBuffer;
Inc(I, IDelta);
O := @OutputBuffer;
Inc(O, ODelta);
MimeEncodeNoCRLF(I^, InputByteCount - IDelta, O^);
end; end;
//------------------------------------------------------------------------------
function MimeDecodePartial(var InputBuffer; const InputBytesCount: Cardinal; function MimeDecodePartial(const InputBuffer; const InputByteCount: SizeInt; out OutputBuffer;
var OutputBuffer; var ByteBuffer: Cardinal; var ByteBufferSpace: Cardinal): Cardinal; var ByteBuffer: Cardinal; var ByteBufferSpace: Cardinal): SizeInt;
var var
lByteBuffer, lByteBufferSpace, C: Cardinal; LByteBuffer, LByteBufferSpace, C: Cardinal;
InPtr, InLimitPtr: ^Byte; InPtr, OuterLimit: PByte;
OutPtr: PByte3; OutPtr: PByte3;
begin begin
if InputBytesCount > 0 then if InputByteCount > 0 then
begin begin
InPtr := @InputBuffer; InPtr := @InputBuffer;
Cardinal(InLimitPtr) := Cardinal(InPtr) + InputBytesCount; OuterLimit := Pointer(TJclAddr(InPtr) + TJclAddr(InputByteCount));
OutPtr := @OutputBuffer; OutPtr := @OutputBuffer;
lByteBuffer := ByteBuffer; LByteBuffer := ByteBuffer;
lByteBufferSpace := ByteBufferSpace; LByteBufferSpace := ByteBufferSpace;
while InPtr <> InLimitPtr do while InPtr <> OuterLimit do
begin begin
C := MIME_DECODE_TABLE[InPtr^]; // Read from InputBuffer. { Read from InputBuffer. }
C := MIME_DECODE_TABLE[InPtr^];
Inc(InPtr); Inc(InPtr);
if C = $FF then if C = $FF then
Continue; Continue;
LByteBuffer := LByteBuffer shl 6;
LByteBuffer := LByteBuffer or C;
Dec(LByteBufferSpace);
{ Have we read 4 bytes from InputBuffer? }
if LByteBufferSpace <> 0 then
Continue;
lByteBuffer := lByteBuffer shl 6; { Write 3 bytes to OutputBuffer (in reverse order). }
lByteBuffer := lByteBuffer or C; OutPtr^.B3 := Byte(LByteBuffer);
Dec(lByteBufferSpace); LByteBuffer := LByteBuffer shr 8;
if lByteBufferSpace <> 0 then OutPtr^.B2 := Byte(LByteBuffer);
Continue; // Read 4 bytes from InputBuffer? LByteBuffer := LByteBuffer shr 8;
OutPtr^.B1 := Byte(LByteBuffer);
OutPtr.B3 := Byte(lByteBuffer); // Write 3 bytes to OutputBuffer (in reverse order). LByteBuffer := 0;
lByteBuffer := lByteBuffer shr 8;
OutPtr.B2 := Byte(lByteBuffer);
lByteBuffer := lByteBuffer shr 8;
OutPtr.B1 := Byte(lByteBuffer);
lByteBuffer := 0;
Inc(OutPtr); Inc(OutPtr);
lByteBufferSpace := 4; LByteBufferSpace := 4;
end; end;
ByteBuffer := lByteBuffer; ByteBuffer := LByteBuffer;
ByteBufferSpace := lByteBufferSpace; ByteBufferSpace := LByteBufferSpace;
Result := Cardinal(OutPtr) - Cardinal(@OutputBuffer); Result := SizeInt(TJclAddr(OutPtr) - TJclAddr(@OutputBuffer));
end end
else else
Result := 0; Result := 0;
end; end;
//------------------------------------------------------------------------------
function MimeDecodePartialEnd(var OutputBuffer; const ByteBuffer: Cardinal; function MimeDecodePartialEnd(out OutputBuffer; const ByteBuffer: Cardinal;
const ByteBufferSpace: Cardinal): Cardinal; const ByteBufferSpace: Cardinal): SizeInt;
var var
lByteBuffer: Cardinal; LByteBuffer: Cardinal;
begin begin
case ByteBufferSpace of case ByteBufferSpace of
1: 1:
begin begin
lByteBuffer := ByteBuffer shr 2; LByteBuffer := ByteBuffer shr 2;
PByte3(@OutputBuffer).B2 := Byte(lByteBuffer); PByte3(@OutputBuffer)^.B2 := Byte(LByteBuffer);
lByteBuffer := lByteBuffer shr 8; LByteBuffer := LByteBuffer shr 8;
PByte3(@OutputBuffer).B1 := Byte(lByteBuffer); PByte3(@OutputBuffer)^.B1 := Byte(LByteBuffer);
Result := 2; Result := 2;
end; end;
2: 2:
begin begin
lByteBuffer := ByteBuffer shr 4; LByteBuffer := ByteBuffer shr 4;
PByte3(@OutputBuffer).B1 := Byte(lByteBuffer); PByte3(@OutputBuffer)^.B1 := Byte(LByteBuffer);
Result := 1; Result := 1;
end; end;
else else
@ -906,5 +879,106 @@ begin
end; end;
end; end;
function MimeEncodeString(const S: AnsiString): AnsiString;
var
L: SizeInt;
begin
if S <> '' then
begin
L := Length(S);
SetLength(Result, MimeEncodedSize(L));
MimeEncode(PAnsiChar(S)^, L, PAnsiChar(Result)^);
end
else
Result := '';
end;
function MimeDecodedSize(const InputSize: SizeInt): SizeInt;
begin
Result := (InputSize + 3) div 4 * 3;
end;
function MimeDecodeString(const S: AnsiString): AnsiString;
var
ByteBuffer, ByteBufferSpace: Cardinal;
L: SizeInt;
P, R: PAnsiChar;
begin
if S <> '' then
begin
L := Length(S);
SetLength(Result, MimeDecodedSize(L));
ByteBuffer := 0;
ByteBufferSpace := 4;
P := PAnsiChar(S);
R := PAnsiChar(Result);
L := MimeDecodePartial(P^, L, R^, ByteBuffer, ByteBufferSpace);
Inc(R, L);
Inc(L, MimeDecodePartialEnd(R^, ByteBuffer, ByteBufferSpace));
SetLength(Result, L);
end
else
Result := '';
end;
procedure MimeEncodeStream(const InputStream: TStream; const OutputStream: TStream);
var
InputBuffer: array [0..MIME_BUFFER_SIZE - 1] of Byte;
OutputBuffer: array [0..(MIME_BUFFER_SIZE + 2) div 3 * 4 + MIME_BUFFER_SIZE div MIME_DECODED_LINE_BREAK * 2 - 1] of Byte;
BytesRead: SizeInt;
IDelta, ODelta: SizeInt;
I, O: PByte;
begin
InputBuffer[0] := 0;
BytesRead := InputStream.Read(InputBuffer, SizeOf(InputBuffer));
while BytesRead = Length(InputBuffer) do
begin
MimeEncodeFullLines(InputBuffer, Length(InputBuffer), OutputBuffer);
OutputStream.Write(OutputBuffer, Length(OutputBuffer));
BytesRead := InputStream.Read(InputBuffer, Length(InputBuffer));
end;
MimeEncodeFullLines(InputBuffer, BytesRead, OutputBuffer);
IDelta := BytesRead div MIME_DECODED_LINE_BREAK; // Number of lines processed.
ODelta := IDelta * (MIME_ENCODED_LINE_BREAK + 2);
IDelta := IDelta * MIME_DECODED_LINE_BREAK;
I := @InputBuffer;
Inc(I, IDelta);
O := @OutputBuffer;
Inc(O, ODelta);
MimeEncodeNoCRLF(I^, BytesRead - IDelta, O^);
OutputStream.Write(OutputBuffer, MimeEncodedSize(BytesRead));
end;
procedure MimeDecodeStream(const InputStream: TStream; const OutputStream: TStream);
var
ByteBuffer, ByteBufferSpace: Cardinal;
InputBuffer: array [0..MIME_BUFFER_SIZE - 1] of Byte;
OutputBuffer: array [0..(MIME_BUFFER_SIZE + 3) div 4 * 3 - 1] of Byte;
BytesRead: SizeInt;
begin
ByteBuffer := 0;
ByteBufferSpace := 4;
InputBuffer[0] := 0;
BytesRead := InputStream.Read(InputBuffer, SizeOf(InputBuffer));
while BytesRead > 0 do
begin
OutputStream.Write(OutputBuffer, MimeDecodePartial(InputBuffer, BytesRead, OutputBuffer, ByteBuffer, ByteBufferSpace));
BytesRead := InputStream.Read(InputBuffer, Length(InputBuffer));
end;
OutputStream.Write(OutputBuffer, MimeDecodePartialEnd(OutputBuffer, ByteBuffer, ByteBufferSpace));
end;
end. end.